This note demonstrates how to host a Docker image as a container in Amazon Elastic Container Service (Amazon ECS). Per AWS Docs, Amazon ECS is a fully managed container orchestration service that helps you easily deploy, manage, and scale containerized applications. Deploying a service into Amazon ECS can be divided into three separate use cases: 1. Provision of the underlying infrastructure to host an Amazon ECS service. 2. Push a Docker image to Amazon Elastic Container Registry (Amazon ECR). 3. Create a service/task from the Docker image and host it on Amazon ECS.
Before a container can be hosted in an Amazon ECS service and the Docker image can be uploaded into Amazon ECR, you must provision specific AWS cloud services. These are the underlying infrastructure components (mentioned in use case 1 above), such as Amazon Virtual Private Cloud, Amazon ECR, Amazon ECS Cluster, load balancer, target group, and listener. These Amazon cloud services are prerequisites and must be provisioned before application development. I have covered the details of provisioning these resources in a separate post: Create Infrastructure to Host an Amazon ECS Service Using Terraform.
After provisioning the necessary AWS cloud services, the second use case is to create a Docker image and push it into Amazon ECR. I have covered the details of this process in another post: Push Docker Image to Amazon ECR Using GitHub Actions.
Finally, the last use case belongs to the application development process, in which an Amazon ECS service is created from the Docker image stored in Amazon ECR. I will cover this use case in this note. This use case can be divided into a) The Terraform code to provision the required AWS cloud resources and b) The GitHub Actions workflow to deploy the Terraform code and create the Amazon ECS service.
I will first cover the AWS services provisioning, followed by the GitHub Actions workflow.
Use-Case 1: Provision AWS Cloud Services Apart from the AWS cloud resources provisioned under the infrastructure section (covered in use case 1), there are four more resources required for the Amazon ECS service: 1. ECS execution role 2. ECS task role 3. ECS task definition 4. ECS service
Optionally, the two IAM roles (task and execution roles) could also belong to the infrastructure stack.
Let’s review these resources one by one. To follow along, you can access the deploy
folder in my GitHub repository: kunduso/add-aws-ecr-ecs-fargate. Please note that the branch name = create-ecs-service
.
Provision the ECS roles:
There are two roles, the ECS execution role and the ECS task role. The task execution role must have permission to create the ECS service. The below resource block creates the AWS IAM role that can be assumed by the "ecs-tasks.amazonaws.com"
service.
The below IAM role policy attachment resource attaches the role to the AWS-managed policy of
arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
.
The managed policy has the necessary permissions to other AWS service resources to run Amazon ECS tasks.
The ECS task role is attached to the tasks running in the ECS service. If the task requires permission to access AWS Secrets Manager secrets, write to an Amazon S3 bucket, CloudWatch logs, DynamoDB, or other resources, it requires the necessary IAM permissions.
In this use case, the task does not communicate with any other AWS resource and, hence, does not have a permission policy attached.
Update: A custom IAM policy was attached to the IAM role after the use case on accessing secure credentials stored in AWS Secrets Manager from the AWS Fargate task was added. However, for this use case, no custom IAM permission policy is required.
Provision the ECS task definition:
The ECS task definition is the blueprint of the ECS service. It defines the Docker image, CPU and memory requirements, networking configuration, and other settings for the tasks in the service.
To access all the properties in an Amazon ECS task definition template, choose ECS-task-definition-template, and for a detailed description of the properties, choose Amazon-ECS-task-definition-parameters.
Provision the ECS service:
The ECS service defines the desired count of tasks, scaling policies, load balancing configurations, and other settings for running and managing the tasks.
That brings us to the end of all the Terraform-managed AWS cloud resources.
Use-Case 2: Update GitHub Actions Workflow with Deploy Job
This step adds a new job (deploy
) to the existing GitHub Actions workflow (.github/workflows/app-ci-cd.yml
) stored in the repository. The first job (build
) creates and pushes a Docker image to the Amazon ECR repository. The second job (deploy
) runs the Terraform code to deploy the ECS service.
To authenticate with AWS from your GitHub Actions workflow, you’ll need to configure AWS credentials. Follow the steps outlined in [this detailed guide] to set up the required AWS credentials and store them as a GitHub repository secret. I completed that while setting up the first job -build
.
Here is the overview of the second job in the workflow:
1. Utilizing the needs
property: The deploy
job must only run, if the previous build
job was successful. That is managed by the needs: build
value in the deploy
job.
2. Read the inputs: The first job’s output is the Docker image tag, which is the input for the second job. This image tag is an input to the Amazon ECS task definition. The
image_tag
is a variable in the Terraform code for the Amazon ECS task definition resource, and no default value is configured for that. Hence, the new Docker image tag must be passed to the ECS task definition; otherwise, the provisioning process will fail.
3. Read and display the Tag name: This step helps the development team during debugging in case of a deployment failure. It will provide information regarding the Docker image used to create the Amazon ECS service.
4. Authenticate to AWS Cloud: This step uses the aws-actions/configure-aws-credentials action to configure the AWS credentials required for authenticating with AWS services. The action retrieves the IAM_ROLE from the GitHub secrets you set up earlier.
5. Setup Terraform and Infracost: You can read about this at - How to setup Terraform and Infracost in GitHub Actions.
6. Condition for Terraform Apply: This workflow is configured to run with each check-in to the app and deploy folders, irrespective of which branch the developers are checking-in code. The
terraform apply
step deploys the Amazon ECS service and hence with the condition in place, only the code that belongs to main
branch can be deployed. The only way to commit to the main
branch is via pull request, which must pass through a review.
After the service is deployed, log into your AWS account, get the load balancer DNS, paste it into your favorite browser, and then enter the port number, which is
8080
. You’ll see your Docker container live and serving traffic.
If you keep refreshing, you will see the private IP of the two containers in the message.
There are a few salient features to this architecture that you must understand: 1. Infrastructure as Code (IaC): Terraform allows you to maintain and version control your infrastructure configuration, enabling consistent and repeatable deployments. 2. Continuous Integration and Continuous Deployment (CI/CD): The GitHub Actions workflow automates the build, scan, and deployment processes, ensuring a smooth and efficient delivery pipeline. 3. Scalability and High Availability: Amazon ECS allows you to scale your containerized applications horizontally and deploy them across multiple Availability Zones for high availability. 4. Separation of Concerns: By separating infrastructure provisioning, Docker image management, and application deployment, you can maintain a modular and maintainable architecture. 5. Immutable Infrastructure: Deploying new versions of your application as immutable Docker images can ensure consistency and reliability across deployments.
Using these three notes, you should have understood how to manage your containerized applications with Amazon ECR and ECS. If you have any questions or suggestions, please feel free to reach out via the comments.