aws-cloudformation-task-ecs-deploy-gh

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AWS CloudFormation Task ECS Deploy with GitHub Actions

借助GitHub Actions实现AWS CloudFormation任务与ECS部署

Comprehensive skill for deploying ECS containers using GitHub Actions CI/CD pipelines with CloudFormation infrastructure management.
本技能全面介绍如何结合GitHub Actions CI/CD流水线与CloudFormation基础设施管理,完成ECS容器部署。

Overview

概述

Deploy containerized applications to Amazon ECS using GitHub Actions workflows. This skill covers the complete deployment pipeline: authentication with AWS (OIDC recommended), building Docker images, pushing to Amazon ECR, updating task definitions, and deploying ECS services. Integrate with CloudFormation for infrastructure-as-code management and implement production-grade deployment strategies.
通过GitHub Actions工作流将容器化应用部署至Amazon ECS。本技能覆盖完整部署流程:AWS认证(推荐使用OIDC)、构建Docker镜像、推送至Amazon ECR、更新任务定义以及部署ECS服务。集成CloudFormation实现基础设施即代码管理,并落地生产级部署策略。

When to Use

适用场景

Use this skill when:
  • Deploying Docker containers to Amazon ECS
  • Setting up GitHub Actions CI/CD pipelines for AWS
  • Configuring AWS authentication for GitHub Actions (OIDC or IAM keys)
  • Building and pushing Docker images to Amazon ECR
  • Updating ECS task definitions dynamically
  • Implementing blue/green or rolling deployments
  • Managing CloudFormation stacks from CI/CD
  • Setting up multi-environment deployments (dev/staging/prod)
  • Configuring private ECR repositories with image scanning
  • Automating container deployment with proper security practices
Trigger phrases:
  • "Deploy to ECS with GitHub Actions"
  • "Set up CI/CD for ECS containers"
  • "Configure GitHub Actions for AWS deployment"
  • "Build and push Docker image to ECR"
  • "Update ECS task definition from CI/CD"
  • "Implement blue/green deployment for ECS"
  • "Deploy CloudFormation stack from GitHub Actions"
在以下场景使用本技能:
  • 向Amazon ECS部署Docker容器
  • 为AWS搭建GitHub Actions CI/CD流水线
  • 为GitHub Actions配置AWS认证(OIDC或IAM密钥)
  • 构建并推送Docker镜像至Amazon ECR
  • 动态更新ECS任务定义
  • 实现蓝绿部署或滚动部署
  • 通过CI/CD管理CloudFormation堆栈
  • 搭建多环境部署(开发/预发布/生产)
  • 配置带镜像扫描的私有ECR仓库
  • 遵循安全实践实现容器部署自动化
触发关键词:
  • "使用GitHub Actions部署至ECS"
  • "为ECS容器搭建CI/CD流水线"
  • "为AWS部署配置GitHub Actions"
  • "构建并推送Docker镜像至ECR"
  • "通过CI/CD更新ECS任务定义"
  • "为ECS实现蓝绿部署"
  • "通过GitHub Actions部署CloudFormation堆栈"

Quick Start

快速开始

Basic ECS Deployment Workflow

基础ECS部署工作流

yaml
name: Deploy to ECS
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecs-role
          aws-region: us-east-1

      - name: Login to ECR
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: my-app
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

      - name: Update task definition
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        id: render-task
        with:
          task-definition: task-definition.json
          container-name: my-app
          image: ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.render-task.outputs.task-definition }}
          service: my-service
          cluster: my-cluster
          wait-for-service-stability: true
yaml
name: Deploy to ECS
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecs-role
          aws-region: us-east-1

      - name: Login to ECR
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: my-app
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

      - name: Update task definition
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        id: render-task
        with:
          task-definition: task-definition.json
          container-name: my-app
          image: ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.render-task.outputs.task-definition }}
          service: my-service
          cluster: my-cluster
          wait-for-service-stability: true

Authentication Methods

认证方式

OIDC Authentication (Recommended)

OIDC认证(推荐)

