Elastic Container
So single EC2 instance is cool and all. But this is the cloud. So dispite that I have routly 3 visitors to my site (and one is probably a bot), let’s setup the infrastructure to scale.
Step one is to build and upload my docker container to ECR. (this does mean I’ll have to change all my ansible plays)
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin {{ account-id }}.dkr.ecr.us-west-2.amazonaws.com
docker build -t dans-homepage .
docker tag dans-homepage:latest {{ account-id }}.dkr.ecr.us-west-2.amazonaws.com/dans-homepage:latest
docker push {{ account-id }}.dkr.ecr.us-west-2.amazonaws.com/dans-homepage:latest
Step two is to create a cluster to hold everything
aws ecs create-cluster --cluster-name dans-homepage
aws ecs list-clusters
Next is to create a taks definition for my dan-homepage service.
aws ecs register-task-definition --cli-input-json file://`pwd`/dans-task-def.json
aws ecs list-task-definitions
The container task definition looks like this.
{
"containerDefinitions": [
{
"name": "dans-homepage",
"image": "{{ account-id }}.dkr.ecr.us-west-2.amazonaws.com/dans-homepage:latest"
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
]
}
],
"memory": "512",
"cpu": "256",
"networkMode": "awsvpc",
"family": "http-server",
"requiresCompatibilities": [
"FARGATE"
]
}
Create the service itself. For this I’ll first need the subnet Id’s for my default VPC and the gourp id of my default secutity group.
aws ec2 describe-subnets | grep SubnetId
aws ec2 describe-security-groups | grep GroupId
Then I can create the service.
aws ecs create-service \
--cluster dans-homepage \
--service-name dans-homepage \
--task-definition dans-homepage:5 \
--desired-count 1 \
--launch-type "FARGATE" \
--network-configuration "awsvpcConfiguration={subnets=[subnet-0049d42d494e6563a,subnet-01753e2313b8a8532,subnet-0b19d4d273bd26f65,subnet-07b03a60d97f0b5eb],securityGroups=[sg-096e303e18dbb67bd], assignPublicIp=ENABLED}"
aws ecs list-services --cluster dans-homepage
Note that each time I update the docker image being uploaded, I’ll need to update the version number (and yes, I tried dans-homepage:latest. No luck)
Next is to get the public IP of the network interface.
aws ecs list-tasks --cluster dans-homepage # get the arn for my task
aws ecs describe-tasks --cluster dans-homepage --tasks "arn:aws:ecs:us-west-2:{{ account-id }}:task/dans-homepage/d765a4dad128495ab8141228c61d2033" | grep eni # get the network interfacer for my task
aws ec2 describe-network-interfaces --network-interface-id "eni-0670deeb6ae5bbddb" | grep PublicIp # get the public IP address for this network interface attached to my service.
Test the ip address in the browser and ta-da! Site is up. Point cloudflare at that IP and we now have WAY more work that is every needed to tell you that I put too much work into this.
Deploy
The downsite is my workflow is now I have to redeploy the site manually.
- In my repo, run
JEKYLL_ENV=production bundle exec jekyll bmanually - Run
docker build -t dans-homepage .to rebuild that image with the new post. - Push the image to ECR with docker
push {{ account-id }}.dkr.ecr.us-west-2.amazonaws.com/dans-homepage:latest - Update the service with
aws ecs update-service --cluster dans-homepage --service dans-homepage --force-new-deployment
And then get the new public Ip of my interface and point cloudflare at that. With great fanciness comes great maintainance.