如何为多个PHP-FPM容器构建单一的Nginx Docker镜像教程-linux运维教程

  • 为什么用 Nginx?
  • 第一种方案: 使用 Docker 文档中的方法
  • 使用另一个 Docker 镜像,差点成功
  • 最终解决方案

在使用 Docker 容器来开发 PHP 微服务套件的过程中,作者遇到了容器数量过多的问题。

最近,我一直在使用 Docker 容器来开发 PHP 微服务套件。一个问题是 PHP 应用已经搭建,可以与 PHP-FPM 还有 Nginx(取代了简单的 Apche/PHP 环境)一起工作,因此每个 PHP 微服务需要两个容器(以及两个 Docker 镜像):一个 PHP-FPM 容器和一个 Nginx 容器。
这个应用运行了 6 个以上的服务,做个乘法就知道,在开发和生产之间会有约 30 个容器。于是我决定构建一个单独的 Nginx Docker 镜像,它可以使用 PHP-FPM 的主机名作为环境变量并运行单独的配置文件,而不用为每个容器构建单独的 Nginx 镜像。

如何为多个PHP-FPM容器构建单一的Nginx Docker镜像教程-linux运维教程

在本文中,我介绍了自己从上图中的方法 1 到方法 2 的转换,最后采用的方案中采用了一种新的定制 Docker 镜像。该镜像的代码是开源的,如果读者碰到类似问题,可以提供给大家参考。

为什么用 Nginx?

Nginx 和 PHP-FPM 配合使用能使 PHP 应用的性能更好,但不好的地方在于,和 PHP Apache 镜像不同,PHP-FPM Docker 镜像默认不是和和 Nginx 绑定在一起的。如果需要通过 Nginx 容器和 PHP-FPM 连接,需要在 Nginx 配置里为该后端增加 DNS 记录。比如,如果名为 php-fpm-api 的 PHP-FPM 容器正在运行,Nginx 配置文件应该包含下面部分:

location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        # This line passes requests through to the PHP-FPM container
        fastcgi_pass php-fpm-api:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

如果只服务于单独的 Nginx 容器,Nginx 配置中容器名字写死还可以接受,但如上所述,需要允许多个 Nginx 容器,每个对应于一个 PHP 服务。创建一个新的 Nginx 镜像(以后需要进行维护和升级)会有些痛苦,即使管理一批不同的数据卷,仅仅改变变量名看起来也有很多工作。

第一种方案: 使用 Docker 文档中的方法

最初,我认为这会很简单。Docker 文档中有少许的几个章节讨论如何使用 envsubst 来完成该工作,但不幸的是,在我的 Nginx 配置文件中,这种方法不奏效。

vhosts.conf