OpenID Connect (OIDC) provides secure, passwordless authentication between GitHub Actions and AWS.
Prerequisites:
  1. Create IAM role with trust policy for GitHub:
yaml
Type: AWS::IAM::Role
Properties:
  RoleName: github-actions-ecs-role
  AssumeRolePolicyDocument:
    Version: '2012-10-17'
    Statement:
      - Effect: Allow
        Principal:
          Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com'
        Action: sts:AssumeRoleWithWebIdentity
        Condition:
          StringEquals:
            token.actions.githubusercontent.com:aud: sts.amazonaws.com
          StringLike:
            token.actions.githubusercontent.com:sub: repo:my-org/my-repo:*
  ManagedPolicyArns:
    - arn:aws:iam::aws:policy/AmazonECS_FullAccess
    - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
  1. Configure GitHub Actions workflow:
yaml
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecs-role
    aws-region: us-east-1
OpenID Connect (OIDC) 为GitHub Actions与AWS之间提供安全的无密码认证机制。
前置条件:
  1. 创建针对GitHub的IAM角色信任策略:
yaml
Type: AWS::IAM::Role
Properties:
  RoleName: github-actions-ecs-role
  AssumeRolePolicyDocument:
    Version: '2012-10-17'
    Statement:
      - Effect: Allow
        Principal:
          Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com'
        Action: sts:AssumeRoleWithWebIdentity
        Condition:
          StringEquals:
            token.actions.githubusercontent.com:aud: sts.amazonaws.com
          StringLike:
            token.actions.githubusercontent.com:sub: repo:my-org/my-repo:*
  ManagedPolicyArns:
    - arn:aws:iam::aws:policy/AmazonECS_FullAccess
    - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
  1. 配置GitHub Actions工作流:
yaml
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecs-role
    aws-region: us-east-1

IAM Key Authentication (Legacy)

IAM密钥认证(传统方式)

yaml
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    aws-region: us-east-1
Store credentials in GitHub repository secrets (Settings → Secrets and variables → Actions).
yaml
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    aws-region: us-east-1
将凭证存储在GitHub仓库密钥中(设置 → 密钥和变量 → Actions)。

Build and Push to ECR

构建并推送至ECR

ECR Repository CloudFormation Template

ECR仓库CloudFormation模板

yaml
ECRRepository:
  Type: AWS::ECR::Repository
  Properties:
    RepositoryName: my-app
    ImageScanningConfiguration:
      ScanOnPush: true
    ImageTagMutability: IMMUTABLE
    LifecyclePolicy:
      LifecyclePolicyText: |
        {
          "rules": [
            {
              "rulePriority": 1,
              "description": "Keep last 30 images",
              "selection": {
                "tagStatus": "tagged",
                "tagPrefixList": ["v"],
                "countType": "imageCountMoreThan",
                "countNumber": 30
              },
              "action": {
                "type": "expire"
              }
            }
          ]
        }
yaml
ECRRepository:
  Type: AWS::ECR::Repository
  Properties:
    RepositoryName: my-app
    ImageScanningConfiguration:
      ScanOnPush: true
    ImageTagMutability: IMMUTABLE
    LifecyclePolicy:
      LifecyclePolicyText: |
        {
          "rules": [
            {
              "rulePriority": 1,
              "description": "Keep last 30 images",
              "selection": {
                "tagStatus": "tagged",
                "tagPrefixList": ["v"],
                "countType": "imageCountMoreThan",
                "countNumber": 30
              },
              "action": {
                "type": "expire"
              }
            }
          ]
        }

Build and Push Step

构建与推送步骤

yaml
- name: Login to ECR
  id: login-ecr
  uses: aws-actions/amazon-ecr-login@v2

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: |
      ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}
      ${{ steps.login-ecr.outputs.registry }}/my-app:latest
    cache-from: type=gha
    cache-to: type=gha,mode=max
    build-args: |
      BUILD_DATE=${{ github.event.head_commit.timestamp }}
      VERSION=${{ github.sha }}
