Slide 1

Slide 1 text

Configuration Management and Provisioning Are Different Carlos Nunez [email protected] | @easiestnameever

Slide 2

Slide 2 text

What’s Provisioning? Provisioning tools enable you to create, modify and/or delete infrastructure using code and/or APIs.

Slide 3

Slide 3 text

Provisioning In A Nutshell OLD NEW Get hardware* terraform plan terraform apply * Or AWS/Google Cloud/Heroku/etc account. Get hardware* Run install scripts Consult runbook Configure CM, if necessary Wait for CM to apply

Slide 4

Slide 4 text

Why Provisioning Tools? Infrastructure deployment procedures as code --- no more docx runbooks Save you time ($$$) from writing your own provisioning code Enables infrastructure deployment testing just like code --- no fragile infrastructure

Slide 5

Slide 5 text

Provisioning: An Example # ~/code/terraform/main.yml resource "aws_instance" "ec2_instance" { ami = "${var.ami_id}" count = "${var.number_of_instances}" subnet_id = "${var.subnet_id}" instance_type = "${var.instance_type}" user_data = "${var.user_data}" key_name = "${var.key_name}" vpc_security_group_ids = ["${var.security_group_ids}"] tags { Name = "${var.instance_name}-${count.index}" } associate_public_ip_address = "${var.create_public_ip_address}“ provisioner “remote-exec” { inline = [ “git clone $ANSIBLE_REPO /tmp/ansible”, “ansible-playbook –i ${var.ansible_inventory} –vvv ${var.playbook} ] } } $> cd ~/code/terraform $> terraform plan –var-file ./environments/dev –var number_of_instances=1000 $> terraform apply –var-file ./environments/dev –var number_of_instances=1000 This is how you define an AWS EC2 instance with Terraform. You can make your own providers for nearly any server, networking device, or other piece of infrastructure you want to provision. Boom. You’ve just deployed 1,000 development EC2 instances, all configured by Ansible. Nice. * Until it’s not. But it usually is.

Slide 6

Slide 6 text

Why Config Management? Configuration management expresses the state of your infrastructure with code and/or APIs.

Slide 7

Slide 7 text

What’s Config Management? Consistent and repeatable infrastructure Simple domain-specific language --- anyone can read and contribute APIs allow easier tooling and scalability

Slide 8

Slide 8 text

Config Management: An Example --- # an example of an ansible playbook main.yml - name: install tree sudo: yes apt: name={{ item }} state=present with_items: - tree --- # an example of which hosts would receive the above - hosts: useless_server.va1.example.com roles: - has_tree Roles in Ansible group specific actions to be applied onto hosts. This is an example of a role called has_tree. It installs tree. Yay, tree. This is how you tell Ansible to install tree onto servers. It really is that easy. Not kidding.* * Until it’s not. But it usually is.

Slide 9

Slide 9 text

You might be thinking… Let’s provision stuff with Ansible!

Slide 10

Slide 10 text

You might be thinking… Let’s not.

Slide 11

Slide 11 text

Provisioning and CM are different There’s a cost to idempotency.

Slide 12

Slide 12 text

Complexity in simplicity --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ Here is a simple playbook that deploys an EC2 instance. We’re assuming that our options such as its access and secret keys and AMI ID will be provided through a variable file. --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... This (incomplete) playbook will configure hosts in the webservers group with NGINX. We’ll assume that this will run on ec2 servers tagged with “application: web_server” by way of dynamic inventory.

Slide 13

Slide 13 text

Complexity in simplicity --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... How can we guarantee this?

Slide 14

Slide 14 text

Complexity in simplicity --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... when: instance_count < 3 --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Obtain number of web instances currently present shell: “aws ec2 describe_instances --filter {{ ec2_filter }} --query ‘Reservations[].Instances[].Id’ –output text | wc –l” register: command_result - set_fact: instance_count: “{{ command_result.stdout | int }}” - fail: msg: “Invalid instance count!” when: instance_count < 0 ... # continued to the right -> --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ Get state externally is how!

Slide 15

Slide 15 text

Complexity in simplicity --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Obtain number of web instances currently present shell: “aws ec2 describe_instances --filter {{ ec2_filter }} --query ‘Reservations[].Instances[].Id’ –output text | wc –l” register: command_result - set_fact: instance_count: “{{ command_result.stdout | int }}” - fail: msg: “Invalid instance count!” when: instance_count < ... 1. What happens if your external dependency isn’t available? 2. What happens with unexpected output? 3. What if this external dependency is slow?

