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
2
3
upstream php-upstream-ios {
server gz-api-ios:9000;
}

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
2
3
services:
php-fpm-74-ios:
container_name: gz-api-ios

⚠️注意区别:

配置项 能否被 Docker DNS 解析
service 名 ✅ 可以
container_name ❌ 默认不行(跨容器)

推荐做法(生产级)
upstream 永远用 service name,不要用 container_name


3.2 Nginx 容器和 php-fpm 不在同一个 network

Docker DNS 只在同一 network 内可见

检查:

1
2
docker inspect <nginx_container> | jq '.[0].NetworkSettings.Networks'
docker inspect <php_container> | jq '.[0].NetworkSettings.Networks'

如果不一致,Nginx 永远解析不到。


3.3 upstream 配置文件未被真正 include

你说有:

1
$ cat conf.d/upstream.conf

但要确认 主 nginx.conf 是否真的 include 了它

1
2
3
4
http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-available/*.conf;
}

如果 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
2
3
4
5
6
7
8
9
10
11
12
services:
php-fpm-ios:
image: xxx
networks:
- backend

openresty:
image: openresty
depends_on:
- php-fpm-ios
networks:
- backend
1
2
3
upstream php-upstream-ios {
server php-fpm-ios:9000;
}

这是 Docker + Nginx 官方推荐模式


4.2 方案二:Nginx 启动容忍 DNS 延迟(高阶)

1
2
3
4
5
6
7

# docker内置dns
resolver 127.0.0.11 valid=30s;

upstream php-upstream-ios {
server gz-api-ios:9000 resolve;
}

这允许 运行期动态解析 DNS,非常适合容器环境。


4.3 方案三(不推荐):写死 IP

1
2
3
upstream php-upstream-ios {
server 172.24.240.10:9000;
}

IP 一变就炸,仅限排障,不适合生产