DEV Community

Cover image for Deploy to AWS ECS with Github actions 🚀
Iacovos Constantinou
Iacovos Constantinou

Posted on • Edited on • Originally published at softius.net

Deploy to AWS ECS with Github actions 🚀

Consistency and automations are key to every project. In this article we will be looking on how we can automate deployments to AWS ECS.

It is a very simple solution which requires almost zero coding. Yet, it's quite powerful as it allows you to deploy automatically every time there is a change in your code.

We will be using Github actions to achieve that. In particular, we will cover the following steps:

  1. Build and deploy a new docker image to ECR
  2. Retrieve and update the task definition with the new image tag
  3. Update the corresponding services and force redeployment

Get started

First, you will need to register your AWS credentials as Secrets in your Github project. Assuming that you create two new Secrets AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, you should be able to configure AWS in your Github action as per below:

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-2
Enter fullscreen mode Exit fullscreen mode

The above registers AWS credentials so that they are available for the next action.

Deploy docker image to ECR

Next we need to build and deploy our image. Most likely, this will be a time consuming action, especially if you have a large number of third party dependencies.

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1
    - name: Build, tag, and push image to Amazon ECR
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: your-ecr-repot
        IMAGE_TAG: ${{ github.sha }}
      run: |
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
Enter fullscreen mode Exit fullscreen mode

There a couple of things that you will need to adjust here. First you will need to provide the repository to deploy to for env ECR_REPOSITORY.

Then you might need to change how the IMAGE_TAG should look like. By default it will include only the commit SHA. Personally, I prefer to include also the date the image was build.

Update ECS task definition and Deploy!

Once the image is build and pushed to ECR, it is time to update the task definition and specify the new image tag. Depending on your setup you may have one or more tasks for the same image tag. In that case, you will need to repeat these steps.

Ideally, you should have the the task definition as part of your code base. In the following examples, we are assuming that the file is called task-definition.json

In case you don't, you can retrieve the task definition dynamically as per below. However, you might need to remove some parts of the definition, before pushing back to AWS - in that case jq is quite helpful.

    - name: Download task definition
      run: |
        aws ecs describe-task-definition --task-definition my-task-definition-family --query taskDefinition > task-definition.json
Enter fullscreen mode Exit fullscreen mode

The following actions specify the new image tag in our task definition and force a deployment to our service. The last option wait-for-service-stability is important since it ensures that the service will reach a stable stage before proceeding further.

    - name: Fill in the new image ID in the Amazon ECS task definition
      id: task-def
      uses: aws-actions/amazon-ecs-render-task-definition@v1
      with:
        task-definition: task-definition.json
        container-name: my-container
        image: ${{ steps.build-image.outputs.image }}

    - name: Deploy Amazon ECS task definition
      uses: aws-actions/amazon-ecs-deploy-task-definition@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: my-service
        cluster: my-cluster
        wait-for-service-stability: true
Enter fullscreen mode Exit fullscreen mode

Similar to the previous actions there a few things that you will need to adjust here. Replace my-container, my-service and my-cluster with your setup details.

Conclusion

Having automated deployments to ECS is quite easy with Github actions. Yet, it's quite powerful as it allows you to deploy automatically every time there is a change in your code.

You can also use the same approach to deploy from any branch or even deploy manually, if needed.

Make sure to follow me on dev.to, Medium or Twitter to read more about PHP, Docker and other dev topics.

Photo by SpaceX on Unsplash

Top comments (4)

Collapse
 
sergsoares profile image
Sergio Soares

Really useful and simple, thinking in substitute code build/code deploy for that alternative.

I only will search more about docker cache in GitHub Actions to avoid slow (and expensive as minutes usage)

Collapse
 
iacons profile image
Iacovos Constantinou

@sergsoares nice point! Fortunately, there is an action even for that :)

One more thing to have in mind is to avoid concurrent deployments, as this might lead to unexpected results. You can control whether concurrent deployments are allowed and if needed you can cancel in progress deployments. More details here docs.github.com/en/actions/learn-g...

Collapse
 
adamdaniel profile image
Adam Daniel

how should be the best approach to kill the old task definition version, because the new is being deployed but the old one persists, and then GitHub actions get stuck in this step until I stop the old TD

Collapse
 
fnaquira profile image
Favio Náquira

can you add the whole code?