yaml
- name: Login to ECR
  id: login-ecr
  uses: aws-actions/amazon-ecr-login@v2

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: |
      ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}
      ${{ steps.login-ecr.outputs.registry }}/my-app:latest
    cache-from: type=gha
    cache-to: type=gha,mode=max
    build-args: |
      BUILD_DATE=${{ github.event.head_commit.timestamp }}
      VERSION=${{ github.sha }}

Task Definition Management

任务定义管理

Basic Task Definition

基础任务定义

task-definition.json:
json
{
  "family": "my-app-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
  "containerDefinitions": [
    {
      "name": "my-app",
      "image": "PLACEHOLDER_IMAGE",
      "portMappings": [
        {
          "containerPort": 8080,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "ENVIRONMENT",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app/db-password"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/my-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs",
          "awslogs-create-group": "true"
        }
      }
    }
  ]
}
task-definition.json:
json
{
  "family": "my-app-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
  "containerDefinitions": [
    {
      "name": "my-app",
      "image": "PLACEHOLDER_IMAGE",
      "portMappings": [
        {
          "containerPort": 8080,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "ENVIRONMENT",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app/db-password"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/my-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs",
          "awslogs-create-group": "true"
        }
      }
    }
  ]
}

Dynamic Task Definition Update

动态任务定义更新

yaml
- name: Render task definition
  uses: aws-actions/amazon-ecs-render-task-definition@v1
  id: render-task
  with:
    task-definition: task-definition.json
    container-name: my-app
    image: ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}

- name: Deploy task definition
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task.outputs.task-definition }}
    service: my-service
    cluster: my-cluster
    wait-for-service-stability: true
    deploy_timeout: 30 minutes
yaml
- name: Render task definition
  uses: aws-actions/amazon-ecs-render-task-definition@v1
  id: render-task
  with:
    task-definition: task-definition.json
    container-name: my-app
    image: ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}

- name: Deploy task definition
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task.outputs.task-definition }}
    service: my-service
    cluster: my-cluster
    wait-for-service-stability: true
    deploy_timeout: 30 minutes

ECS Deployment Strategies

ECS部署策略

Rolling Deployment (Default)

滚动部署(默认)

yaml
- name: Deploy to ECS (Rolling)
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task.outputs.task-definition }}
    service: my-service
    cluster: my-cluster
    wait-for-service-stability: true
CloudFormation Service Configuration:
yaml
ECSService:
  Type: AWS::ECS::Service
  Properties:
    ServiceName: my-service
    Cluster: !Ref ECSCluster
    TaskDefinition: !Ref TaskDefinition
    DeploymentConfiguration:
      MaximumPercent: 200
      MinimumHealthyPercent: 100
      DeploymentCircuitBreaker:
        Enable: true
        Rollback: true
    HealthCheckGracePeriodSeconds: 60
    EnableECSManagedTags: true
    PropagateTags: SERVICE
yaml
- name: Deploy to ECS (Rolling)
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task.outputs.task-definition }}
    service: my-service
    cluster: my-cluster
    wait-for-service-stability: true
CloudFormation服务配置:
yaml
ECSService:
  Type: AWS::ECS::Service
  Properties:
    ServiceName: my-service
    Cluster: !Ref ECSCluster
    TaskDefinition: !Ref TaskDefinition
    DeploymentConfiguration:
      MaximumPercent: 200
      MinimumHealthyPercent: 100
      DeploymentCircuitBreaker:
        Enable: true
        Rollback: true
    HealthCheckGracePeriodSeconds: 60
    EnableECSManagedTags: true
    PropagateTags: SERVICE

Blue/Green Deployment with CodeDeploy

结合CodeDeploy的蓝绿部署

yaml
- name: Deploy to ECS (Blue/Green)
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task.outputs.task-definition }}
    service: my-service
    cluster: my-cluster
    codedeploy-appspec: appspec.yaml
    codedeploy-application: my-app
    codedeploy-deployment-group: my-deployment-group
    wait-for-service-stability: true
appspec.yaml:
yaml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: my-app
          ContainerPort: 8080
        PlatformVersion: "1.4.0"
