This workshop aims to provide an overview for basic ECS operation. For a full and more complete workshop, please check https://ecsworkshop.com/
AWS CLI: It can be installed here: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html
Docker: https://docs.docker.com/get-docker/
Use aws-azure-login cli or the provided credentials
AWS workshop: https://ecsworkshop.com/introduction/ecs_basics/
Internal Wiki:
git clone https://github.com/searchmetrics/ecs-workshop.git
cd ecs-workshop
Brief on ASG and Spot.io options
To create an ECR repository we can run the following command:
aws ecr create-repository --repository-name workshop-<name>
Replace with your name.
This will produce an output similar to this one:
{
"repository": {
"repositoryArn": "arn:aws:ecr:eu-west-1:123456789000:repository/workshop-mls",
"registryId": "123456789000",
"repositoryName": "workshop-mls",
"repositoryUri": "123456789000.dkr.ecr.eu-west-1.amazonaws.com/workshop-mls",
"createdAt": 1502712474.0,
"imageTagMutability": "MUTABLE",
"imageScanningConfiguration": {
"scanOnPush": false
}
}
}
Please take a note of the repositoryUri and registryId, in the case above is 123456789000.dkr.ecr.eu-west-1.amazonaws.com/workshop-mls and 123456789000.
Once we create the ECR repository, we can build an example image and push it to the new repository, but first, lets login to the AWS ECR:
aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin <registryId>.dkr.ecr.eu-west-1.amazonaws.com
Replace with the newly created repository Id After login, we can build the image:
docker build -t <repositoryUri> -f Dockerfile .
Replace with the newly created repository URI.
Once the build is done, we can push the image:
docker push <repositoryUri>
Replace with the newly created repository URI.
To create the task definition, first lets edit the file simple-task.json and replace the image value with our repositoryUri:
{
"containerDefinitions": [
{
"name": "nginx",
"image": "<repositoryUri>",
...
Once this is complete, we can create the task definition with the following command:
aws ecs register-task-definition --family workshop-<name> --cli-input-json file://simple-task.json
Replace with your name.
This will produce an output similar to this one:
{
"taskDefinition": {
"taskDefinitionArn": "arn:aws:ecs:eu-west-1:123456789000:task-definition/workshop-mls:1",
"containerDefinitions": [
{
"name": "nginx",
"image": "123456789000.dkr.ecr.eu-west-1.amazonaws.com/workshop-mls",
"cpu": 0,
"memory": 128,
"portMappings": [
{
"containerPort": 80,
"hostPort": 0,
"protocol": "tcp"
}
],
"essential": true,
"environment": [],
"mountPoints": [],
"volumesFrom": []
}
],
"family": "workshop-mls",
"revision": 1,
"volumes": [],
"status": "ACTIVE",
"placementConstraints": [],
"compatibilities": [
"EC2"
]
}
}
Please take a note of the taskDefinitionArn, in the case above is arn:aws:ecs:eu-west-1:123456789000:task-definition/workshop-mls:1.
Now, lets run the task definition as a simple task in our cluster:
aws ecs run-task --cluster ecs-workshop --count 1 --task-definition <taskDefinitionArn>
Now we can access the ECS cluster and check our task under the tasks tab by typing your name in the search bar. When you access the task information page, you can expand the container to view which host port the container is mapped and after enable access to that port, you can try to access the ip:port provided.
With this run, lets check the example with a environment variable.
This time, lets edit the file withvars-task.json, once again replace the image value with our repositoryUri and replace the value for the variable SMWORKSHOP with your name:
{
"containerDefinitions": [
{
"name": "nginx",
"image": "<repositoryUri>",
"cpu": 0,
"memory": 128,
"portMappings": [
{
"containerPort": 80,
"hostPort": 0,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "SMWORKSHOP",
"value": "<name>"
}
]
}
]
}
Then we can register our new task, get the new taskDefinitionArn and execute the run-task command again with the new file:
aws ecs register-task-definition --family workshop-<name> --cli-input-json file://simple-task.json
Note that the task arn have a number increment
Execute the run-task using the new revision.
aws ecs run-task --cluster ecs-workshop --count 1 --task-definition <taskDefinitionArn>
This time we will be able to see a new task and in its information page we can see our environment variable
Now lets create an ecs service to manage our task lifecycle.
First step, lets create the task:
aws ecs create-service --cluster ecs-workshop --desired-count 1 --service-name workshop-<name> --task-definition <taskDefinitionArn>
Here we can check and discuss the main differences from scheduling the container using Service x stand alone task.
In order to expose our services to the internet, we need to recreate them, but this time we will use a load balancer and direct traffic based on host-header.
First we need to create target group for our service:
aws elbv2 create-target-group --name workshop-<name> --protocol HTTP --port 80 --target-type instance --health-check-interval-seconds 10 --health-check-timeout-seconds 5 --healthy-threshold-count 2 --vpc-id <vpc_id>
vpc_id will be provided by the meeting host
This will generate an output like the following:
{
"TargetGroups": [
{
"TargetGroupArn": "arn:aws:elasticloadbalancing:eu-west-1:123456789000:targetgroup/workshop-mls2/15a9e0c1b1414df9",
"TargetGroupName": "workshop-mls",
"Protocol": "HTTP",
"Port": 80,
"VpcId": "vpc-123456789000",
"HealthCheckProtocol": "HTTP",
"HealthCheckPort": "traffic-port",
"HealthCheckEnabled": true,
"HealthCheckIntervalSeconds": 10,
"HealthCheckTimeoutSeconds": 5,
"HealthyThresholdCount": 2,
"UnhealthyThresholdCount": 2,
"HealthCheckPath": "/",
"Matcher": {
"HttpCode": "200"
},
"TargetType": "instance"
}
]
}
Keep note of the TargetGroupArn
Now lets create your listener rule which tells the Load balancer to forward traffic to the new target group. First lets edit the conditions-host.json and replace with your name:
[
{
"Field": "host-header",
"HostHeaderConfig": {
"Values": ["<REPLACE>.ecs.src.hm"]
}
}
]
Then we can create the listener rule by running the command below:
aws elbv2 create-rule --listener-arn <listener_arn> --priority <priority> --conditions file://conditions-host.json --actions Type=forward,TargetGroupArn=<TargetGroupArn>
listener_arn will be provided by the host
priority should be different among the participants
Replace with the one previously created
Once you have prepared the target group and the listener rule, we can recreate our service. First, lets delete the previous service:
aws ecs delete-service --cluster ecs-workshop --force --service workshop-<name>
Now lets recreate the service with loadbalancer support:
aws ecs create-service --cluster ecs-workshop --desired-count 1 --service-name workshop-<name> --task-definition <taskDefinitionArn> --load-balancers targetGroupArn=<TargetGroupArn>,containerName=nginx,containerPort=80
Replace with the one previously created
Now you can access your service at http://name.ecs.src.hm
This is a visual part where we use AWS SSM session manager through the ec2 console to connect to the instance.
To view logs, we have many options, from plain docker logs, to cloudwatch or datadog. Here we will discuss the possibilities and get logs from the instance access.
After access the instance using AWS SSM session manager, we can run the following commangs:
sudo docker ps | grep <name>
This will give you all runing containers with your name, where you can use one of the containers id to get logs:
sudo docker logs <container_id>
You can access the service url and generate some 404 requests http://name.ecs.src.hm/error, you will notice new events.
Lets go through the metrics that ECS offers