Lesson 3 – Deploying the Infrastructure
Lesson Overview
- In this lesson we’ll use terraform.io to build the AWS infrastructure required to host a docker application.
- We will tag our changes in git and commit them to github.
- If things work correctly, travis-ci will be notified of the commit and will start a build of the environment. If the tests pass, it will push a brand new docker image to AWS ECR artifact repository.
Warning:
This lab will not work with multiple users running the lab concurrently
in the same region. This is primarily due to limits on the number of
Elastic IPs allowed by default per region. Life will be much simpler
if each user uses a separate AWS account. If you insist on multiple users
running in the same account concurrently, please make the following
adjustments.
- Open a case with AWS to increase the limit on EIPs per region. You will need 3 EIPs per user running the lab in a singe region.
- Each user must have a unique
stageName
in the infrastructure/terraform/variables.tf file (currently set to “dev”). Use a 3 character name with all lower case alpha chars, maybe your initials (like: “bob”, “prd”, “tst” or “foo”). This is because all AWS resources are named using this string. If 2 or more users use the same names, there will be naming conflicts. - Additionally the
conatinerName
defined in infrastructure/terraform/variables.tf and docker-compose.yml (currently set to “flask_docker_lab”) must be changed to something unique. It is suggested that you change it to flaskdockerbob where bob is the same 3 chars you used for the stageName. This is because one image name can only be used once in an AWS account/region ECR repository - Finally, the
image:
&conatiner_name:
parameters in the docker-compose.yml file must match theconatinerName
in the variables.tf file (flaskdockerbob). You’ll need to stop the local containerdocker-compose down
, edit the docker-compose.yml file, then re-start the docker containerdocker-compose up -d
. This is because the docker image name must match the ECR repository defined above.
Lesson
- Initialize Terraform.
Terraform is a very powerful infrastructure automation engine. First we need toterraform init
the terraform scripts and download any required modules (aws module in this case).cd ~/flask_docker_lab/infrastructure/terraform/ terraform init
- Plan with Terraform
Next we need to run aterraform plan
to let terraform tell us what its going to do when we run apply. In this case, we are planning to create 50+ new resources including, but not limited to: (1) vpc, (1) internet gateway, (4) subnets, (4) routing tables, (1) application load balancer, (1) target group, (1) IAM user, (2) IAM roles, (1) auto scaling group, (1) launch configuration, (2) security groups, (1) ecr artifact repositories & (1) ecr cluster.terraform plan
- Apply (deploy) with Terraform
Finally, we need to runterraform apply
to actually build the infrastructure in AWS. This will take a few minutes to complete.terraform apply
Because we haven’t yet pushed a docker container to the AWS ECR repository, the build of the AWS ECR Service definition will fail. Terraform doesn’t roll back when a deployment fails. This is important to know about terraform and works great in this circumstance.
Error: Error applying plan:
1 error(s) occurred:
aws_ecs_service.ecs_service: 1 error(s) occurred:
aws_ecs_service.ecs_service: InvalidParameterException: The target group with targetGroupArn arn:aws:elasticloadbalancing:us-west-2:357849880876:targetgroup/fdldev20180514180259459500000003/a9063a8553981aaf does not have an associated load balancer.
status code: 400, request id: 136531a0-57a1-11e8-ba1e-8db92705beda “flask_docker_lab_svc”
Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.Navigate to: AWS Console > EC2 Container Services > Clusters > flask_docker_lab_dev_ecs_cluster > ECS Instances tab and you should have 2 running t2.micro EC2 servers.
- Configure the .travis.yml
Now that the AWS infrastructure is ready to go, lets configure travis-ci to automatically test, build and upload docker images (if the code passes a battery of tests).First thing we’ll do is put a starter .travis.yml in place
cd ~/flask_docker_lab cp infrastructure/travis.yml.example .travis.yml
- Login into travis cli
We’ll use our github credentials to authenticate the travis clitravis login
- Encrypt the AWS ECR artifact repository login information
If travis-ci has a successful build, we want it to push the docker file to the AWS docker repository we created in AWS Console > EC2 Container Services > Repositories > flask_docker_lab. Since this is a private repository, we need to put the login credentials in the .travis.yml file. But that file is going to be stored in our public repository, so it must be encrypted. The following script does the work for us../create_ecr_secrets.sh
- Tag and push our code
Now that AWS and Travis are both ready for a new docker image, lets tag and push the current version. You’ll have to authenticate with github twice, once for the code push and once for the tag pushgit add . git commit -am "the first version of our application" git tag -a v1.0 -m "the first version of our application" git push && git push --tags
- Go check travis-ci.org > Build History
It should be building, or have already built our application. The .travis.ci file runs a build and test on all commits, but only pushes tagged versions as image:latest and image:$versionCheck AWS > ECS Container > ECR repository.
We should have 1 image with 2 tags (latest and v1.0)Re-run terraform apply to deploy the ECR service definition
cd ~/flask_docker_lab/infrastructure/terraform/terraform apply
- Get the Loadbalancer DNS name from terraform output
Check AWS > ECS Container Service > Cluster > flask_docker_lab_dev_ecs_cluster > Tasks. Should have 2 tasks running terraform output
Put the DNS name in browser and tada!
- Update the code
modify SITE_TITLE again in atom flask_docker_lab/app/config.py
Then check to make sure the local version looks the way you want
cd ~/flask_docker_lab git add . git commit -am "the 2nd version of our application" git tag -a v1.1 -m "the 2nd version of our application" git push && git push --tags
- Deploy the new code
When the travis build / test / push is complete, update the ECS task
definition and service definition with the new docker `containerTag`cd infrastructure/terraform nano variables.tf
- Now redeploy terraform
terraform plan terraform apply
In a few minutes, the web site on the load balancer should have your new changes! Look at AWS > EC2 > target groups > flask-docker-lab-dev-alb-tgt-grp > targets. Observe that one of the old v1.0 instances will drain and be replaced by the new v1.1 instances. Then the second one will trade places too. This ensures a zero outage migration.
Also watch Clusters > flask_docker_lab_dev_ecs_cluster > flask_docker_lab_svc > Tasks tab. You can see what version of Tasks definition is specified in the service and which are running in the Task tab. Your migration is complete when both tasks are running the new code.
- See Update Site
Get “DNS name:” from AWS Console > EC2 > Load Balancers > flask-docker-lab-dev-alb and paste that URL into your browser
Lesson 3 Summary
In this lesson we
- Created ssh keys
- Initialized Terraform
- ran Terraform plan to see what would happen
- ran terraform apply to make the changes
- configured travis.yml for the ci build
- logged into travis CLI
- Encrypted the AWS ECR repository password file
- Tagged our code as v1.0 and pushed it out
- Watched the build, test and push to AWS happen in travis-ci
- Deployed out containers to a running cluster in AWS
- Updated our web site again as v1.1 and commit / pushed it
- Let Travis-ci build the updated code and we deployed it
- Learned how to earn $50!
In Lesson 4 we’ll clean up our mess.
Recent Comments