CloudFormation CodeDeploy Configuration:
yaml
CodeDeployApplication:
  Type: AWS::CodeDeploy::Application
  Properties:
    ApplicationName: my-app
    ComputePlatform: ECS

CodeDeployDeploymentGroup:
  Type: AWS::CodeDeploy::DeploymentGroup
  Properties:
    ApplicationName: !Ref CodeDeployApplication
    DeploymentGroupName: my-deployment-group
    ServiceRoleArn: !Ref CodeDeployServiceRole
    DeploymentConfigName: CodeDeployDefault.ECSAllAtOnce
    DeploymentStyle:
      DeploymentType: BLUE_GREEN
      DeploymentOption: WITH_TRAFFIC_CONTROL
    AutoRollbackConfiguration:
      Enabled: true
      Events:
        - DEPLOYMENT_FAILURE
        - DEPLOYMENT_STOP_ON_ALARM
        - DEPLOYMENT_STOP_ON_REQUEST
    AlarmConfiguration:
      Alarms:
        - !Ref CPUPercentageAlarm
        - !Ref MemoryPercentageAlarm
    BlueGreenDeploymentConfiguration:
      TerminateBlueInstancesOnDeploymentSuccess:
        Action: TERMINATE
        WaitTimeInMinutes: 5
      DeploymentReadyOption:
        ActionOnTimeout: CONTINUE_DEPLOYMENT
        WaitTimeInMinutes: 0
    LoadBalancerInfo:
      TargetGroupPairInfoList:
        - TargetGroups:
            - Ref: BlueTargetGroup
            - Ref: GreenTargetGroup
          ProdTrafficRoute:
            ListenerArns:
              - !Ref ProductionListener
yaml
- name: Deploy to ECS (Blue/Green)
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task.outputs.task-definition }}
    service: my-service
    cluster: my-cluster
    codedeploy-appspec: appspec.yaml
    codedeploy-application: my-app
    codedeploy-deployment-group: my-deployment-group
    wait-for-service-stability: true
appspec.yaml:
yaml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: my-app
          ContainerPort: 8080
        PlatformVersion: "1.4.0"
CloudFormation CodeDeploy配置:
yaml
CodeDeployApplication:
  Type: AWS::CodeDeploy::Application
  Properties:
    ApplicationName: my-app
    ComputePlatform: ECS

CodeDeployDeploymentGroup:
  Type: AWS::CodeDeploy::DeploymentGroup
  Properties:
    ApplicationName: !Ref CodeDeployApplication
    DeploymentGroupName: my-deployment-group
    ServiceRoleArn: !Ref CodeDeployServiceRole
    DeploymentConfigName: CodeDeployDefault.ECSAllAtOnce
    DeploymentStyle:
      DeploymentType: BLUE_GREEN
      DeploymentOption: WITH_TRAFFIC_CONTROL
    AutoRollbackConfiguration:
      Enabled: true
      Events:
        - DEPLOYMENT_FAILURE
        - DEPLOYMENT_STOP_ON_ALARM
        - DEPLOYMENT_STOP_ON_REQUEST
    AlarmConfiguration:
      Alarms:
        - !Ref CPUPercentageAlarm
        - !Ref MemoryPercentageAlarm
    BlueGreenDeploymentConfiguration:
      TerminateBlueInstancesOnDeploymentSuccess:
        Action: TERMINATE
        WaitTimeInMinutes: 5
      DeploymentReadyOption:
        ActionOnTimeout: CONTINUE_DEPLOYMENT
        WaitTimeInMinutes: 0
    LoadBalancerInfo:
      TargetGroupPairInfoList:
        - TargetGroups:
            - Ref: BlueTargetGroup
            - Ref: GreenTargetGroup
          ProdTrafficRoute:
            ListenerArns:
              - !Ref ProductionListener

CloudFormation Integration

CloudFormation集成

Update Stack from GitHub Actions

通过GitHub Actions更新堆栈

