docker compose:重建一个链接的容器会破坏 nginx 的上游

pky*_*eck 5 nginx docker docker-compose

我正在使用docker-compose“Docker for Mac”并且我有两个容器:一个 NGINX,一个容器在端口 3000 上为节点应用程序提供服务。

docker-compose.yml 看起来像这样:

version: "2"

services:
  nginx:
    build: ./nginx
    ports:
      - "80:80"
    links:
      - api
  api:
    build: ./api
    volumes:
      - "./api:/opt/app"
Run Code Online (Sandbox Code Playgroud)

在 NGINX 的配置中,我说:

upstream api {
  server api:3000;
}

server {
  # ....
  location ~ ^/api/?(.*) {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;

    proxy_pass http://api;
    proxy_redirect off;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我更改节点代码中的某些内容并重建容器时

$ docker-compose stop api && docker-compose up -d --build --no-deps api
Run Code Online (Sandbox Code Playgroud)

容器正在重建和启动。问题是,有时容器的内部 IP 会发生变化,而 NGINX 不会知道这一点。有趣的是,当我进入 NGINX 容器并ping api获得新的 IP 地址时

$ ping api
PING api (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: icmp_seq=0 ttl=64 time=0.236 ms
Run Code Online (Sandbox Code Playgroud)

但 NGINX 日志仍然说

2016/10/20 14:20:53 [error] 9#9: *9 connect() failed (113: No route to host) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET /api/test HTTP/1.1", upstream: "http://172.19.0.7:3000/api/test", host: "localhost"
Run Code Online (Sandbox Code Playgroud)

上游172.19.0.7仍然是旧的 IP 地址。

PS:每次我重建容器时都不会发生这种情况。

Elt*_*man 4

这是因为Nginx 缓存了上游服务器的 DNS 响应- 在您的工作流程中,您只需重新启动应用程序容器,因此 Nginx 不会重新加载,并且始终使用其缓存的api容器 IP 地址。

当您运行一个新api容器时,如您所见,它可能具有不同的 IP 地址,因此 Nginx 中的缓存无效。之所以ping有效,是因为它不缓存 Docker 的 DNS 响应。

假设这仅适用于开发并且停机时间不是问题,docker-compose restart nginx那么在重建应用程序容器后,将重新启动 Nginx 并清除 DNS 缓存。