Slide 16

Slide 16 text

Complexity in simplicity --- # ~/code/ansible/tasks/ec2/retrieve_instance_count.yml - include: tasks/check_for_awscli.yml - name: Obtain number of web instances currently present shell: “{{ awscli_path }} ec2 describe_instances --filter {{ ec2_filter }} --query ‘Reservations[].Instances[].Id’ –output text | wc –l” register: command_result - set_fact: instance_count: “{{ command_result.stdout | int }}” - fail: msg: “Invalid instance count!” when: instance_count < 0 “Modularize” it! --- # ~/code/ansible/tasks/ec2/check_for_awscli.yml - name: Find awscli binary shell: “which awscli” register: command_result - fail: msg: “AWSCLI was not found.” when: command_result.exit_code != - set_fact: awscli_path: “{{ command_result.stdout }}” --- # ~/code/ansible/deploy_ec2_web_server.yml - include: tasks/ec2/retrieve_instance_count.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} ...

Slide 17

Slide 17 text

Complexity in simplicity --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ Want to create things like security groups dynamically? Prepare for more of that.

Slide 18

Slide 18 text

Complexity in simplicity simplicity

Slide 19

Slide 19 text

Complexity in simplicity --- # ~/code/terraform/web_servers.tf resource “aws_instance” “ec2_instance” { ami = “${var.ami_id}” count = “${var.number_of_instances}” subnet_id = “${var.instance_type}” user_data = “${var.user_data}” key_name = “${var.key_name}” tags { cost_center = “${var.cost_center}” application = “web servers” project_name = “${var.project_name}” } associate_public_ip_address = yes } simplicity.

Slide 20

Slide 20 text

Stateless provisioning is tricky Keeping environment state is up to you.

Slide 21

Slide 21 text

Stateless provisioning is tricky --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... What happens to existing instances when this changes?

Slide 22

Slide 22 text

Stateless provisioning is tricky --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... Nothing. You have to write a new task to update them.

Slide 23

Slide 23 text

Complexity in simplicity --- # ~/code/terraform/web_servers.tf resource “aws_instance” “ec2_instance” { ami = “${var.ami_id}” count = “${var.number_of_instances}” subnet_id = “${var.instance_type}” user_data = “${var.user_data}” key_name = “${var.key_name}” tags { cost_center = “${var.cost_center}” application = “web servers” project_name = “${var.project_name}” } associate_public_ip_address = yes } stateful.

Slide 24

Slide 24 text

Stateless provisioning is tricky --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... What happens if this fails?

Slide 25

Slide 25 text

Stateless provisioning is tricky --- # ~/code/ansible/deploy_ec2_web_server.yml - name: Provision an EC2 web server instance. ec2: aws_access_key: {{ aws_access_key }} aws_secret_key: {{ aws_secret_key }} exact_count: {{ number_of_instances }} group: [ ‘web’, ‘ansible_managed’ ] instance_type: t2.medium monitoring: yes key_name: {{ aws_ec2_access_key }} vpc_subnet_id: {{ vpc_subnet_id }} assign_public_ip: yes ami_id: {{ aws_ami_id }} instance_tags: cost_center: {{ cost_center }} project_code: {{ project_code }} application: ‘web_server’ --- # ~/code/ansible/configure_nginx_web_server.yml - hosts: webservers tasks: - name: Install nginx ... - name: Configure it ... Nothing. Rollback is on you.

Slide 26

Slide 26 text

Complexity in simplicity --- # ~/code/terraform/web_servers.tf resource “aws_instance” “ec2_instance” { ami = “${var.ami_id}” count = “${var.number_of_instances}” subnet_id = “${var.instance_type}” user_data = “${var.user_data}” key_name = “${var.key_name}” tags { cost_center = “${var.cost_center}” application = “web servers” project_name = “${var.project_name}” } associate_public_ip_address = yes } safe.

Slide 27

Slide 27 text

Provisioning Tools Cumulus SparkleFormation

Slide 28

Slide 28 text

Provisioning Tools Cumulus SparkleFormation + Chef/Ansible/Puppet?

Slide 29

Slide 29 text

Provisioning Tools Cumulus SparkleFormation + Chef/Ansible/Puppet? SURE!

Slide 30

Slide 30 text

Thanks!