【Docker】docker-compose中的nginx为何突然访问不到服务了?

docker-compose中的nginx为何突然访问不到服务了?

我使用docker-compose的方式启动了一个Nginx、服务A、服务B,nginxconfig内部是填写的服务名,

在重建服务A之后,有时就会出现服务A无法访问的问题,此时重启一下nginx就可以访问到了。

场景复现准备

目录结构
text 复制代码
docker-repro/
├── docker-compose.yml
├── nginx/
│   └── nginx.conf
└── service-a/
    ├── Dockerfile
    └── app.py

1. 编写 docker-compose.yml

在根目录 docker-repro/docker-compose.yml 中写入:

yaml 复制代码
version: '3.8'

services:
  nginx:
    image: nginx:latest
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "8080:80"
    depends_on:
      - service_a

  service_a:
    build: ./service-a
    container_name: service_a

  service_b:
    image: busybox
    command: ["sh", "-c", "while true; do echo B; sleep 5; done"]
    container_name: service_b
  • service_a:一个简单的 Python Flask 服务,返回 "Hello A"
  • service_b:一个不停输出字符 B 的占位容器
  • nginx :反向代理到 service_a,端口转发到本机 8080

2. 编写 Service A

在 docker-repro/service-a/ 下:

app.py
python 复制代码
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello A\n'

if __name__ == '__main__':
    # 监听 5000 端口
    app.run(host='0.0.0.0', port=5000)
Dockerfile
dockerfile 复制代码
FROM dockerpull.cn/library/python:3.9-slim
WORKDIR /app
COPY app.py /app/
RUN pip install flask  -i https://mirrors.aliyun.com/pypi/simple/
EXPOSE 5000
CMD ["python", "app.py"]

3. 编写 Nginx 配置

在 docker-repro/nginx/nginx.conf 中:

nginx 复制代码
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    upstream service_a {
        server service_a:5000;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://service_a;
        }
    }
}

注意:这里直接在 upstream 里写了 service_a:5000,Nginx 启动时只解析一次。


4. 启动服务并验证启动成功

在项目根目录运行:

bash 复制代码
docker-compose up -d --build

待启动完成之后执行:

bash 复制代码
curl -i http://localhost:8080

问题复现

  • 先查看下目前service_a的IP
shell 复制代码
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' service_a
销毁并重新创建 Service A
shell 复制代码
docker-compose stop service_a
docker-compose rm -f service_a
docker-compose up -d service_a

如果你是这样就开始实验了,那么你大概率会发现 IP 没变,服务正常访问,本次实验就没有找出原因。

因为 Docker 的网络默认会"填补空缺"------只要那个槽位(IP)在你重建前没有被别的容器占用,

它就会再分配给新的 service_a。

想要让它真正拿到一个不同的 IP,你需要"先占坑"。

正确复现的做法是:

shell 复制代码
docker-compose stop service_a
docker-compose rm -f service_a

# 使用一个临时的容器占坑
docker run -d --name dummy --network docker-repro_default busybox sleep 3600

docker-compose up -d service_a

这样你再次执行查看ip命令就能发现,IP变了,服务访问不到了,问题复现出来了。

总结以下问题的核心:
Nginx 默认只解析服务名一次,DNS 结果缓存不变。
Docker 中服务 A 重建后 IP 会变,但 Nginx 仍然访问旧 IP,导致连接失败。

解决方案

解决方案有很多,在这里使用较为简单的一种方式,仅需要修改nginx配置文件。

shell 复制代码
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    resolver 127.0.0.11 valid=5s;

    server {
        listen 80;

        location / {
            set $backend "service_a:5000";
            proxy_pass http://$backend;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}
配置项 作用
resolver 127.0.0.11 使用 Docker 内置 DNS 进行域名解析
valid=5s DNS 记录最多缓存 5 秒,之后会重新解析
set $backend 动态构造代理地址,触发每次请求前的 DNS 查询
proxy_pass http://$backend 代理到动态地址
proxy_set_header 添加常用的请求头,方便后端服务识别请求来源
相关推荐
Wang's Blog3 小时前
Java 项目部署之 Docker工具快速入门: Docker 是什么以及它如何解决部署环境问题
java·开发语言·docker
AIGC大时代4 小时前
LLM Agent 执行沙箱闸门:失败含义与当天最小实验
docker·沙箱·闸门·bubblewrap·llm agent
灯澜忆梦5 小时前
【docker】#2 | 基础命令
docker·容器·eureka
程序员老赵7 小时前
Docker 部署 WordPress:轻松搭建开源内容管理平台
docker·开源·wordpress
sbjdhjd8 小时前
云安全 | 从特权容器到旧版 runC:Docker 宿主机访问与运行时缺陷复盘
运维·网络安全·docker·云原生·kubernetes·云计算·云安全
Pocker_Spades_A10 小时前
Penpot自托管设计协作:Docker部署、MCP接入与Codex生成UI实操记录
ui·docker·容器
Lvan的前端笔记19 小时前
docker:每个前端项目一个 Nginx 容器还是只有一个Nginx容器
前端·nginx·docker
姜鱼问生19 小时前
Nginx 缓存命中率监控:从 X-Cache-Status 到实时统计
运维·nginx·缓存
sbjdhjd1 天前
云安全 | Docker 容器逃逸复盘(三):docker.sock 挂载与 Docker-in-Docker 风险
经验分享·网络安全·docker·云原生·容器·kubernetes·云安全