nginx的php-fpm upstream server在容器化使用注意点
问题
1.报错含义拆解:
nginx: [emerg] host not found in upstream "php-upstream-ios"
这句话不是在说 upstream 名字不存在,而是在说:
upstream 里配置的 server 主机名无法被解析(DNS 失败)
真正出问题的不是 php-upstream-ios 这个 upstream,而是它里面这一行:
1 | upstream php-upstream-ios { |
gz-api-ios 这个 主机名在 Nginx 启动时解析失败。
2.为什么 Nginx 会“启动即失败”
2.1 Nginx 的一个关键特性(很多人忽略)
- Nginx 在启动 / reload 阶段就解析 upstream 中的 server
- 不是等到有请求才解析
- 解析失败 = 直接启动失败(emerg 级别)
也就是说,只要此时 DNS / hosts / Docker DNS 里还不存在 gz-api-ios,Nginx 就拒绝启动。
3. 你的场景里最常见的 4 种原因
3.1 Docker Compose 服务名不一致(最常见)
Docker DNS 里,能解析的只有 service name
检查:
1 | docker compose ps |
你需要确认 到底有没有叫 gz-api-ios 的 service
1 | services: |
⚠️注意区别:
| 配置项 | 能否被 Docker DNS 解析 |
|---|---|
| service 名 | ✅ 可以 |
| container_name | ❌ 默认不行(跨容器) |
推荐做法(生产级)
upstream 永远用 service name,不要用 container_name
3.2 Nginx 容器和 php-fpm 不在同一个 network
Docker DNS 只在同一 network 内可见
检查:
1 | docker inspect <nginx_container> | jq '.[0].NetworkSettings.Networks' |
如果不一致,Nginx 永远解析不到。
3.3 upstream 配置文件未被真正 include
你说有:
1 | $ cat conf.d/upstream.conf |
但要确认 主 nginx.conf 是否真的 include 了它:
1 | http { |
如果 upstream.conf 没被 include,fastcgi_pass php-upstream-ios:9000;
就会在解析阶段直接炸。
3.4 Nginx 启动早于 php-fpm(冷启动竞态)
即使 network 和 service 都对,启动顺序也会坑你
- Nginx 启动
- Docker DNS 里还没注册 php-fpm service
- Nginx 解析失败 → 直接退出
4.解决方案
4.1 方案一:统一使用 service name(nginx/php-fpm放到一个compose文件管理,upstream通过service_name转发)
1 | services: |
1 | upstream php-upstream-ios { |
这是 Docker + Nginx 官方推荐模式。
4.2 方案二:Nginx 启动容忍 DNS 延迟(高阶)
1 |
|
这允许 运行期动态解析 DNS,非常适合容器环境。
4.3 方案三(不推荐):写死 IP
1 | upstream php-upstream-ios { |
IP 一变就炸,仅限排障,不适合生产。