Skip to content
Latchkey

How to Deploy a Container to Amazon ECS With GitHub Actions

Push the image to ECR, inject its tag into the task definition, then update the ECS service so it rolls out the new revision.

Use aws-actions/amazon-ecr-login to push the image, amazon-ecs-render-task-definition to swap the image into a task def JSON, then amazon-ecs-deploy-task-definition to register it and update the service.

Steps

  • Authenticate to AWS via OIDC and log in to ECR.
  • Build and push the image tagged with the commit SHA.
  • Render the new image into your task-definition.json.
  • Deploy the rendered task definition to the ECS service and wait for stability.

Workflow

.github/workflows/deploy.yml
permissions: { id-token: write, contents: read }
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/ecs-deploy
          aws-region: us-east-1
      - id: ecr
        uses: aws-actions/amazon-ecr-login@v2
      - run: |
          docker build -t $REG/app:$GITHUB_SHA .
          docker push $REG/app:$GITHUB_SHA
        env:
          REG: ${{ steps.ecr.outputs.registry }}
      - id: taskdef
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: app
          image: ${{ steps.ecr.outputs.registry }}/app:${{ github.sha }}
      - uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: ${{ steps.taskdef.outputs.task-definition }}
          service: app-service
          cluster: prod
          wait-for-service-stability: true

Common pitfalls

  • Reusing a mutable tag like latest means ECS may not pull a new image; tag with the commit SHA so each revision is distinct.
  • Without wait-for-service-stability: true the job is green before the rollout finishes, hiding failing health checks.
  • The task container-name in the render step must match a container in the task definition, or the action errors with "container not found".

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →