ECS 上的 Nginx 容器未遵循滚动更新

Nginx container on ECS not following rolling update

我非常接近使用 Docker Compose 和 ECS 找到一个不错的设置,但还剩下一件小事。

场景是这样的:

  1. 更新应用程序 (Django) 源代码并使用 Docker Compose 和 Docker Context 部署到 ECS。
  2. ECS 为应用程序注册一个新任务,并与旧任务一起启动。
  3. 问题:Nginx 对旧容器进行健康检查,当它被注销时,nginx 开始抛出 502 错误并重新启动任务,导致停机和不可用。
  4. 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 的发展,这种模式将得到改进!