yaml
- name: Deploy CloudFormation stack
  run: |
    aws cloudformation deploy \
      --template-file infrastructure/ecs-stack.yaml \
      --stack-name my-app-ecs \
      --capabilities CAPABILITY_NAMED_IAM \
      --parameter-overrides \
        Environment=production \
        DesiredCount=2 \
        CPU=256 \
        Memory=512 \
        ImageUrl=${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}
yaml
- name: Deploy CloudFormation stack
  run: |
    aws cloudformation deploy \
      --template-file infrastructure/ecs-stack.yaml \
      --stack-name my-app-ecs \
      --capabilities CAPABILITY_NAMED_IAM \
      --parameter-overrides \
        Environment=production \
        DesiredCount=2 \
        CPU=256 \
        Memory=512 \
        ImageUrl=${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }}

CloudFormation Stack with ECS Resources

包含ECS资源的CloudFormation堆栈

ecs-stack.yaml:
yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: ECS Fargate Service with CloudFormation

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, prod]
  DesiredCount:
    Type: Number
    Default: 2
  CPU:
    Type: String
    Default: '256'
  Memory:
    Type: String
    Default: '512'
  ImageUrl:
    Type: String

Resources:
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub '${Environment}-cluster'
      ClusterSettings:
        - Name: containerInsights
          Value: enabled

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub '${Environment}-task'
      Cpu: !Ref CPU
      Memory: !Ref Memory
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn
      TaskRoleArn: !GetAtt TaskRole.Arn
      ContainerDefinitions:
        - Name: my-app
          Image: !Ref ImageUrl
          PortMappings:
            - ContainerPort: 8080
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref LogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs

  ECSService:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerListener
    Properties:
      ServiceName: !Sub '${Environment}-service'
      Cluster: !Ref ECSCluster
      TaskDefinition: !Ref TaskDefinition
      DesiredCount: !Ref DesiredCount
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          Subnets:
            - !Ref PrivateSubnetA
            - !Ref PrivateSubnetB
          SecurityGroups:
            - !Ref ContainerSecurityGroup
          AssignPublicIp: DISABLED
      LoadBalancers:
        - ContainerName: my-app
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroup
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
        DeploymentCircuitBreaker:
          Enable: true
          Rollback: true
      HealthCheckGracePeriodSeconds: 60

Outputs:
  ServiceURL:
    Description: Service URL
    Value: !Sub 'http://${LoadBalancer.DNSName}'
ecs-stack.yaml:
yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: ECS Fargate Service with CloudFormation

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, prod]
  DesiredCount:
    Type: Number
    Default: 2
  CPU:
    Type: String
    Default: '256'
  Memory:
    Type: String
    Default: '512'
  ImageUrl:
    Type: String

Resources:
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub '${Environment}-cluster'
      ClusterSettings:
        - Name: containerInsights
          Value: enabled

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub '${Environment}-task'
      Cpu: !Ref CPU
      Memory: !Ref Memory
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn
      TaskRoleArn: !GetAtt TaskRole.Arn
      ContainerDefinitions:
        - Name: my-app
          Image: !Ref ImageUrl
          PortMappings:
            - ContainerPort: 8080
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref LogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs

  ECSService:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerListener
    Properties:
      ServiceName: !Sub '${Environment}-service'
      Cluster: !Ref ECSCluster
      TaskDefinition: !Ref TaskDefinition
      DesiredCount: !Ref DesiredCount
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          Subnets:
            - !Ref PrivateSubnetA
            - !Ref PrivateSubnetB
          SecurityGroups:
            - !Ref ContainerSecurityGroup
          AssignPublicIp: DISABLED
      LoadBalancers:
        - ContainerName: my-app
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroup
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
        DeploymentCircuitBreaker:
          Enable: true
          Rollback: true
      HealthCheckGracePeriodSeconds: 60

Outputs:
  ServiceURL:
    Description: Service URL
    Value: !Sub 'http://${LoadBalancer.DNSName}'

Stack Outputs for Cross-Stack References

用于跨堆栈引用的堆栈输出

