AICon 深圳站聚焦 Agent 技术、应用与生态,大咖分享实战干货 了解详情
写点什么

为所有 PHP-FPM 容器构建单独的 NGinx Dock 镜像

  • 2018-07-22
  • 本文字数:4310 字

    阅读完需:约 14 分钟

最近,原文作者一直在使用 Docker 容器来开发 PHP 微服务套件。一个问题是 PHP 应用已经搭建,可以和 PHP-FPM 和 Nginx(取代了简单的Apche/PHP 环境)一起工作,因此每个PHP 微服务需要两个容器(以及两个Docker 镜像):一个PHP-FPM 容器和一个NGinx 容器。 

这个应用运行了 6 个以上的服务,如果做个乘法,在开发和生产之间会有约 30 个容器。作者决定构建一个单独的 NGinx Docker 镜像,它可以使用 PHP-FPM 的主机名作为环境变量并运行单独的配置文件,而没有为每个容器构建单独的 NGinx 镜像。



在本文中,原文作者简要说明从上图中的方法 1 到方法 2 的转换,最后采用的方案中采用了一种新的定制 Docker 镜像。该镜像的代码是开源的,如果读者碰到类似问题,可以随时签出该部分代码。

为什么用 NGinx?

NGinx 和 PHP-FPM 配合使用能使PHP 应用的性能更好,但不好的是和PHP Apache 镜像不同, PHP-FPM Docker 镜像缺省并没有和 NGinx 进行绑定。如果需要通过 NGinx 容器和 PHP-FPM 连接,需要在 NGind 配置里为该后端增加 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

它可以正常工作了。但是,这种方法有两个困扰的地方: 

  1. 正在使用的基础镜像已经有两年了。这会引入安全和性能风险。 
  2. 有个空的/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 上,如果读者看到任何问题或有改进建议,可以直接创建一个问题单。如果有疑问或任何Docker 相关的,可以在Twitter 上找到我继续探讨。

查看英文原文:  https://www.shiphp.com/blog/2018/nginx-php-fpm-with-env

感谢张婵对本文的审校。

2018-07-22 19:002729

评论 1 条评论

发布
暂无评论
发现更多内容

开发者测评:阿里云 ACR 与其他的镜像仓库到底有什么不同?

阿里巴巴云原生

阿里云 云原生 ACR

秋招!面试十次字节/美团失败总结的《520道LeetCode题Java版答案》

退休的汤姆

Java 程序员 面经 Java工程师 秋招

Java基础知识总结--事务失效的12种场景

阿婷

Java 后端 事务 8月月更

RT-Thread记录(十五、I/O 设备模型之SPI设备)

矜辰所致

RT-Thread 8月月更 I/O设备模型

如何通过OpenHarmony的音频模块实现录音变速功能?

OpenHarmony开发者

OpenHarmony

逆向工程:揭示Google Colab未公开的秘密

OneFlow

机器学习 深度学习 模型

非关系型数据库 Redis 核心内容

苏玖

数据库 nosql redis redis持久化 8月月更

图文详解:内存总是不够,我靠HBase说服了Leader为新项目保驾护航

浅羽技术

数据库 大数据 微服务 HBase 8月月更

微服务全链路灰度新能力

阿里巴巴云原生

阿里云 微服务 云原生 灰度 全链路

讲座回顾丨基于 OpenYurt 和 EdgeX 的云边端协同新可能

阿里巴巴云原生

阿里云 云原生 边缘计算

AIGC:自动化内容生成,AI的下一个引爆点?

晨山资本

AI 2D 3D模型 3D点云

五问五答:第三方风险管理

SEAL安全

网络安全 风险管理 安全风险 软件供应链安全

App Push 通用测试方案

转转技术团队

测试工具

讲真,这份秋招豪礼【面试锦囊】真舍不得给你们

浅羽技术

面试 面试题 秋招 8月月更 秋招你准备的怎样了

让“上链”触手可及:VoneBaaS 赋能传统应用场景

旺链科技

区块链 数字化转型 产业区块链

阿里架构师花近十年时间整理出来的Java核心知识pdf(Java岗)

退休的汤姆

Java 面经 校招 秋招 java·工程师

团队管理之不轻易责备

蛋先生DX

管理 团队 团队氛围

长阳土家族自治县政府与升哲科技达成战略合作

SENSORO

新基建 智慧城市 AIOT

绿色数据中心案例介绍:阿里巴巴、华为、电信、移动……

GPU算力

低成本、强交互、沉浸式的云游戏,究竟如何实现?

阿里云CloudImagine

视频云 云游戏

合合信息对于表格识别与内容提炼技术理解及研发趋势

合合技术团队

人工智能 表格识别 合合信息

获取IP地址的途径有哪些?要如何保护IP地址不被窃取?

郑州埃文科技

IP地址 追踪IP 保护IP

前端的状态管理与时间旅行:San实践篇

百度Geek说

前端 JavaScrip

2022 全国大学生操作系统大赛圆满落幕 龙蜥推动人才培养与产业发展深度融合

OpenAnolis小助手

开源 操作系统 龙蜥社区 设计比赛

秒合约交易APP系统开发源码搭建

开发微hkkf5566

升哲科技荣获2022年“中国IC设计成就奖”

SENSORO

物联网 芯片

别小看 Log 日志,它难住了我们组的架构师

浅羽技术

日志 log4j slf4j logback 8月月更

80%Java开发者面试都问的SpringBoot你竟不会?看完这些笔记足以

退休的汤姆

Java 面经 秋招 spring、

基于 gh-ost 的在线 Schema 变更

Bytebase

MySQL 数据库

Alibaba最新神作!耗时182天肝出来1015页分布式全栈手册太香了

退休的汤姆

Java 程序员 分布式 面经 秋招

2022年密码测评理论与关键技术前沿论坛|海泰方圆分享密码应用改造典型方案

电子信息发烧客

为所有PHP-FPM容器构建单独的NGinx Dock镜像_PHP_Karl Hughes_InfoQ精选文章