ECS 上的 Nginx 容器未遵循滚动更新
Nginx container on ECS not following rolling update
我非常接近使用 Docker Compose 和 ECS 找到一个不错的设置,但还剩下一件小事。
场景是这样的:
- 更新应用程序 (Django) 源代码并使用 Docker Compose 和 Docker Context 部署到 ECS。
- ECS 为应用程序注册一个新任务,并与旧任务一起启动。
- 问题:Nginx 对旧容器进行健康检查,当它被注销时,nginx 开始抛出 502 错误并重新启动任务,导致停机和不可用。
- Nginx 再次启动并对新容器进行健康检查,应用程序再次运行,但如前所述出现意外停机。
我需要在这里做一些配置吗?我错过了什么吗?
docker-compose.yml供参考:
services:
web:
image: # Image from ECR, built from GH-action.
command: gunicorn core.wsgi:application --bind 0.0.0.0:8000
environment:
# ...
volumes:
# ...
deploy:
replicas: 1
nginx:
image: # Image from ECR, kept static
ports:
- "80:80"
volumes:
# ...
depends_on:
- web
deploy:
replicas: 1
事实证明这是一个很大的挑战。底线是 ECS 任务在 运行 时无法更新。所以我们需要重启任务或者使用execute-command
手动更新。
我尝试了 jwilder/nginx-proxy
方法,但由于卷安装与该启动类型的工作方式,这对于 Fargate 是不可能的。
我最终为我的 nginx 容器使用了 sidecar 模式,但是,目前没有可用于 Compose-CLI 的 sidecar 的解决方案(参见 https://github.com/docker/compose-cli/issues/1566),所以我不得不使用 x-aws-cloudformation
以稍微凌乱的方式叠加。
所以首先我们只删除 nginx 服务:
version: "3.9"
services:
web:
image: # django-app
command: gunicorn core.wsgi:application --bind 0.0.0.0:8000
environment:
# ...
volumes:
# ...
ports:
- "80:80" # Move ports into this service so we get the ALB
deploy:
replicas: 1
运行转换命令获取生成的CloudFormation模板:
docker compose covert > cfn.yml
然后添加 x-aws-cloudformation
叠加层:
x-aws-cloudformation:
Resources:
WebTaskDefinition:
Properties:
ContainerDefinitions:
# Generated container definitions, copy/paste from cfn.yml
# Only change ContainerPort for web:
- # ...Web_ResolvConf_InitContainer
- # ...Web-container
PortMappings:
- ContainerPort: 8000
# The nginx sidecar:
- DependsOn:
- Condition: SUCCESS
ContainerName: Web_ResolvConf_InitContainer
- Condition: START
ContainerName: web
Essential: true
Image: # nginx
LogConfiguration:
# ...
MountPoints:
# ...
Name: nginx
PortMappings:
- ContainerPort: 80
# We also need to tell the load-balancer to reference the nginx container
WebService:
Properties:
LoadBalancers:
- ContainerName: nginx
ContainerPort: 80
TargetGroupArn:
Ref: WebTCP80TargetGroup
最后,我们需要稍微更改一下 nginx 配置
# BEFORE
upstream app_server {
server web:8000 fail_timeout=0;
}
# AFTER
upstream app_server {
server 0.0.0.0:8000 fail_timeout=0;
}
不漂亮,但很管用。滚动更新现在将按预期实现零停机时间。希望随着 Compose-CLI 的发展,这种模式将得到改进!
我非常接近使用 Docker Compose 和 ECS 找到一个不错的设置,但还剩下一件小事。
场景是这样的:
- 更新应用程序 (Django) 源代码并使用 Docker Compose 和 Docker Context 部署到 ECS。
- ECS 为应用程序注册一个新任务,并与旧任务一起启动。
- 问题:Nginx 对旧容器进行健康检查,当它被注销时,nginx 开始抛出 502 错误并重新启动任务,导致停机和不可用。
- Nginx 再次启动并对新容器进行健康检查,应用程序再次运行,但如前所述出现意外停机。
我需要在这里做一些配置吗?我错过了什么吗?
docker-compose.yml供参考:
services:
web:
image: # Image from ECR, built from GH-action.
command: gunicorn core.wsgi:application --bind 0.0.0.0:8000
environment:
# ...
volumes:
# ...
deploy:
replicas: 1
nginx:
image: # Image from ECR, kept static
ports:
- "80:80"
volumes:
# ...
depends_on:
- web
deploy:
replicas: 1
事实证明这是一个很大的挑战。底线是 ECS 任务在 运行 时无法更新。所以我们需要重启任务或者使用execute-command
手动更新。
我尝试了 jwilder/nginx-proxy
方法,但由于卷安装与该启动类型的工作方式,这对于 Fargate 是不可能的。
我最终为我的 nginx 容器使用了 sidecar 模式,但是,目前没有可用于 Compose-CLI 的 sidecar 的解决方案(参见 https://github.com/docker/compose-cli/issues/1566),所以我不得不使用 x-aws-cloudformation
以稍微凌乱的方式叠加。
所以首先我们只删除 nginx 服务:
version: "3.9"
services:
web:
image: # django-app
command: gunicorn core.wsgi:application --bind 0.0.0.0:8000
environment:
# ...
volumes:
# ...
ports:
- "80:80" # Move ports into this service so we get the ALB
deploy:
replicas: 1
运行转换命令获取生成的CloudFormation模板:
docker compose covert > cfn.yml
然后添加 x-aws-cloudformation
叠加层:
x-aws-cloudformation:
Resources:
WebTaskDefinition:
Properties:
ContainerDefinitions:
# Generated container definitions, copy/paste from cfn.yml
# Only change ContainerPort for web:
- # ...Web_ResolvConf_InitContainer
- # ...Web-container
PortMappings:
- ContainerPort: 8000
# The nginx sidecar:
- DependsOn:
- Condition: SUCCESS
ContainerName: Web_ResolvConf_InitContainer
- Condition: START
ContainerName: web
Essential: true
Image: # nginx
LogConfiguration:
# ...
MountPoints:
# ...
Name: nginx
PortMappings:
- ContainerPort: 80
# We also need to tell the load-balancer to reference the nginx container
WebService:
Properties:
LoadBalancers:
- ContainerName: nginx
ContainerPort: 80
TargetGroupArn:
Ref: WebTCP80TargetGroup
最后,我们需要稍微更改一下 nginx 配置
# BEFORE
upstream app_server {
server web:8000 fail_timeout=0;
}
# AFTER
upstream app_server {
server 0.0.0.0:8000 fail_timeout=0;
}
不漂亮,但很管用。滚动更新现在将按预期实现零停机时间。希望随着 Compose-CLI 的发展,这种模式将得到改进!