yaml
Outputs:
  ClusterName:
    Description: ECS Cluster Name
    Value: !Ref ECSCluster
    Export:
      Name: !Sub '${AWS::StackName}-ClusterName'

  ServiceName:
    Description: ECS Service Name
    Value: !Ref ECSService
    Export:
      Name: !Sub '${AWS::StackName}-ServiceName'

  TaskDefinitionArn:
    Description: Task Definition ARN
    Value: !Ref TaskDefinition
    Export:
      Name: !Sub '${AWS::StackName}-TaskDefinitionArn'
yaml
Outputs:
  ClusterName:
    Description: ECS Cluster Name
    Value: !Ref ECSCluster
    Export:
      Name: !Sub '${AWS::StackName}-ClusterName'

  ServiceName:
    Description: ECS Service Name
    Value: !Ref ECSService
    Export:
      Name: !Sub '${AWS::StackName}-ServiceName'

  TaskDefinitionArn:
    Description: Task Definition ARN
    Value: !Ref TaskDefinition
    Export:
      Name: !Sub '${AWS::StackName}-TaskDefinitionArn'

Best Practices

最佳实践

Security

安全

  1. Use OIDC authentication instead of long-lived IAM keys
  2. Implement least privilege IAM roles with specific permissions
  3. Enable ECR image scanning on push
  4. Use AWS Secrets Manager for sensitive data
  5. Encrypt ECR repositories with KMS
  6. VPC endpoints for ECR and ECS without internet gateway
  7. Security groups restrict access to minimum required
  1. 使用OIDC认证替代长期IAM密钥
  2. 实现最小权限IAM角色,配置特定权限
  3. 启用ECR镜像推送扫描
  4. 使用AWS Secrets Manager存储敏感数据
  5. 通过KMS加密ECR仓库
  6. 为ECR和ECS配置VPC终端节点,无需互联网网关
  7. 安全组限制访问,仅开放必要端口

IAM Role Permissions

IAM角色权限

yaml
ECSDeployRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com'
          Action: sts:AssumeRoleWithWebIdentity
          Condition:
            StringEquals:
              token.actions.githubusercontent.com:aud: sts.amazonaws.com
            StringLike:
              token.actions.githubusercontent.com:sub: repo:${GitHubOrg}/${GitHubRepo}:*
    Policies:
      - PolicyName: ECSDeployPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - ecs:DescribeServices
                - ecs:DescribeTaskDefinition
                - ecs:DescribeTasks
                - ecs:ListTasks
                - ecs:RegisterTaskDefinition
                - ecs:UpdateService
              Resource: !Sub 'arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*'
            - Effect: Allow
              Action:
                - ecr:GetAuthorizationToken
                - ecr:BatchCheckLayerAvailability
                - ecr:GetDownloadUrlForLayer
                - ecr:GetRepositoryPolicy
                - ecr:DescribeRepositories
                - ecr:ListImages
                - ecr:DescribeImages
                - ecr:BatchGetImage
                - ecr:InitiateLayerUpload
                - ecr:UploadLayerPart
                - ecr:CompleteLayerUpload
                - ecr:PutImage
              Resource: !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${ECRRepositoryName}'
            - Effect: Allow
              Action:
                - cloudformation:DescribeStacks
                - cloudformation:CreateStack
                - cloudformation:UpdateStack
                - cloudformation:DescribeStackEvents
              Resource: !Sub 'arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${CloudFormationStackName}/*'
