Amazon ECS notes
These are my notes for creating a Docker image, pushing it to Amazon ECR (Elastic Container Registry), and deploying it to Amazon ECS (Elastic Container Service) using AWS Fargate (serverless for containers) using command line tools.
Create docker image on local machine ¶
install docker (macOS)
brew install homebrew/cask/dockercreate directory
mkdir /tmp/my-project cd /tmp/my-projectcreate
/tmp/my-project/Dockerfile:FROM python:3.9-alpine3.13 WORKDIR /app RUN echo 'Hello' > ./index.html EXPOSE 80 CMD ["python", "-m", "http.server", "80"]create Docker image
docker build -t my-image .test running the Docker image locally
docker run -p 80:80 my-imagego to http://localhost in the browser and see the text "Hello"
Install and configure AWS command line tools ¶
install AWS command line tools
brew install awsclirun
aws configureand enter:- AWS Access Key ID
- AWS Secret Access Key
This creates the file
~/.aws/credentials
Create ECR repository and push image to it ¶
From https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html#use-ecr
create an Amazon ECR repository using
aws ecr create-repositoryaws ecr create-repository --repository-name my-repository --region us-east-1output:
{ "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:AAAAAAAAAAAA:repository/my-repository", "registryId": "AAAAAAAAAAAA", "repositoryName": "my-repository", "repositoryUri": "AAAAAAAAAAAA.dkr.ecr.us-east-1.amazonaws.com/my-repository", "createdAt": "2021-03-17T10:48:18-07:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": false }, "encryptionConfiguration": { "encryptionType": "AES256" } } }Take note of the "registryId" and use it in place of "AAAAAAAAAAAA" below.
tag the docker image with the
repositoryUridocker tag my-image AAAAAAAAAAAA.dkr.ecr.us-east-1.amazonaws.com/my-repositorylog in to the Amazon ECR registry using
aws ecr get-login-passwordaws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin AAAAAAAAAAAA.dkr.ecr.us-east-1.amazonaws.compush the docker image to the Amazon ECR repository
docker push AAAAAAAAAAAA.dkr.ecr.us-east-1.amazonaws.com/my-repositorysee the image in AWS console https://console.aws.amazon.com/ecr/repositories?region=us-east-1
Install ECS command line tools¶
- install
ecs-cli. Note there isecs-cliin addition toaws ecstools. The reason is probably similar to why some services are named "Amazon Service" and some are named "AWS Service". (It seems likeecs-cliprovides higher level commands.)brew install amazon-ecs-cli
Create Amazon ECS Fargate cluster ¶
From https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-cli-tutorial-fargate.html
- create a cluster using
ecs-cli up
output:ecs-cli up --cluster my-cluster --launch-type FARGATE --region us-east-1
Take note of the VPC (virtual private cloud), and two subnet IDs to use later. See the cluster in the AWS console UI: https://console.aws.amazon.com/ecs/home?region=us-east-1#/clustersINFO[0001] Created cluster cluster=my-cluster region=us-east-1 INFO[0002] Waiting for your cluster resources to be created... INFO[0002] Cloudformation stack status stackStatus=CREATE_IN_PROGRESS VPC created: vpc-BBBBBBBBBBBBBBBBB Subnet created: subnet-CCCCCCCCCCCCCCCCC Subnet created: subnet-DDDDDDDDDDDDDDDDD Cluster creation succeeded.
Gather parameters required to deploy to ECS cluster ¶
From https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-cli-tutorial-fargate.html
Create task execution IAM role¶
create a file
/tmp/my-project/task-execution-assume-role.json{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }create the task execution role using
aws iam create-roleaws iam create-role --role-name my-task-execution-role --assume-role-policy-document file:///tmp/my-project/task-execution-assume-role.json --region us-east-1attach the task execution role policy using
aws iam attach-role-policyaws iam attach-role-policy --role-name my-task-execution-role --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy --region us-east-1
Get security group ID¶
get the default security group ID for the virtual private cloud (VPC) created when creating the ECS cluster using
aws ec2 describe-security-groups. Replace "vpc-BBBBBBBBBBBBBBBBB" with your VPC IDaws ec2 describe-security-groups --filters Name=vpc-id,Values=vpc-BBBBBBBBBBBBBBBBB --region us-east-1output:
{ "SecurityGroups": [ { "Description": "default VPC security group", "GroupName": "default", "IpPermissions": [ { "IpProtocol": "-1", "IpRanges": [], "Ipv6Ranges": [], "PrefixListIds": [], "UserIdGroupPairs": [ { "GroupId": "sg-EEEEEEEEEEEEEEEEE", "UserId": "AAAAAAAAAAAA" } ] } ], "OwnerId": "AAAAAAAAAAAA", "GroupId": "sg-EEEEEEEEEEEEEEEEE", "IpPermissionsEgress": [ { "IpProtocol": "-1", "IpRanges": [ { "CidrIp": "0.0.0.0/0" } ], "Ipv6Ranges": [], "PrefixListIds": [], "UserIdGroupPairs": [] } ], "VpcId": "vpc-BBBBBBBBBBBBBBBBB" } ] }Take note of the "GroupId" to be used later
Deploy to Amazon ECS cluster¶
From https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-cli-tutorial-fargate.html
create
/tmp/my-project/ecs-params.ymlreplacing "subnet-CCCCCCCCCCCCCCCCC", "subnet-DDDDDDDDDDDDDDDDD", and "sg-EEEEEEEEEEEEEEEEE" with appropriate IDs from above. ECS Parameters docsversion: 1 task_definition: task_execution_role: my-task-execution-role ecs_network_mode: awsvpc task_size: mem_limit: 0.5GB cpu_limit: 256 run_params: network_configuration: awsvpc_configuration: subnets: - "subnet-CCCCCCCCCCCCCCCCC" - "subnet-DDDDDDDDDDDDDDDDD" security_groups: - "sg-EEEEEEEEEEEEEEEEE" assign_public_ip: ENABLEDcreate
/tmp/my-project/docker-compose.ymlreplacing AAAAAAAAAAAA with the registryId:version: '3' services: web: image: 'AAAAAAAAAAAA.dkr.ecr.us-east-1.amazonaws.com/my-repository' ports: - '80:80'deploy to the ECS cluster using
ecs-cli compose service up. This creates a task definition and service. This uses thedocker-compose.ymlfile in the current directory.ecs-cli compose --cluster my-cluster --project-name my-project --ecs-params ecs-params.yml --region us-east-1 service up --launch-type FARGATEsee the service in the web UI: https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters/my-cluster/services
Hit the server in the browser¶
configure security group to allow inbound access on port 80 using
aws ec2 authorize-security-group-ingressaws ec2 authorize-security-group-ingress --group-id sg-EEEEEEEEEEEEEEEEE --protocol tcp --port 80 --cidr 0.0.0.0/0 --region us-east-1get the IP address using
ecs-cli compose service psecs-cli compose --cluster my-cluster --project-name my-project --region us-east-1 service psoutput:
Name State Ports TaskDefinition Health my-cluster/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/web RUNNING FF.FF.FF.FF:80->80/tcp my-project:1 UNKNOWNTake note of the IP address under "Ports"
visit in the browser: http://FF.FF.FF.FF replacing "FF.FF.FF.FF" with your IP address
Destroy¶
delete the ECS service using
ecs-cli compose service downecs-cli compose --cluster my-cluster --project-name my-project --region us-east-1 service downdelete the ECS cluster using
ecs-cli downecs-cli down --force --cluster my-cluster --region us-east-1delete the ECR repository using
aws ecr delete-repositoryaws ecr delete-repository --repository-name my-repository --region us-east-1 --force
