Slide 1

Slide 1 text

CLOUDFORMATION PHILLY DEVOPS MEETUP 2017-01-17

Slide 2

Slide 2 text

CLOUDFORMATION FOR FUN& PROFIT BUT MOSTLY SANITY

Slide 3

Slide 3 text

YOUR HOST: NATE ABELE ▸Some PHP frameworks (Li3, CakePHP) ▸AngularUI Router ▸Architect @ Radify ▸[email protected] ▸@nateabele

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

GROWING AN APP

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

- name: Create launch config for worker nodes ec2_lc: name: "lc_{{ app_environment }}_workers_{{ ami }}_{{ stamp }}" image_id: "{{ ami }}" instance_monitoring: 'yes' instance_profile_name: "cloudwatch-write" key_name: "{{ key_name }}" region: "{{ asg_region }}" security_groups: "{{ asg_ec2_instance_sg }}" instance_type: "{{ asg_instance_type }}" assign_public_ip: yes volumes: - device_name: /dev/sda1 volume_size: 8 delete_on_termination: true service remote_syslog restart # Inject env vars into workers perl -pi -e "s/{{ sqs_queue_notifications }}/g" /etc/init/app-worker-noti… perl -pi -e "s/{{ sqs_queue_emails }}/g" /etc/init/app-worker-emails.conf perl -pi -e "s/{{ sqs_queue_kpis }}/g" /etc/init/app-worker-gather-kpis… if [[ "{{ app_environment }}" == "production" ]] then update-rc.d datadog-agent enable service datadog-agent start fi if [[ "{{ app_environment }}" == "demo" ]] then # remove the gather KPI worker on demo rm -f /etc/init/app-worker-gather-kpis.conf else # Symlink newrelic PHP extension and PHP config ln -s /usr/lib/newrelic-php5/agent/x64/newrelic-20131226.so … ln -s /etc/php/5.6/mods-available/newrelic.ini /etc/php/5.6/… ln -s /etc/php/5.6/mods-available/newrelic.ini /etc/php/5.6/… # Start all monitoring services service newrelic-sysmond restart fi # Kill FPM and Nginx service nginx stop service php5.6-fpm stop # Restart services /usr/local/bin/restart_services tags: launch_config_workers - name: Upsert autoscale group for workers [in foreground] ec2_asg: name: "{{ app_environment }}-workers-group" launch_config_name: "lc_{{ app_environment }}_workers_{{ ami }}_{{ stamp }}" replace_all_instances: yes region: "{{ asg_region }}" health_check_period: 300 health_check_type: EC2 wait_timeout: 600 state: present default_cooldown: 150 vpc_zone_identifier: "{{ asg_subnets }}" availability_zones: "{{ asg_availability_zones }}" min_size: "{{ asg_min_size_workers }}" max_size: "{{ asg_max_size_workers }}" desired_capacity: "{{ asg_desired_capacity_workers }}" tags: - Environment: "{{ app_environment }}" - Class: "worker" - Type: "autoscaling" - Name: "{{ app_environment }}-worker-autoscaling" user_data: | #!/bin/bash # Install env vars to /etc/environment cat > /etc/environment < /etc/log_files.yml < /etc/log_files.yml <

Slide 16

Slide 16 text

PR-BASED DEMO ENVIRONMENTS

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

“The Oven”

Slide 20

Slide 20 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates { "AWSTemplateFormatVersion": "2010-09-09", "Description": "...", "Parameters": { ... }, "Resources": { ... }, "Outputs": { ... } }

Slide 21

Slide 21 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates ▸ Stacks aws:cloudformation:logical-id: WebServerFleet aws:cloudformation:stack-id: arn:aws:cloudformation:us-east-1:022261289334:stack/ prod/458dc900-d0a5-11e6-b7e8-50d501eed2b3 aws:cloudformation:stack-name: prod

Slide 22

Slide 22 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates ▸ Stacks ▸ Parameters "SSHLocation": { "Description": "Lockdown SSH access", "Type": "String", "MinLength": "9", "MaxLength": "18", "Default": "0.0.0.0/0", "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\ \d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription": "must be a valid CIDR range of the form x.x.x.x/x." }

Slide 23

Slide 23 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates ▸ Stacks ▸ Parameters "KeyName": { "Description": "Name of an existing EC2 KeyPair", "Type": "AWS::EC2::KeyPair::KeyName", "ConstraintDescription": "must be the name of an existing EC2 KeyPair." }

