The Pragmatic Programmer

Appian, Pega, Java, DevSecOps, Quality Engineering

Lab 3: Deploying an Application with Amazon ECS on Fargate

Deploy a web-based application as a Docker container image. After verifying that the image is successfully created, push it to Amazon Elastic Container Registry (Amazon ECR). Then, launch an Amazon Elastic Container Service (Amazon ECS) cluster and create an AWS Fargate profile. Finally, deploy the application to a Fargate cluster.

docker -v && git --version

Docker version 20.10.13, build a224086
git version 2.37.1
pwd

/home/ssm-user
# or
/usr/bin
cd ~
git clone https://github.com/gabrielecirulli/2048
ls -l | grep 2048

drwxr-xr-x 6 ssm-user ssm-user 200 Jul 22 23:57 2048

Task 2 : Containerize the Application

cd 2048
vim Dockerfile
FROM nginx:latest

COPY . /usr/share/nginx/html

EXPOSE 80

Task 3 : Build the Web2048 Container

cd ~/2048
ls -l

-rw-r--r-- 1 ssm-user ssm-user 1970 Jul 22 22:12 CONTRIBUTING.md
-rw-r--r-- 1 ssm-user ssm-user   59 Jul 22 23:00 Dockerfile
-rw-r--r-- 1 ssm-user ssm-user 1083 Jul 22 22:12 LICENSE.txt
-rw-r--r-- 1 ssm-user ssm-user 2280 Jul 22 22:12 README.md
-rw-r--r-- 1 ssm-user ssm-user  300 Jul 22 22:12 Rakefile
-rw-r--r-- 1 ssm-user ssm-user 4286 Jul 22 22:12 favicon.ico
-rw-r--r-- 1 ssm-user ssm-user 3988 Jul 22 22:12 index.html
drwxr-xr-x 2 ssm-user ssm-user  252 Jul 22 22:12 js
drwxr-xr-x 2 ssm-user ssm-user  125 Jul 22 22:12 meta
drwxr-xr-x 3 ssm-user ssm-user   72 Jul 22 22:12 style
sudo usermod -aG docker ssm-user
newgrp docker
docker images
docker build -t web2048 .
Sending build context to Docker daemon   1.36MB
Step 1/3 : FROM nginx:latest
latest: Pulling from library/nginx
461246efe0a7: Pull complete
060bfa6be22e: Pull complete
b34d5ba6fa9e: Pull complete
8128ac56c745: Pull complete
44d36245a8c9: Pull complete
ebcc2cc821e6: Pull complete
Digest: sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7
Status: Downloaded newer image for nginx:latest
 ---> 670dcc86b69d
Step 2/3 : COPY . /usr/share/nginx/html
 ---> af91f0e53954
Step 3/3 : EXPOSE 80
 ---> Running in c854197142b7
 ...

...
Successfully built 7de26addeed8
docker images

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
web2048      latest    7de26addeed8   24 minutes ago   143MB
nginx        latest    670dcc86b69d   3 days ago       142MB
docker run -d -it -p 80:80 web2048
history | grep container
ctrl + r