yaml
ECSDeployRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Principal:
            Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com'
          Action: sts:AssumeRoleWithWebIdentity
          Condition:
            StringEquals:
              token.actions.githubusercontent.com:aud: sts.amazonaws.com
            StringLike:
              token.actions.githubusercontent.com:sub: repo:${GitHubOrg}/${GitHubRepo}:*
    Policies:
      - PolicyName: ECSDeployPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - ecs:DescribeServices
                - ecs:DescribeTaskDefinition
                - ecs:DescribeTasks
                - ecs:ListTasks
                - ecs:RegisterTaskDefinition
                - ecs:UpdateService
              Resource: !Sub 'arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*'
            - Effect: Allow
              Action:
                - ecr:GetAuthorizationToken
                - ecr:BatchCheckLayerAvailability
                - ecr:GetDownloadUrlForLayer
                - ecr:GetRepositoryPolicy
                - ecr:DescribeRepositories
                - ecr:ListImages
                - ecr:DescribeImages
                - ecr:BatchGetImage
                - ecr:InitiateLayerUpload
                - ecr:UploadLayerPart
                - ecr:CompleteLayerUpload
                - ecr:PutImage
              Resource: !Sub 'arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${ECRRepositoryName}'
            - Effect: Allow
              Action:
                - cloudformation:DescribeStacks
                - cloudformation:CreateStack
                - cloudformation:UpdateStack
                - cloudformation:DescribeStackEvents
              Resource: !Sub 'arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${CloudFormationStackName}/*'

Performance

性能

  1. Docker layer caching with GitHub Actions cache
  2. Multi-stage builds to minimize image size
  3. Parallel deployments across multiple environments
  4. Fargate Spot for cost savings on non-critical workloads
  5. CloudWatch Logs with appropriate retention policies
  1. 通过GitHub Actions缓存实现Docker层缓存
  2. 使用多阶段构建最小化镜像体积
  3. 多环境并行部署
  4. 使用Fargate Spot降低非关键工作负载成本
  5. 配置CloudWatch Logs并设置合适的保留策略

Cost Optimization

成本优化

  1. ECR lifecycle policies to clean up old images
  2. Fargate Spot instances for development/testing
  3. Right-sized task CPU and memory
  4. Auto-scaling based on metrics
  5. Scheduled scaling for predictable traffic patterns
  1. 配置ECR生命周期策略清理旧镜像
  2. 为开发/测试环境使用Fargate Spot实例
  3. 合理调整任务CPU与内存规格
  4. 基于指标实现自动扩缩容
  5. 为可预测流量配置定时扩缩容

Multi-Environment Deployments

多环境部署

yaml
name: Deploy to ECS
on:
  push:
    branches: [main, staging, develop]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    strategy:
      matrix:
        environment: [dev, staging, prod]
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecs-${{ matrix.environment }}
          aws-region: us-east-1

      - name: Deploy to ${{ matrix.environment }}
        run: |
          aws cloudformation deploy \
            --template-file infrastructure/ecs-stack.yaml \
            --stack-name my-app-${{ matrix.environment }} \
            --parameter-overrides \
              Environment=${{ matrix.environment }} \
              ImageUrl=${{ steps.build-image.outputs.image-url }}
yaml
name: Deploy to ECS
on:
  push:
    branches: [main, staging, develop]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    strategy:
      matrix:
        environment: [dev, staging, prod]
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-ecs-${{ matrix.environment }}
          aws-region: us-east-1

      - name: Deploy to ${{ matrix.environment }}
        run: |
          aws cloudformation deploy \
            --template-file infrastructure/ecs-stack.yaml \
            --stack-name my-app-${{ matrix.environment }} \
            --parameter-overrides \
              Environment=${{ matrix.environment }} \
              ImageUrl=${{ steps.build-image.outputs.image-url }}

Monitoring and Observability

监控与可观测性

  1. CloudWatch Container Insights for ECS metrics
  2. Application logs centralized in CloudWatch Logs
  3. Health checks with proper grace periods
  4. CloudWatch Alarms for deployment failures
  5. X-Ray tracing for distributed tracing
  1. 使用CloudWatch Container Insights获取ECS指标
  2. 将应用日志集中存储至CloudWatch Logs
  3. 配置健康检查并设置合理的宽限期
  4. 配置CloudWatch告警监控部署失败
  5. 使用X-Ray追踪实现分布式链路追踪

Further Reading

