背景
我们使用 nginx 作为 docker compose 堆栈中的反向代理。 nginx 源自 nginx:1.25
我们需要强制 nginx 反向代理重新加载,作为 CI/CD 的一部分
无法保证 docker compose 在重新加载服务容器时会分配相同的 IP 地址,并且 nginx 在启动时缓存名称查找。最终结果是,当我们推送更新时,重新启动的容器最终可能会与反向代理断开连接(这不是理论上的,我们肯定会看到它发生)。
所以我们需要强制 nginx 刷新它的 dns 缓存 - 我们真的不希望反弹整个 nginx 容器。
我想做的是 bash 进入正在运行的容器并运行“service nginx reload”(这是我能找到的所有 nginx 资源所说的要做的事情)。
但是,基于 docker 的 nginx 镜像必须具有 CMD = nginx -g 'daemon off;' (否则容器将会退出)。
问题
当 nginx 在守护进程关闭的情况下启动时,它似乎不会生成 /var/run/nginx.pid 文件。这意味着所有重新加载的尝试都会失败。
其他发现
nginx.conf 文件具有:
pid /var/run/nginx.pid;
- 容器启动后 /var/run 文件夹存在。
真正有趣的是,如果我们执行“service nginx restart”,它会生成 pid 文件,并且从该点开始的所有重新加载都会成功(直到容器重新启动)。
当我们尝试使用非服务命令时,我们会看到类似的行为:
nginx -s reload
结果是:
nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
我们在 logrotate.d 上看到了类似的问题 - 它依赖于创建 nginx.pid - 这绝对不会在 -g 'daemon off;' 时发生。发射。
那么:我们如何让 nginx 重新加载而无需重新启动 nginx(或整个容器重新启动)?还是最好的做法是重新启动?
可能(不是很好)的解决方法
我已经尝试过:
docker compose kill -s HUP <nginx_service_name>
这确实会强制重新加载配置 - 但它并不能解决 logrotate 问题(并且无法在不知道 pid 的情况下从容器内的 cron 作业执行kill -s USR1)。
另外,我越来越怀疑重新加载是否足以让 nginx 获取 DNS 更改......也许这里需要重新启动。
与此同时,我正在对 CICD 和 logrotate 配置使用重启。只是希望有一些更手术的东西。
如果其他人遇到这种情况:
根本问题是我使用
docker compose run
而不是 docker compose exec
执行“重新加载”步骤。这会导致操作系统干净启动(不执行 CMD),因此当然不会创建 pid 文件。吸取教训。
另外,我已经确认 nginx -s reload 足以让 nginx 重新加载其 DNS 缓存。无需完全重启。
最终结果是将此调用添加到我的 CICD 脚本中(相当于针对 nginx pid 的kill -s USR1):
docker compose exec <nginx-service-name> nginx -s reload
类似地,在 logrotate 的后轮换中执行以下操作(相当于针对 nginx pid 执行kill -s HUP):
nginx -s reopen