Introduction#

This note goes through some concepts

  • Fargate Task
  • ECS Service
  • ECS Cluster
  • ALB and ECS Service
  • Flask web
  • GitHub

aws_devops-ecs drawio

Create an ECS Cluster#

// ecs cluster
const cluster = new aws_ecs.Cluster(this, 'EcsClusterFlaskApp', {
vpc: vpc,
clusterName: 'EcsClusterFlaskApp',
containerInsights: true,
enableFargateCapacityProviders: true
})

Create an ECS Task Definition#

// ecs task definition
const task = new aws_ecs.FargateTaskDefinition(this, 'FlaskTaskDefinition', {
family: 'latest',
cpu: 2048,
memoryLimitMiB: 4096,
runtimePlatform: {
operatingSystemFamily: aws_ecs.OperatingSystemFamily.LINUX,
cpuArchitecture: aws_ecs.CpuArchitecture.X86_64
}
})

Create an ECS Container#

// container
const container = task.addContainer('FlaskAppContainer', {
containerName: 'FlaskAppContainer',
memoryLimitMiB: 4096,
memoryReservationMiB: 4096,
stopTimeout: Duration.seconds(120),
startTimeout: Duration.seconds(120),
environment: {
FHR_ENV: 'DEPLOY'
},
image: aws_ecs.ContainerImage.fromEcrRepository(
aws_ecr.Repository.fromRepositoryName(
this,
'FlaskAppRepository',
'flask-app-demo'
)
),
portMappings: [{ containerPort: 8080 }]
})

Create a ECS Service#

// service
const service = new aws_ecs.FargateService(this, 'FlaskService', {
vpcSubnets: {
subnetType: aws_ec2.SubnetType.PUBLIC
},
assignPublicIp: true,
cluster: cluster,
taskDefinition: task,
desiredCount: 2,
capacityProviderStrategies: [
{
capacityProvider: 'FARGATE',
weight: 1
},
{
capacityProvider: 'FARGATE_SPOT',
weight: 0
}
]
})

Add an Application Load Balancer#

// application load balancer
const alb = new aws_elasticloadbalancingv2.ApplicationLoadBalancer(
this,
'AlbForEcs',
{
loadBalancerName: 'AlbForEcsDemo',
vpc: vpc,
internetFacing: true
}
)
// add listener
const listener = alb.addListener('Listener', {
port: 80,
open: true,
protocol: aws_elasticloadbalancingv2.ApplicationProtocol.HTTP
})
// add target
listener.addTargets('EcsService', {
port: 8080,
targets: [
service.loadBalancerTarget({
containerName: 'FlaskAppContainer',
containerPort: 8080,
protocol: aws_ecs.Protocol.TCP
})
],
healthCheck: {
timeout: Duration.seconds(10)
}
})

scaling

// scaling on cpu utilization
const scaling = service.autoScaleTaskCount({
maxCapacity: 4,
minCapacity: 1
})
scaling.scaleOnMemoryUtilization('CpuUtilization', {
targetUtilizationPercent: 50
})

Docker file#

FROM python:3.7-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
COPY . /app
EXPOSE 8080
ENTRYPOINT [ "python" ]
CMD [ "app.py" ]

Some Docker Commands#

docker build -t flask-app .

and run

docker run -d -p 3000:3000 flask-app:latest

list docker running

docker ps

stop all running containers

docker kill $(docker ps -q)

delete all docker images

docker system prune -a

docker ecr log in

aws ecr get-login-password --region ap-southeast-1 | docker login --username AWS --password-stdin ACCOUNT_ID.dkr.ecr.ap-southeast-1.amazonaws.com

tag

sudo docker tag b3bab24448e4 ACCOUNT_ID.dkr.ecr.ap-southeast-1.amazonaws.com/flask-app-demo:latest

push

sudo docker push ACCOUNT_ID.dkr.ecr.ap-southeast-1.amazonaws.com/flask-app-demo:latest

Troubleshooting#

#! /bin/bash
cluster=clustername
capacityprovider=capacityprovidername
services=$(aws ecs list-services --cluster ${cluster} | jq --raw-output '.serviceArns[]')
aws ecs describe-services \
--cluster ${cluster} \
--services ${services} \
| jq -r --arg capacityprovider "${capacityprovider}" \
'.services[] | select(.capacityProviderStrategy[]?.capacityProvider == $capacityprovider) | .serviceName'