This project is to create a CI solution using Terraform, Circle-CI, Ansible, AWS, and Docker
An automated way to deploy a webapp. Currently it uses or more EC2 instances interfaced from a load balancer.
It can accomodate multiple environments
s3 buckets are used for storing the terraform state files. One per environment. All s3 buckets are managed in one terraform workspace
Each environment is in AWS and contains:
- instances
- Security group for instances
- target group
- load balancer and listener
- Security group for load balancer
Each instance has local packages and docker. The webapp is running in a docker container on the instance.
Each environment can have as many instances as you want. They will round robin through the subnets.
The webapp is in a local python file and built to an image.
Stored on dockerhub (Todo: Create versioning for docker image)
Each environment is managed using a terraform workspace. The statefile is stored in the s3 bucket for that environment.
To avoid a circular dependancy problem, s3 buckets are part of a seperate terraform workspace called s3bucket
Any number of environments can be created, but it is recommended to create:
- dev
- test
- prod
- feature or stage as needed. Destroy them when done.
Environments each need an <env>.tfvars
file to store their configs. Make sure to specify this file when running terraform.
Install these into your dev environment:
- terminal (I used wsl and wt on windows)
- GIT
- terraform
- awscli
- ansible
- docker
- IDE (I used VSC)
These need to exist before any other infrastructure because terraform's state is stored in them.
To create a new environment:
- create a workspace
- create s3 bucket using s3 workspace
- select environment workspace
- init terraform for environment
- apply terriform to build instances and load balancer
- for each instance, run ansible playbook to install docker.
- for each instance, run ansible playbook to pull and run webapp docker image.
- test each instacne by navigating to public DNS.
- navigate to load balancer public DNS to test.
Only need to do this once at the beginning. This will set up dev, test, and prod environments. If more are needed, add to main.tf before setting up.
Warning: Do not do this except at creation because it could delete statefiles for environments if done after those environments are set up.
- Create workspace
cd tf/s3bucket
terraform workspace new s3bucket
- Verify in s3bucket workspace
terraform workspace list
- Add more environments into list in main.tf in this file if needed.
- Link variables from main directory
ln -s ../prod.tfvars prod.tfvars
- Run terraform
terraform init # answer yes
terraform plan -var-file="prod.tfvars"
terraform apply -var-file="prod.tfvars"
Instructions for setting up the initial configs stored in variables and s3 bucket for a new environment
- Select the workspace and verify it is selected:
cd tf
terraform workspace select s3bucket
terraform workspace list
- In the
tf
directory, create a<env>.tfvars
file (example:dev.tfvars
) intf
directory for your new environment.
See
example.tfvars.bak
for usage
cd tf
cp example.tfvars.bak prod.tfvars
- Modify file and configurations.
- Change directory into the s3bucket dirctory and create the symlink to them variables in the main directory.
cd s3bucket
ln -s ../prod.tfvars prod.tfvars
- Verify: cat to make sure it shows your variables
cat prod.tfvars
- From the s3bucket directory initialize terriform
terraform init
- Create s3bucket:
terraform plan -var-file="prod.tfvars"
terraform apply -var-file="prod.tfvars"
The bucket will need to be rebuilt if a policy or IAM role is added. For example if you want to add a new dev. cd tf/s3bucket terrafrom init
terraform plan -var-file="prod.tfvars
terraform apply -var-file="prod.tfvars
- Create new workspace
cd tf
terraform workspace new prod
- Select and verify the workspace
terraform workspace select prod
terraform workspace list
- Initialize the terraform. The environment needs to match the workspace. This will create the statefile in the bucket
cd tf
terraform init -migrate-state \
-backend-config="bucket=<your-bucket-name>" \
-backend-config="key=<path/state/terraform.tfstate>" \
-backend-config="region=us-west-2"
When you are creating for the first time, use
terraform -migrate-state \
as first line. For all other workspace, you just need to use theterraform init
command (may not need to use backend config first time either.) Example:
terraform init -migrate-state \
-backend-config="bucket=henry808-webserver-s3bucket-prod" \
-backend-config="key=prod/terraform.tfstate" \
-backend-config="region=us-west-2"
- Create ec2 instances and load balancer using terraform:
terraform plan -var-file="prod.tfvars"
public DNS for instances and load balancers are output when you run the terraform launcher. Instance DNS' are output for debugging.
- Create
hosts.yaml
and add ec2 domain name to host file. seeansible/inventory/hosts.yaml.bak
for example.
cd ansible/inventory
cp hosts.yaml.bak hosts.yaml
-
Add domain name of ec2 instances to
hosts.yaml
. Example: ec2-52-39-31-93.us-west-2.compute.amazonaws.com. Also add path to private key. -
Run ansible scripts for installing docker and then for installing the webapp via docker.
First Set all hosts in playbook to environment: prod_webservers, test_webservers, or dev_webservers. Also select hosts in the playbook before running.
cd ansible
ansible-playbook -i inventory/hosts.yaml playbooks/install_docker.yaml
ansible-playbook -i inventory/hosts.yaml playbooks/install_docker_webapp.yaml
Answer yes first time running with new host to add hostnames to your local hostfile.
- Navigate to http:////:8080
- Edit Python file
- build the docker image
- run the docker image locally and test it
- push image to dockerhub
- (Optional) create a feature environment
- deploy to a dev environment or feature environment using ansible script.
- Test on web browser.
For Developing the Webapp
cd docker/app
docker build -t henry808/webapp .
docker run -d -e ENV=test -p 8080:8080 henry808/webapp
Navigate to http://localhost:8080/
docker build -t henry808/webapp:latest .
docker push henry808/webapp:latest
cd ansible
ansible-playbook -i inventory/hosts.yaml playbooks/install_docker_webapp.yaml
Needed for troubleshooting
docker cp da681f7a7b0d:/home/ubuntu/ /home/henry808/temp/webapp/
docker attach webapp
docker exec -it webapp bash
- Add ASG
- Support for Private Docker Images
- https
- Lock ansible docker pull script to a version and remove force pull.
- Use IAM Role
- Create VPC and subnets (Maybe in another repo but use them here)
- Add feature (developer) envs (just add a feature to s3 key and to variables.tf and add new tfvars for each)
- Back up statefiles.
- Add Test harness and test job.
Current workspaces:
Workspace | State File Location | Directory |
---|---|---|
s3bucket | Local workspace | tf/s3bucket |
dev | Dev bucket | tf |
test | Test bucket | tf |
prod | Prod bucket | tf |
Directory column specifies the directory where terraform workspace command must be run from to access those workspaces.
Please note that in the markdown table, the "State File Location" column corresponds to the storage location of the state files for each workspace.
- Create new workspace
terraform workspace new prod
terraform workspace select prod
terraform workspace list
This need to be done so you use the right state file for each.
terraform workspace select dev
terraform workspace select prod
Henry Grantham