Update: This project is originally written on April 2016 with Terraform 0.6. On March 2018, ELB is updated to ALB and this repository is now tested with Terraform 0.11.
This repository provides a tutorial to deploy a simple webapp (https://github.com/docker-training/webapp) to ASG cluster which utilizes ECS as its container service.
Advantage of using Terraform in managing ASG + ECS cluster with Docker:
- Scalability: We can simply add number of running instances in ASG and desired number of tasks in ECS
- Easy deployment and rollback: With Docker tag as version marker and ECS minimum healthy percent, we can specify it in Terraform to execute rolling update to our servers (See: http://docs.aws.amazon.com/AmazonECS/latest/developerguide/update-service.html). One simple command and you can release your new web application anytime.
- Terraform (https://www.terraform.io/downloads.html)
AWS_SECRET_ACCESS_KEYenvironment variable in your local environment
In our project, we divide Terraform configuration files into three main categories:
asg: Autoscaling groups (ASG), Application Load Balancer (ALB), ECS fall into this category
common: Common architecture which is rarely changed (VPC) but we still want to manage them with Terraform
static: As the name suggests, we usually create this static configuration only once. Furthermore, we usually don't want to delete any resource from this category. IAM, DynamoDB tables, SQS queues, S3 bucket fall into this category
Why do we separate our Terraform configuration files into three categories?
Reason 1: Sometimes, we don't want to touch specific part of our environments after initial creation. For example, we don't want to destroy our DynamoDB Tables, IAM role, and SQS queues. That's why we create a specific
static category for this scenario.
Reason 2: We want to deploy our application in several regions, let's say,
ap-northeast-1 a.k.a Tokyo and
ap-southeast-1 a.k.a Singapore. IAM role are global configuration which only needs to be executed one time while we may need to replicate
asg to several environments.
Reason 3: For application versioning, we usually only change Docker tag version or instance's launch configuration. Therefore, we separate the category into two:
common. We don't want to touch our VPC for each deployment, which makes it reasonable to put these configurations under
├── asg | ├── task-definition | | ├── ecs_task_webapp.tpl | | └── ... (another task definitions) | ├── alb.tf | ├── autoscaling.tf | ├── autoscaling_user_data.tpl | ├── configuration.tfvars | ├── ecs.tf | ├── output.tf | ├── vars.tf | └── ... (other ASG related files) | ├── common | ├── configuration.tfvars | ├── output.tf | ├── security_groups.tf | ├── vpc.tf | ├── vars.tf | └── ... (other common related files) | └── static ├── iam | ├── configuration.tfvars | ├── iam.tf | ├── output.tf | └── vars.tf └── ... (other AWS services: SQS, DynamoDB, etc)
For the first step, we need to deploy these environments in order:
asg. After first deployment, our changes will usually happen in
asg category, so we don't need to touch other environments anymore.
The workflow for each part is basically quite the same:
- Modify configuration.tfvars variables
terraform initto initialize things
terraform plan -var-file=configuration.tfvarsand confirm changes
terraform apply -var-file=configuration.tfvars
It's recommended to store
terraform.tfstate remotely. In this case, you can share your current environment state with other members. You can utilize S3, Atlas, etc to store your tfstate. For further information, please read it at the official documentation: https://www.terraform.io/docs/backends/index.html.
Not only that, you could simplify
asg to use
common environment as its remote state. All
common will be consumed directly by
asg and therefore you don't need to specify those values in
configuration.tfvars any longer. For further information, please read it at the official documentation: https://www.terraform.io/docs/state/remote.html.
Last Updated: March 2, 2018