In the previous article we described the reasons that made us change the provider.
In this article we will describe how we built our infrastructure as code.
As a first step let’s create a bash script to run the playbook:
1 2 3 4 5 6 7 8 9 10 11 |
:~$ ./infrastructure_nuvola_env_aws.sh --env prod #!/bin/bash . libs/extra_option_parser.sh … ansible-playbook --vault-password-file secrets/infrastructure_nuvola_env.secret \ ansible/infrastucture_nuvola_env.yml \ -e"$EXTRA_OPTIONS" |
With the flexibility of AWS & Ansible we can easily craft an isolated multi environment:
1 2 3 |
./infrastructure_nuvola_env_aws.sh --env dev ./infrastructure_nuvola_env_aws.sh --env prod ./infrastructure_nuvola_env_aws.sh --env issue_env |
Then we need a playbook for each infrastructure’s component :
1 2 3 4 5 6 7 8 9 10 11 |
infrastructure_nuvola_env.yml tasks: - include: roles/infrastructure/tasks/infrastructure_nuvola_vpc.yml tags: vpc - include: roles/infrastructure/tasks/infrastructure_nuvola_ec2.yml tags: ec2 - include: roles/infrastructure/tasks/infrastructure_nuvola_elb.yml tags: elb - include: roles/infrastructure/tasks/infrastructure_nuvola_destroy.yml when: destroy == "true" and nuvola_env != "prod" |
Now let’s dig into some details for each playbook.
VPC (Virtual Private Cloud)
This is the playbook for VPC creation and network routing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
tasks/infrastructure_nuvola_vpc.yml - name: INFRASTRUCTURE NUVOLA VPC | setting up vpc ec2_vpc: state: present cidr_block: 10.0.0.0/16 resource_tags: { Name: "nuvola_{{ nuvola_env }}_vpc", nuvola_env: '{{ nuvola_env }}', nuvola_role: "vpc", billing: "{{ billing_tag_value }}", resource_type: "vpc" } subnets: - cidr: "10.0.{{ ec2_vpc_subnet }}.0/24" resource_tags: { Name : 'nuvola_{{ nuvola_env }}_vpc_subnet_0', nuvola_env: '{{ nuvola_env }}', nuvola_role: "vpc", billing: "{{ billing_tag_value }}", resource_type: "subnet" } az: {{ default_region }} - cidr: "10.0.{{ ec2_vpc_subnet | int + 1 }}.0/24" resource_tags: { Name : 'nuvola_{{ nuvola_env }}_local_rds_subnet', nuvola_env: '{{ nuvola_env }}', nuvola_role: "vpc", billing: "{{ billing_tag_value }}", resource_type: "subnet" } az: {{ default_region }} - cidr: "10.0.{{ ec2_vpc_subnet | int + 2 }}.0/24" resource_tags: { Name : 'nuvola_{{ nuvola_env }}_local_rds_subnet', nuvola_env: '{{ nuvola_env }}', nuvola_role: "vpc", billing: "{{ billing_tag_value }}", resource_type: "subnet" } az: {{ default_region_b }} internet_gateway: True register: vpc |
All instances in an env have a private network class. We also set up a gateway to connect our vpc with the internet.
It only remains to create a routing rule:
1 2 3 4 5 6 7 8 9 10 |
infrastructure_nuvola_vpc.yml - name: INFRASTRUCTURE NUVOLA VPC | setting up vpc peering ec2_vpc_peer: vpc_id: "{{ vpc['vpc']['id'] }}" peer_vpc_id: "{{ default_vpc.vpcs.0.id }}" state: present tags: Name: "Peering conenction nuvola_{{ nuvola_env }}" register: vpc_peer |
Good. We now have a fully functional vpc, one for each environment.
EC2 (Elastic Compute Cloud)
With the following playbook we build some EC2 instances to host our applications:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
infrastructure_nuvola_ec2.yml - name: INFRASTRUCTURE NUVOLA EC2 | Initialize backend instances ec2: key_name: '{{ ec2_key_name }}' instance_type: '{{ backend_instance_type }}' instance_tags: nuvola_type: "{{ nuvola_env }}_backend" nuvola_env: '{{ nuvola_env }}' nuvola_role: "backend" billing: "{{ billing_tag_value }}" image: "{{ ec2_ami_id }}" zone: "{{ ec2_zone }}" wait: yes wait_timeout: 600 group: "nuvola_{{ nuvola_env }}_backend_sg" count_tag: nuvola_type: "{{ nuvola_env }}_backend" exact_count: '{{ nuvola_backend_ec2_instances }}' vpc_subnet_id: "{{ vpc['subnets'][0]['id'] }}" assign_public_ip: yes monitoring: no termination_protection: "{{ delete_lock }}" volumes: - device_name: /dev/sda1 volume_type: gp2 volume_size: "{{ ec2_volume_size_backend }}" delete_on_termination: true instance_profile_name: "{{ ec2_instance_role }}" register: ec2_backend |
ELB (Elastic Load Balancer)
Having VPC and EC2 instances in place, we need a load balancer to distribute load on our backends. It’s pretty easy with AWS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
infrastructure_nuvola_elb.yml - name: INFRASTRUCTURE NUVOLA ELB | Setup ELB ec2_elb_lb: state: present name: 'nuvola-{{ nuvola_env }}-elb' security_group_names: 'nuvola_{{ nuvola_env }}_elb_sg' subnets: "{{ vpc['subnets'][0]['id'] }}" purge_subnets: yes tags: Name: "nuvola-{{ nuvola_env }}-elb" nuvola_type: "{{ nuvola_env }}_elb" nuvola_env: "{{ nuvola_env }}" billing: "{{ billing_tag_value }}" nuvola_role: elb listeners: - protocol: http load_balancer_port: 80 instance_port: 80 - protocol: https load_balancer_port: 443 instance_protocol: http instance_port: 80 ssl_certificate_id: '{{ ssl_cert_id }}' health_check: ping_protocol: http ping_port: 80 ping_path: "/ping.html" response_timeout: 2 interval: 5 unhealthy_threshold: 2 healthy_threshold: 5 register: elb_setup |
In the next article we’ll show you another chapter of our migration to AWS.
Stay tuned!
How do you deploy the application code to EC2? Is it already baked in EC2 Image?
These scripts are for the infrastructure. We do deploy with other scripts. In practice, we download the code from github and configure the environment. Maybe we will do an article on deploy.