You can download this article in PDF format via the link below to support us.
Download the guide in PDF format turn off
This article is part 3 of part 4 of the guide to running Docker containers on AWS ECS. ECS stands for Elastic Container Service. It is a managed container service that can run docker containers. Although AWS also provides container management through Kubernetes (EKS), it also has its own proprietary solution (ECS).
The guide will cover:
- Create an ECS cluster.
- Set up the image registry (ECR) and push the docker image to the registry.
- Use task and service definitions to deploy containers to the cluster.
- Create a pipeline to update the services running on the ECS cluster.
This is part 1 and part 2:
Using ECS to run Docker containers on AWS-part 1
Run Docker container on AWS ECS-upload Docker image to ECR-part 2
Part 3 of this guide will cover “Deploying containers to clusters using task and service definitions.”
In this demo, we will use a simple hello-world image pushed from Docker Hub to the ECR registry. We will create a task and service definition and deploy it to the ECS cluster.
Requirements/prerequisites
- An AWS account.
- A user is created on the account, and the user has permission to provision resources on the account.
- Created a Route 53 hosted zone with your custom domain (it can be a public zone or a private zone according to user requirements).
- Import or generate your site certificate to ACM (Amazon Certificate Manager).
- Set up an AWS ECS cluster
- Upload your Docker image to the ECR registry.
Create AWS Application Load Balancer and target group
ALB (Application Load Balancer) is an AWS-hosted load balancer that can route traffic according to the OSI layer 7 protocol. We will use a load balancer to expose our world service endpoints. We have provided an AWS guide on creating an application load balancer on the link below:
- Use CloudFormation to create and configure AWS Application Load Balancer
Therefore, I will not introduce ALB too much. We will use the CloudFormation template below to create and configure our ECS ALB. The template will be provided;
- ALB (application load balancer).
- ALB security group.
- Target group.
- ALB listener and listener rules.
N/B: If readers/users wish to expose their services internally, they should create a load balancer on a private subnet. Otherwise, the load balancer should face the Internet and be created in a public subnet. For high-availability load balancers, users should configure them in different subnets in different availability zones.
AWSTemplateFormatVersion: "2010-09-09"
Description: "Create ALB, Target Groups and ALB security group"
Parameters:
VPC:
Type: String
Description: The vpc to launch the service
Default: vpc-ID
PublicSubnet1:
Type: String
Description: The subnet where to launch the service
Default: subnet-ID
PublicSubnet2:
Type: String
Description: the subnet where to Launch the service
Default: subnet-ID
Resources:
ALBSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: "security group for ALB"
GroupName: "test-prod-ALB-SG"
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Environment"
Value: "test"
-
Key: "Name"
Value: "test-ALB-SG"
VpcId: !Ref VPC
SecurityGroupIngress:
-
CidrIp: "0.0.0.0/0"
FromPort: 80
IpProtocol: "tcp"
ToPort: 80
-
CidrIp: "0.0.0.0/0"
FromPort: 443
IpProtocol: "tcp"
ToPort: 443
ApplicationLoadBalancer:
Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
Properties:
Name: "test-Application-Load-Balancer"
Scheme: "internet-facing"
Type: "application"
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
SecurityGroups:
- !Ref ALBSecurityGroup
IpAddressType: "ipv4"
LoadBalancerAttributes:
-
Key: "access_logs.s3.enabled"
Value: "true"
-
Key: "idle_timeout.timeout_seconds"
Value: "60"
-
Key: "deletion_protection.enabled"
Value: "false"
-
Key: "routing.http2.enabled"
Value: "true"
-
Key: "routing.http.drop_invalid_header_fields.enabled"
Value: "false"
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Environment"
Value: "test"
-
Key: "Name"
Value: "test-Application-Load-Balancer"
HTTPSListener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 443
Protocol: "HTTPS"
SslPolicy: "ELBSecurityPolicy-2016-08"
Certificates:
-
CertificateArn: arn:aws:acm:eu-central-1:*************:certificate/************
DefaultActions:
-
Order: 1
TargetGroupArn: !Ref TestTargetGroup
Type: "forward"
HTTPListener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: "HTTP"
DefaultActions:
-
Order: 1
RedirectConfig:
Protocol: "HTTPS"
Port: "443"
Host: "#{host}"
Path: "/#{path}"
Query: "#{query}"
StatusCode: "HTTP_301"
Type: "redirect"
TestTargetGroup:
Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
Properties:
HealthCheckIntervalSeconds: 30
HealthCheckPath: "/"
Port: 80
Protocol: "HTTP"
HealthCheckPort: "traffic-port"
HealthCheckProtocol: "HTTP"
HealthCheckTimeoutSeconds: 5
UnhealthyThresholdCount: 2
TargetType: "ip"
Matcher:
HttpCode: "200"
HealthyThresholdCount: 5
VpcId: !Ref VPC
Name: "target-group-1"
HealthCheckEnabled: true
TargetGroupAttributes:
-
Key: "stickiness.enabled"
Value: "false"
-
Key: "deregistration_delay.timeout_seconds"
Value: "300"
-
Key: "stickiness.type"
Value: "lb_cookie"
-
Key: "stickiness.lb_cookie.duration_seconds"
Value: "86400"
-
Key: "slow_start.duration_seconds"
Value: "0"
-
Key: "load_balancing.algorithm.type"
Value: "round_robin"
TestListenerRule1:
Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
Properties:
Priority: "1"
ListenerArn: !Ref HTTPSListener
Conditions:
-
Field: "host-header"
Values:
- "test1.helloworld.com"
Actions:
-
Type: "forward"
TargetGroupArn: !Ref TestTargetGroup
Order: 1
ForwardConfig:
TargetGroups:
-
TargetGroupArn: !Ref TestTargetGroup
Weight: 1
TargetGroupStickinessConfig:
Enabled: false
Outputs:
ALB:
Description: The created loadbalancer
Value: !Ref ApplicationLoadBalancer
TargetGroup:
Description: The created TargetGroup
Value: !Ref TestTargetGroup
LoadBalancerSecurityGroup:
Description: the securty group for the ALB
Value: !Ref ALBSecurityGroup
Make sure to replace the certificate with the generated certificate ARN under the HTTPS listener. Similarly, according to the listener rules, we should replace the host header with the record set created by the user on the Route 53 hosted zone.
The tags and names of resources should also be customized according to user requirements.
ECS task and service definition
The ECS task definition defines the requirements of Docker containers.It defines the image to be used, CPU and memory requirements, etc.
The ECS service definition defines how to run the application/service.It defines the startup type, the cluster in which the service will run, the target group used for ALB, the task definition to be used, etc.
Create ECS task execution role
N/B: The task execution role is usually created on the AWS account.One can search for it ecsTaskExecutionRole
. If you haven’t created one on your account, please create one using the CloudFormation template below.
AWSTemplateFormatVersion: "2010-09-09"
Description: "Template to create ECS Task Execution Role"
Resources:
ECSTaskExecutionRole:
Type: 'AWS::IAM::Role'
Properties:
Description: The ECS task execution Role
RoleName: AWSECSTaskExecutionRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: "AWSECSTaskExecutionRole"
Outputs:
IAMRole:
Description: the role created
Value: !Ref ECSTaskExecutionRole
Export:
Name: !Sub "${AWS::StackName}-rolename"
Create ECS tasks and service definitions
Use the following template to create task and service definitions.
N/B: This template creates tasks and service definitions for the Fargate cluster. In addition, for the task role and task execution role arn, please use arn for the role created above; if it exists, use arn for the following tasks: ecsTaskExecutionRole .
To create a task and service definition for an EC2 cluster, replace the LaunchType on the “Service Definition” with EC2. In terms of task definition, EC2 can work in any network mode; awsvpc, bridge or host. Fargate is only available in awsvpc mode.
AWSTemplateFormatVersion: "2010-09-09"
Description: "hello-world task and service definition"
Parameters:
VPC:
Type: String
Description: The vpc to launch the service
Default: vpc-ID
Subnet1:
Type: String
Description: The subnet where to launch the service
Default: subnet-ID
Subnet2:
Type: String
Description: The subnet where to launch the service
Default: subnet-ID
Resources:
CWLoggroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: ecs-hello-world-Loggroup
TaskDefinition:
Type: "AWS::ECS::TaskDefinition"
Properties:
ContainerDefinitions:
-
Essential: true
Image: 429758582529.dkr.ecr.eu-central-1.amazonaws.com/hello-world:latest
LogConfiguration:
LogDriver: "awslogs"
Options:
awslogs-group: !Ref CWLoggroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: "ecs"
Name: "Hello_World"
PortMappings:
-
ContainerPort: 80
HostPort: 80
Protocol: "tcp"
Family: "Hello_World"
TaskRoleArn: arn:aws:iam::429758582529:role/AWSECSTaskExecutionRole
ExecutionRoleArn: arn:aws:iam::429758582529:role/AWSECSTaskExecutionRole
NetworkMode: "awsvpc"
RequiresCompatibilities:
- "FARGATE"
Cpu: "256"
Memory: "512"
ServiceDefinition:
Type: "AWS::ECS::Service"
Properties:
ServiceName: "hello-world"
Cluster: "arn:aws:ecs:eu-central-1:429758582529:cluster/eu-central-1-test-ECS-Fargate-Cluster"
LoadBalancers:
-
TargetGroupArn: "arn:aws:elasticloadbalancing:eu-central-1:************:targetgroup/test-fargate-hello/*********"
ContainerName: "Hello_World"
ContainerPort: 80
DesiredCount: 1
LaunchType: "FARGATE"
PlatformVersion: "1.4.0"
TaskDefinition: !Ref TaskDefinition
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: "ENABLED"
SecurityGroups:
- "sg-ID"
Subnets:
- !Ref Subnet1
- !Ref Subnet2
HealthCheckGracePeriodSeconds: 300
SchedulingStrategy: "REPLICA"
Outputs:
HelloTaskDefinition:
Description: The created name of the ECS TaskDefinition
Value: !Ref TaskDefinition
HelloService:
Description: The ECS service
Value: !Ref Service
N/B: CloudFormation templates should be customized according to user requirements. We can customize:
- The name of the resource to be provisioned.
- For the container definition, we can change the image name, port mapping, etc.
- The user/reader should also replace the cluster and target group arn to reflect his/her own value.
After completion, you should follow the steps below to run the service on the ECS cluster.ECS cluster with running tasks and services
Now you can access the service through the created domain name.
Important link
- Use CloudFormation to create and configure AWS Application Load Balancer
- AWS ALB file
- AWS ECS file
Other AWS guidelines:
- How to mount AWS EFS file system on EC2 instance
- Create an AWS S3 upload and list object policy that does not perform delete operations
- How to set up AWS VPC network using CloudFormation
Happy Building! ! !
You can download this article in PDF format via the link below to support us.
Download the guide in PDF format turn off