(reverse-i-search)`container': docker container ls

# press enter and the "list containers" command runs again.

[ssm-user@ip-10-0-0-55 2048]$ docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                               NAMES
0e5c8fe77af7   web2048   "/docker-entrypoint.…"   4 minutes ago   Up 4 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp   elated_boyd


docker container ls

curl http://169.254.169.254/latest/meta-data/public-ipv4 -w "\n"

docker stop CONTAINER ID

Task 4 : Create an Amazon ECR Repository and Push the Docker Image

docker images

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
web2048      latest    df0b3b5dd073   2 hours ago   143MB
nginx        latest    670dcc86b69d   3 days ago    142MB
aws configure


AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name []: <YOUR_REGION>
Default output format [json]: json
aws ecr create-repository --repository-name web2048


{
    "repository": {
        "repositoryUri": "294373654843.dkr.ecr.us-east-1.amazonaws.com/web2048",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        },
        "registryId": "294373654843",
        "imageTagMutability": "MUTABLE",
        "repositoryArn": "arn:aws:ecr:us-east-1:294373654843:repository/web2048",
        "repositoryName": "web2048",
        "createdAt": 1658766018.0
    }
}
aws ecr describe-repositories --query 'repositories[].[repositoryName, repositoryUri]' --output table

---------------------------------------------------------------------
|                       DescribeRepositories                        |
+---------+---------------------------------------------------------+
|  web2048|  294373654843.dkr.ecr.us-east-1.amazonaws.com/web2048   |
+---------+---------------------------------------------------------+
export REPOSITORY_URI=$(aws ecr describe-repositories --query 'repositories[].[repositoryUri]' --output text)
echo ${REPOSITORY_URI}
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)

export AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')

aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
docker tag web2048:latest ${REPOSITORY_URI}:latest
docker images

REPOSITORY                                             TAG       IMAGE ID       CREATED         SIZE
 294373654843.dkr.ecr.us-east-1.amazonaws.com/web2048   latest    07a9581ba9e6   6 minutes ago   143MB
 web2048                                                latest    07a9581ba9e6   6 minutes ago   143MB
 nginx                                                  latest    670dcc86b69d   5 days ago      142MB
docker push ${REPOSITORY_URI}:latest


The push refers to repository [294373654843.dkr.ecr.us-east-1.amazonaws.com/web2048]
9fb7edea8440: Pushed
abc66ad258e9: Pushed
243243243ee2: Pushed
f931b78377da: Pushed
d7783033d823: Pushed
4553dc754574: Pushed
43b3c4e3001c: Pushed
latest: digest: sha256:daac922f8e9d6d2445c1ee1ab24a36190c0763d766908f7915cfcef53cec0123 size: 1780
aws ecr describe-images --repository-name web2048
{
    "imageDetails": [
        {
            "artifactMediaType": "application/vnd.docker.container.image.v1+json",
            "imageSizeInBytes": 57719510,
            "imageDigest": "sha256:daac922f8e9d6d2445c1ee1ab24a36190c0763d766908f7915cfcef53cec0123",
            "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "imageTags": [
                "latest"
            ],
            "registryId": "294373654843",
            "repositoryName": "web2048",
            "imagePushedAt": 1658767453.0
        }
    ]
}

Task 5 : Create an ECS Cluster

aws ecs create-cluster --cluster-name web2048
{
    "cluster": {
        "status": "ACTIVE",
        "defaultCapacityProviderStrategy": [],
        "statistics": [],
        "capacityProviders": [],
        "tags": [],
        "clusterName": "web2048",
        "settings": [
            {
                "name": "containerInsights",
                "value": "disabled"
            }
        ],
        "registeredContainerInstancesCount": 0,
        "pendingTasksCount": 0,
        "runningTasksCount": 0,
        "activeServicesCount": 0,
        "clusterArn": "arn:aws:ecs:us-east-1:294373654843:cluster/web2048"
    }
}
cd ~
echo ${REPOSITORY_URI}
vim web2048_task_definition.json
{
    "family": "web2048",
    "networkMode": "awsvpc",
    "taskRoleArn": "arn:aws:iam::000000000000:role/test-lab-3-ECSTaskExecutionRole-0000000000000",
    "executionRoleArn": "arn:aws:iam::000000000000:role/test-lab-3-ECSTaskExecutionRole-0000000000000",
    "containerDefinitions": [
        {
            "name": "web2048",
            "image": "000000000000.dkr.ecr.us-east-1.amazonaws.com/web2048:latest",
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ],
            "essential": true
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512"
}
aws ecs register-task-definition --cli-input-json file://web2048_task_definition.json
vim web2048_service.json
{
    "cluster": "web2048",
    "serviceName": "web2048",
    "taskDefinition": "web2048",
    "loadBalancers": [
        {
            "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-1:000000000000:targetgroup/ECS-Target-Group/0000000000000000",
            "containerName": "web2048",
            "containerPort": 80
        }
    ],
    "desiredCount": 2,
    "launchType": "FARGATE",
    "platformVersion": "LATEST",
    "networkConfiguration": {
        "awsvpcConfiguration": {
            "subnets": [
                "PublicSubnet1",
                "PublicSubnet2"
            ],
            "securityGroups": [
                "ecsSecurityGroup"
            ],
            "assignPublicIp": "ENABLED"
        }
    }
}
aws ecs create-service --cli-input-json file://web2048_service.json
aws ecs describe-clusters --cluster web2048
{
    "clusters": [
        {
            "status": "ACTIVE",
            "defaultCapacityProviderStrategy": [],
            "statistics": [],
            "capacityProviders": [],
            "tags": [],
            "clusterName": "web2048",
            "settings": [],
            "registeredContainerInstancesCount": 0,
            "pendingTasksCount": 0,
            "runningTasksCount": 2,
            "activeServicesCount": 1,
            "clusterArn": "arn:aws:ecs:us-east-1:310899899985:cluster/web2048"
        }
    ],
    "failures": []
}