拓展阅读

  • Reference Documentation - Detailed technical reference for GitHub Actions syntax, OIDC configuration, ECR operations, task definitions, and CloudFormation integration
  • Production Examples - Complete, production-ready workflows including basic deployments, multi-environment setups, blue/green deployments, private ECR with scanning, CloudFormation stack updates, and full CI/CD pipelines with testing
  • 参考文档 - GitHub Actions语法、OIDC配置、ECR操作、任务定义及CloudFormation集成的详细技术参考
  • 生产示例 - 完整的生产就绪工作流,包括基础部署、多环境配置、蓝绿部署、带扫描的私有ECR、CloudFormation堆栈更新及包含测试的完整CI/CD流水线

Key Concepts

核心概念

  • GitHub Actions: Automate workflows from GitHub repository events
  • OIDC Authentication: Secure, tokenless authentication between GitHub and AWS
  • ECR: Amazon Elastic Container Registry for Docker image storage
  • ECS: Amazon Elastic Container Service for container orchestration
  • Fargate: Serverless compute engine for ECS without managing servers
  • Task Definition: Blueprint for ECS containers (similar to Pod spec in Kubernetes)
  • Service: Long-running ECS service with load balancing and auto-scaling
  • CloudFormation: Infrastructure as Code for AWS resource management
  • Blue/Green Deployment: Zero-downtime deployment strategy with CodeDeploy
  • GitHub Actions: 基于GitHub仓库事件自动化工作流
  • OIDC Authentication: GitHub与AWS之间的安全无令牌认证
  • ECR: 用于存储Docker镜像的Amazon弹性容器注册表
  • ECS: 用于容器编排的Amazon弹性容器服务
  • Fargate: 无需管理服务器的ECS无服务器计算引擎
  • Task Definition: ECS容器的蓝图(类似Kubernetes中的Pod规格)
  • Service: 具备负载均衡与自动扩缩容的长期运行ECS服务
  • CloudFormation: 用于AWS资源管理的基础设施即代码工具
  • Blue/Green Deployment: 结合CodeDeploy实现的零停机部署策略

Common Troubleshooting

常见问题排查

Authentication failures:
  • Verify OIDC trust relationship matches GitHub organization/repository
  • Check IAM role has proper permissions for ECR and ECS
  • Ensure GitHub Actions repository has
    id-token: write
    permission
Deployment failures:
  • Check CloudWatch Logs for application errors
  • Verify task definition matches service requirements
  • Ensure sufficient CPU/memory in Fargate cluster
  • Review health check configuration
ECR push failures:
  • Verify repository exists and permissions are correct
  • Check image tag format and registry URL
  • Ensure Docker daemon is running in GitHub Actions runner
  • Verify image size doesn't exceed ECR limits
CloudFormation rollback:
  • Review stack events in AWS Console
  • Check parameter values match resource constraints
  • Verify IAM role has
    cloudformation:UpdateStack
    permission
  • Enable termination protection for production stacks
认证失败:
  • 验证OIDC信任关系是否匹配GitHub组织/仓库
  • 检查IAM角色是否拥有ECR与ECS的正确权限
  • 确保GitHub Actions仓库拥有
    id-token: write
    权限
部署失败:
  • 检查CloudWatch Logs中的应用错误
  • 验证任务定义是否符合服务要求
  • 确保Fargate集群有足够的CPU/内存资源
  • 检查健康检查配置
ECR推送失败:
  • 验证仓库是否存在且权限配置正确
  • 检查镜像标签格式与注册表URL
  • 确保GitHub Actions运行器中Docker守护进程已启动
  • 验证镜像大小未超出ECR限制
CloudFormation回滚:
  • 在AWS控制台查看堆栈事件
  • 检查参数值是否符合资源约束
  • 验证IAM角色是否拥有
    cloudformation:UpdateStack
    权限
  • 为生产堆栈启用终止保护

Related Skills

相关技能

  • aws-cloudformation-ecs - Design and implement ECS cluster architecture
  • aws-sdk-java-v2-ecs - Programmatic ECS management with Java SDK
  • aws-cloudformation - Core CloudFormation patterns and best practices
  • aws-cloudformation-ecs - 设计并实现ECS集群架构
  • aws-sdk-java-v2-ecs - 使用Java SDK实现ECR编程式管理
  • aws-cloudformation - CloudFormation核心模式与最佳实践