docker 容器在负载均衡器后面的滚动部署
rolling deployment for docker containers behind load balancer
我在负载均衡器后面滚动部署 docker 个容器时遇到问题。
这是我的 docker compose yml 文件内容。
nginx:
image: nginx_image
links:
- node1:node1
- node2:node2
- node3:node3
ports:
- "80:80"
node1:
image: nodeapi_image
ports:
- "8001"
node2:
image: nodeapi_image
ports:
- "8001"
node3:
image: nodeapi_image
ports:
- "8001"
这是我的 nginx.conf
worker_processes 4;
events { worker_connections 1024; }
http {
upstream node-app {
least_conn;
server node1:8001 weight=10 max_fails=3 fail_timeout=30s;
server node2:8001 weight=10 max_fails=3 fail_timeout=30s;
server node3:8001 weight=10 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
listen 443 ssl;
# ssl on;
ssl_certificate /etc/nginx/ssl/imago.io.chain.crt;
ssl_certificate_key /etc/nginx/ssl/imago.io.key;
location / {
proxy_pass http://node-app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}
如果我要部署一个新构建的映像,我必须停止节点容器,将其删除并使用新映像重新创建它。这里的问题是新容器将获得一个新 IP 而 nginx 容器不知道该新 IP,因此如果我重新创建负载均衡器后面的 3 个容器,一旦我重新创建最后一个容器,应用程序将不再提供服务,因为所有 IP在 nginx 机器中 /etc/hosts
和环境变量不再是最新的。
我可以通过 SSH 连接到每个容器,通过从 git 存储库中提取并重新启动进程来更新其代码,但这对我来说似乎是错误的。这样做的正确方法是什么?
有一个更简单的方法来实现,以下面的docker-compose.yml文件为例:
lb:
image: tutum/haproxy
links:
- app
ports:
- "80:80"
app:
image: tutum/hello-world
这个 docker 组合文件描述了两个服务:
- lb:使用 tutum/haproxy 镜像的负载均衡器
- 应用程序:侦听端口 80 的示例 Web 应用程序
如果您天真地使用 docker-compose up -d
启动这些服务,您最终将只有 2 个容器(负载均衡器和 Web 应用程序)。
但是如果你 运行 docker-compose scale app=3
然后 运行 再次 docker-compose up -d
,你最终会得到 4 个负载平衡容器。
这里的关键人物是 tutum/haproxy
docker 图像,它能够发现它链接到的不同容器。
一个类似的解决方案是使用 Jason Wilder's nginx-proxy 图像,它的优点是可以实时发现新节点;这样您就不必重新启动 lb
服务。
lb:
image: jwilder/nginx-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
ports:
- "80:80"
app:
image: tutum/hello-world
environment:
VIRTUAL_HOST: www.mysite.com
VIRTUAL_HOST
环境变量必须设置为解析为 docker 主机 IP 地址的域名。
另一种是使用Traefik
lb:
image: traefik
command: --docker
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
app:
image: tutum/hello-world
labels:
traefik.frontend.rule: Host:www.mysite.com
traefik.frontend.rule
标签必须定义一个 Traefik rule 设置为解析为 docker 主机 IP 地址的域名。
Traefik 还提供不同的 load balancing strategies and circuit breakers.
我在负载均衡器后面滚动部署 docker 个容器时遇到问题。
这是我的 docker compose yml 文件内容。
nginx:
image: nginx_image
links:
- node1:node1
- node2:node2
- node3:node3
ports:
- "80:80"
node1:
image: nodeapi_image
ports:
- "8001"
node2:
image: nodeapi_image
ports:
- "8001"
node3:
image: nodeapi_image
ports:
- "8001"
这是我的 nginx.conf
worker_processes 4;
events { worker_connections 1024; }
http {
upstream node-app {
least_conn;
server node1:8001 weight=10 max_fails=3 fail_timeout=30s;
server node2:8001 weight=10 max_fails=3 fail_timeout=30s;
server node3:8001 weight=10 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
listen 443 ssl;
# ssl on;
ssl_certificate /etc/nginx/ssl/imago.io.chain.crt;
ssl_certificate_key /etc/nginx/ssl/imago.io.key;
location / {
proxy_pass http://node-app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}
如果我要部署一个新构建的映像,我必须停止节点容器,将其删除并使用新映像重新创建它。这里的问题是新容器将获得一个新 IP 而 nginx 容器不知道该新 IP,因此如果我重新创建负载均衡器后面的 3 个容器,一旦我重新创建最后一个容器,应用程序将不再提供服务,因为所有 IP在 nginx 机器中 /etc/hosts
和环境变量不再是最新的。
我可以通过 SSH 连接到每个容器,通过从 git 存储库中提取并重新启动进程来更新其代码,但这对我来说似乎是错误的。这样做的正确方法是什么?
有一个更简单的方法来实现,以下面的docker-compose.yml文件为例:
lb:
image: tutum/haproxy
links:
- app
ports:
- "80:80"
app:
image: tutum/hello-world
这个 docker 组合文件描述了两个服务:
- lb:使用 tutum/haproxy 镜像的负载均衡器
- 应用程序:侦听端口 80 的示例 Web 应用程序
如果您天真地使用 docker-compose up -d
启动这些服务,您最终将只有 2 个容器(负载均衡器和 Web 应用程序)。
但是如果你 运行 docker-compose scale app=3
然后 运行 再次 docker-compose up -d
,你最终会得到 4 个负载平衡容器。
这里的关键人物是 tutum/haproxy
docker 图像,它能够发现它链接到的不同容器。
一个类似的解决方案是使用 Jason Wilder's nginx-proxy 图像,它的优点是可以实时发现新节点;这样您就不必重新启动 lb
服务。
lb:
image: jwilder/nginx-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
ports:
- "80:80"
app:
image: tutum/hello-world
environment:
VIRTUAL_HOST: www.mysite.com
VIRTUAL_HOST
环境变量必须设置为解析为 docker 主机 IP 地址的域名。
另一种是使用Traefik
lb:
image: traefik
command: --docker
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
app:
image: tutum/hello-world
labels:
traefik.frontend.rule: Host:www.mysite.com
traefik.frontend.rule
标签必须定义一个 Traefik rule 设置为解析为 docker 主机 IP 地址的域名。
Traefik 还提供不同的 load balancing strategies and circuit breakers.