Slide 24

Slide 24 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates ▸ Stacks ▸ Parameters ▸ Resources ▸ Refs "VPC": { "Type": "AWS::EC2::VPC", "Properties": { ... } }, "DatabaseSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "VpcId": { "Ref": "VPC" } } }

Slide 25

Slide 25 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates ▸ Stacks ▸ Parameters ▸ Resources ▸ Refs ▸ Functions "DBName": { "Fn::Join": [ "", [ “appname", { "Ref": "AWS::StackName" } ]] }

Slide 26

Slide 26 text

PHILLY DEVOPS SO, HOW DOES ONE CLOUDFORMATION? ▸ Templates ▸ Stacks ▸ Parameters ▸ Resources ▸ Refs ▸ Functions ▸ Outputs "URL": { "Description": "URL of new stack", "Value": { "Fn::Join": [ "", [ "http://", { "Fn::GetAtt": [ "PublicElasticLoadBalancer", "DNSName" ] ]] } }

Slide 27

Slide 27 text

USER DATA, SIGNALS, & SECRETS

Slide 28

Slide 28 text

"UserData": { "Fn::Base64": { "Fn::Join": ["", [ "#!/bin/bash -xe\n", "/opt/aws/bin/cfn-init --stack ", {"Ref": "AWS::StackId"}, " --resource WebServerFleet ", " --region ", { "Ref": "AWS::Region" }, "\n\n", " db_username=", { "Ref": "DBUserName" }, " db_password=", { "Ref": "DBPassword" }, “; export APP_ENV=production", "\n\n" ...Other bootstrappy stuff "# Signal completion\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref": "AWS::StackId" }, " --resource WebServerFleet ", " --region ", { "Ref": "AWS::Region" } ]]}}

Slide 29

Slide 29 text

LAYERS; FOR ONIONS, FOR OGRES, FOR STACKS

Slide 30

Slide 30 text

PHILLY DEVOPS QUANTIFYING THE WIN ▸ Declarative: No process logic ▸ Fully self-contained: no one-off or bespoke resources ▸ Easy name-spacing for global objects ▸ Eliminates / isolates secrets

Slide 31

Slide 31 text

PHILLY DEVOPS TRY THIS AT HOME

Slide 32

Slide 32 text

PHILLY DEVOPS TRY THIS AT HOME

Slide 33

Slide 33 text

PHILLY DEVOPS TRY THIS AT HOME ▸ CloudFormation Designer ▸ Do it by hand! ▸ Bootstrap via AWS Console + CloudFormer

Slide 34

Slide 34 text

PHILLY DEVOPS TRY THIS AT HOME ▸ CloudFormation Designer ▸ Do it by hand! ▸ Bootstrap via AWS Console + CloudFormer

Slide 35

Slide 35 text

PHILLY DEVOPS TRY THIS AT HOME ▸ CloudFormation Designer ▸ Do it by hand! ▸ Bootstrap via AWS Console + CloudFormer ▸ VisualOps

Slide 36

Slide 36 text

THANKS

Slide 37

Slide 37 text

QUESTIONS?

Slide 38

Slide 38 text

NOTES The Platonic ideal of ops (and computing tasks generally) is to be able to describe an expected state, and have the computer figure out the details. Tools like Chef, Puppet, and Ansible get us closer to this state, but often our work ends up being little more than abstractions over commands to manually provision infrastructure. Enter AWS CloudFormation. CloudFormation allows us to provision & maintain complete application infrastructures from a single template file, and solves many problems for us along the way, including dependency resolution, data passing, and sharing or eliminating secrets. Come learn about these techniques, as well as the many ways to author & maintain CloudFormation stacks. - Brief intro to AWS - Progression of stack complexity: EC2 instance -> EC2 + S3 -> + DB -> + ELB -> + ASG -> + VPC - Staging environment? Good luck refactoring all your playbooks / recipes, sucker! -- More importantly, unless you're really experienced, the definition of your infrastructure is now tightly coupled to your playbooks, and probably to some extent to your build process - Example: demo nodes (flowchart) - Parameters - App / stack name (& naming things like S3 buckets) - Roles (vs. secrets) - Digression into user data - Building and maintaining - Do it by hand! Great way to learn and understand the inner workings - Bootstrap via AWS Console + CloudFormer - AWS CloudFormation Designer (It's terrible) - VisualOps