server {
    listen 80;
    index index.php index.html;
    root /var/www/public;
    client_max_body_size 32M;
    location / {
        try_files $uri /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass ${NGINX_HOST}:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

该vhosts.conf文件使用了 Nginx 内置变量,因此当依照文档运行 Docker 命令 (/bin/bash -c “envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g ‘daemon off;’”) 时,得到错误提示$uri和$fastcgi_script_name没有定义。这些变量通常通过 Nginx 传入,因此不能简单的识别出他们是什么并传给自身,而且这样会影响容器的动态配置。

使用另一个 Docker 镜像,差点成功

接下来,我开始研究不同的 Nginx 镜像。找到的有两个,但它们都在随后的几年中都没有任何更新。我开始使用 martin/nginx,试图找到可以工作的原型。

Martin 的镜像和其它镜像有点不一样,因为它要求特定的文件夹结构。在 root 下增加Dockerfile:

FROM martin/nginx

接下来,我添加了一个app/空目录和conf/目录,conf/目录下只有一个文件
vhosts.conf:

server {
    listen 80;
    index index.php index.html;
    root /var/www/public;
    client_max_body_size 32M;
    location / {
        try_files $uri /index.php?$args;
    }
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass $ENV{"NGINX_HOST"}:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

这个文件和之前的配置文件几乎一样,除了有一行的改动:
fastcgi_pass $ENV{“NGINX_HOST”}:9000;。现在想要启动带命名为 php-fpm-api 的 PHP 容器的 Nginx 容器,就可以构建一个新的镜像,让它在以下环境变量下运行:

docker build -t shiphp/nginx-env:test .
docker run -it --rm -e NGINX_HOST=php-fpm-api shiphp/nginx-env:test

它可以正常工作了。但是,这种方法有两个困扰的地方:
正在使用的基础镜像已经有两年了。这会引入安全和性能风险。
有个空的/app目录看起来并不必需,因为文件会被存储在一个不同的目录中。

最终解决方案

我认为作为定制解决方案,从 Martin 镜像开始比较好,因此我给项目建了分叉,创建了新的 Nginx 基础镜像并修复了上述两个问题。现在,如果要在 Nginx 容器中允许动态命名的后端,可以参照:

# 从 Docker Hub 得到最新版本
docker pull shiphp/nginx-env:latest
# 运行名为"php-fpm-api"的 PHP 容器 
docker run --name php-fpm-api -v $(pwd):/var/www php:fpm
# 允许链接到 PHP-FPM 容器的 NGinx 容器
docker run --link php-fpm-api -e NGINX_HOST=php-fpm-api shiphp/nginx-env

如果想增加自己的文件或 Nginx 配置文件,来定制镜像,用Dockerfile来扩展它就可以:

FROM shiphp/nginx-env
ONBUILD ADD <PATH_TO_YOUR_CONFIGS> /etc/nginx/conf.d/
...

现在所有的 PHP-FPM 容器都能使用单个Docker镜像中自己的实例,这样在升级 Nginx,改变权限或做某些调整时,就变得非常轻松了。

所有的代码都在 Github 上,如果你看到任何问题或有改进建议,可以直接创建 issue。

GitHub 项目链接:https://github.com/shiphp/nginx-env

主题测试文章,只做测试使用。发布者:云大使,转转请注明出处:https://www.xp8.net/server/1003.html

(0)
打赏 微信扫一扫 微信扫一扫
云大使的头像云大使
上一篇 2018年10月16日 下午9:19
下一篇 2018年10月16日 下午9:19

相关推荐

  • 如何在Linode CentOS7开启Google TCP-BBR优化算法 | linux运维

    Linux在4.9版本的内核新增了一款TCP拥塞控制技术:BBR,Linode最新内核也更新到4.9,但是没有把BBR编译进去,下面是教程是替换Linode CentOS7内核,并开启Google TCP-BBR优化算法方法。 注意:Linode、阿里云测试OK,Ucloud测试加载4.9变为只读系统。 1. 安装elrepo提供的kernel4.9 增加e…

    服务器运维 2018年11月21日
    2.7K00
  • linux/centos下使用kill命令的使用教程方法

    kill命令 kill命令用来删除执行中的程序或工作。kill可将指定的信息送至程序。预设的信息为SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用SIGKILL(9)信息尝试强制删除程序。程序或工作的编号可利用ps指令或job指令查看。 语法 kill(选择)(参数) 选项-a:当处理当前进程时,不限制命令名和进程号的对应关系;-l &l…

    2019年4月13日
    4.7K00
  • 在Linux命令上下载文件的5个wget案例教程

    wget是Linux命令行实用程序,广泛用于从Linux命令行下载文件,有许多选项也可用于从远程服务器下载文件。wget与浏览器窗口中的open url相同。 1:使用Wget下载文件 下面的示例将从服务器下载文件到当前本地目录。 $ wget https://tecadmin.net/file.zip 2:下载文件并保存到特定位置 下面的命令将下载名为fi…

    2019年3月13日
    3.4K00
  • 总结关于文件说明注意点-linux教程

    如果您有服务器咨询问题、购买问题、可以联系我们客服 7271895 690624商祺云-阿里代理、景安代理、西部代理 一、/etc/hosts>man hosts1、作用: 主机名查询静态表;主要用于IP地址与计算机主机名之间的转换。/etc/hosts文件格式,每行表示一个IP地址;每行由三部分构成:IP_address canonical_host…

    服务器运维 2019年1月14日
    2.9K00
  • inode索引节点用满报错mkdir: cannot create directory `xxx’: No space left on device

    小编今天维护一台服务器、数据库无法启动、也无法建立文件目录等操作。都提示No space left on device 后来仔细查看洗了 是因为inode满了。那就赶紧想办法清理下了。 命令:df -i 其中/dev/mapper/vg_have-lv_root 884208 884208 0 100% /索引节点 (inode)满了 已经找出问题所在,那么…

    2019年4月18日
    3.3K00

发表回复

登录后才能评论
联系我们

联系我们

18838889666

在线咨询: QQ交谈

邮件:xinyun@88.com

工作时间:周一至周五,9:30-18:30,节假日休息

添加微信
添加微信
分享本页
返回顶部
---------官方优惠叠加渠道折扣:通过我们购买腾讯云/阿里云,价格更低,服务更优。更有专业配置指导与服务。微信同步:18838889666----