Slide 1

Slide 1 text

By Thijs Feryn Build, provision & deploy in the Cloud with: Packer, Ansible & Terraform

Slide 2

Slide 2 text

I’m so sick of Cloud!

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

SaaS PaaS Iaas Private Public Hybrid

Slide 6

Slide 6 text

Abstraction

Slide 7

Slide 7 text

Flexibility

Slide 8

Slide 8 text

Result in stability

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Addressing the needs of today’s internet

Slide 11

Slide 11 text

Technical point of view

Slide 12

Slide 12 text

Developers Agile

Slide 13

Slide 13 text

Sysadmins DevOps

Slide 14

Slide 14 text

Virtualization

Slide 15

Slide 15 text

Web 2.0: everyone participates

Slide 16

Slide 16 text

Always online

Slide 17

Slide 17 text

Online Everywhere

Slide 18

Slide 18 text

Deployment

Slide 19

Slide 19 text

Scalability

Slide 20

Slide 20 text

Servers can go down any second

Slide 21

Slide 21 text

Automation

Slide 22

Slide 22 text

Many platforms

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

✓ Less lock-in ✓ Faster deployments ✓ Better scalability ✓ Better reproducibility ✓ Less human error ✓ Lower cost Goals

Slide 26

Slide 26 text

Hi, I’m Thijs

Slide 27

Slide 27 text

I’m @ThijsFeryn on Twitter

Slide 28

Slide 28 text

I’m an Evangelist At

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

Git repo Application Code Build server Servers Commit Build Deploy Git repo Infra scripts Build server Commit Build Orchestrate

Slide 31

Slide 31 text

Git repo Application Code Build server Servers Commit Build Push Infra scripts VM image Cloud registry Build & provision Orchestrate

Slide 32

Slide 32 text

Application code + Stack = VM image

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

VM image + Orchestration = Infrastructure

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Disposable stacks

Slide 38

Slide 38 text

Test = Staging = Production

Slide 39

Slide 39 text

Deployment A Deployment B Internet Floating IP Atomic switch from deployment A to deployment B

Slide 40

Slide 40 text

Deployment A Deployment B Internet Floating IP Atomic switch from deployment A to deployment B

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

✓ Alicloud ECS ✓ Amazon EC2 ✓ Azure ✓ CloudStack ✓ DigitalOcean ✓ Docker ✓ File ✓ Google Cloud ✓ Hyper-V ✓ LXC ✓ LXD ✓ Null ✓ 1&1 ✓ OpenStack ✓ Oracle OCI ✓ Parallels ✓ ProfitBricks ✓ QEMU ✓ Triton ✓ VirtualBox ✓ VMware ✓ Custom Packer builders

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

{ "builders": [ { "type": "openstack", "identity_endpoint": "https://osp.combell.com:5000/v3", "tenant_name": "", "username": "", "password": "", "image_name": "MyBuild-{{isotime \"2006-01-02 03:04:05\"}}", "source_image": "1b9fe43e-4cf2-4986-b7f2-51f5706b120b", "ssh_username": "debian", "domain_name" : "default", "flavor": "m1.medium", "networks": ["a1175c54-cb12-436d-ac7b-d327499dc39b"], "floating_ip_pool" : "public" } ] }

Slide 45

Slide 45 text

$ packer build packer.json

Slide 46

Slide 46 text

Packer build Openstack API Boot VM using source image Take VM snapshot Image registry Store VM snapshot as new image Tear down VM

Slide 47

Slide 47 text

$ openstack image list +--------------------------------------+----------------------------------+--------+ | ID | Name | Status | +--------------------------------------+----------------------------------+--------+ | ef90ad1c-ed64-4ae0-8283-e446e95c33e6 | MyBuild-2017-10-26 02:31:24 | active | | aa0a5244-0d57-477d-b985-653d6b881292 | Windows-2012-R2 | active | | 31e84bbb-abbb-4d5a-b620-ecebf4697d16 | centos-6-64bit | active | | 9eac74f9-6e6c-45a9-bd93-915d3e390687 | centos-7-64bit | active | | 3a69a110-775f-41ad-9d63-32079db57203 | cirros-0.3.4-64bit | active | | 244cbbde-77b6-4f1e-837f-9250520ee78b | coreos-stable | active | | 1b9fe43e-4cf2-4986-b7f2-51f5706b120b | debian-jessie-64bit | active | | 690b063b-f239-4032-ad23-9ae6337f248f | debian-stretch-64bit | active | | d8034a10-9b15-46b1-9c68-bd98f92d0ffb | ubuntu-server-precise-lts-64-bit | active | | 040f9d1d-bb18-4466-abd7-9f2172e6db70 | ubuntu-server-trusty-lts-64-bit | active | | 5be2b652-a965-4ecb-a2b4-b9f83d7779e6 | ubuntu-server-xenial-lts-64-bit | active | +--------------------------------------+----------------------------------+--------+

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

Configuration management system

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

✓ Written in Python ✓ Agentless ✓ Standalone ✓ SSH-based ✓ Runs playbook (yml files) ✓ Groups playbook in roles ✓ Install software ✓ Configure your server Ansible

Slide 52

Slide 52 text

--- - hosts: all sudo: true tasks: - name: update apt cache apt: update_cache=yes cache_valid_time=86400 - name: install required packages apt: name={{ item }} state=present with_items: - vim - curl - nginx - php-fpm - name: create /var/www/html folder file: path: /var/www/html state: directory mode: 0755 owner: www-data - name: configure index.php template: src: files/index.php playbook.yml

Slide 53

Slide 53 text

- name: configure index.php template: src: files/index.php dest: /var/www/html/index.php owner: www-data group: www-data mode: 0644 force: yes - name: configure nginx vhost copy: src: files/nginx.conf dest: /etc/nginx/sites-enabled/default owner: www-data group: www-data mode: 0644 force: yes notify: - reload nginx handlers: - name: reload nginx service: name=nginx state=reloaded playbook.yml

Slide 54

Slide 54 text

Organize your playbooks

Slide 55

Slide 55 text

. !"" files # $"" db.sql !"" host_vars # $"" default.yml !"" group_vars # $"" all.yml !"" inventory !"" playbook.yml !"" roles # $"" my-role # !"" defaults # # $"" main.yml # !"" handlers # # $"" main.yml # !"" meta # # $"" main.yml # !"" tasks # # $"" main.yml # !"" templates # # $"" template.j2 # $"" vars # $"" vars.yml !"" tasks # !"" task1.yml # !"" task2.yml $"" templates $"" template.j2

Slide 56

Slide 56 text

- hosts: default sudo: true tasks: - include: tasks/logfiles.yml - include: tasks/hosts.yml - include: tasks/packages.yml - include: tasks/mysql.yml post_tasks: - include: tasks/nginx-vhost.yml handlers: - name: Import MySQL mysql_db: name=my_database state=import target=/path/to/files/db.sql roles: - nginx - percona-server - php - php-fpm More organized version of playbook.yml

Slide 57

Slide 57 text

. !"" files # $"" db.sql !"" host_vars # $"" default.yml !"" group_vars # $"" all.yml !"" inventory !"" playbook.yml !"" roles # $"" my-role # !"" defaults # # $"" main.yml # !"" handlers # # $"" main.yml # !"" meta # # $"" main.yml # !"" tasks # # $"" main.yml # !"" templates # # $"" template.j2 # $"" vars # $"" vars.yml !"" tasks # !"" task1.yml # !"" task2.yml $"" templates $"" template.j2

Slide 58

Slide 58 text

[eu-webservers] web01.srv.my-company.com web02.srv.my-company.com [us-webservers] web03.srv.my-company.com web04.srv.my-company.com [eu-dbservers] db01.srv.my-company.com db02.srv.my-company.com [us-dbservers] db03.srv.my-company.com db04.srv.my-company.com [webservers:children] eu-webservers us-webservers [dbservers:children] eu-dbservers us-dbservers [eu:children] eu-webservers eu-dbservers [us:children] eu-webservers us-dbservers Inventory file

Slide 59

Slide 59 text

server { index index.php; server_name {{webserver_hostname}}; root {{homedirectory}}/public; listen 80; location ~ \.php { fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_param APPLICATION_ENV {{application_env}}; fastcgi_pass unix:/var/run/php7.0-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_split_path_info ^(.+\.php)(\/.+)$; } location ~ /\.ht { deny all; } location / { sendfile on; try_files $uri $uri/ /index.php; } } Template file in Jinja2 format

Slide 60

Slide 60 text

. !"" files # $"" db.sql !"" host_vars # $"" default.yml !"" group_vars # $"" all.yml !"" inventory !"" playbook.yml !"" roles # $"" my-role # !"" defaults # # $"" main.yml # !"" handlers # # $"" main.yml # !"" meta # # $"" main.yml # !"" tasks # # $"" main.yml # !"" templates # # $"" template.j2 # $"" vars # $"" vars.yml !"" tasks # !"" task1.yml # !"" task2.yml $"" templates $"" template.j2

Slide 61

Slide 61 text

--- php_display_errors: "Off" php_enable_webserver: false php_enable_php_fpm: true php_date_timezone: "Europe/Brussels" create_app_db: true db_name: "my_db" db_collation: "utf8_general_ci" db_user: "username" db_user_password: "" db_host: "%" db_dump_file: "files/db.sql" nginx_install_method: "package" webserver_hostname: "web001.srv.my-company.com" application_env: "production" homedirectory: "/var/www/html" nginx_repo: "ppa:nginx/stable" php_enable_webserver: false php_enable_php_fpm: true php_date_timezone: "Europe/Brussels" root_password: “" Host or group variables

Slide 62

Slide 62 text

. !"" files # $"" db.sql !"" host_vars # $"" default.yml !"" group_vars # $"" all.yml !"" inventory !"" playbook.yml !"" roles # $"" my-role # !"" defaults # # $"" main.yml # !"" handlers # # $"" main.yml # !"" meta # # $"" main.yml # !"" tasks # # $"" main.yml # !"" templates # # $"" template.j2 # $"" vars # $"" vars.yml !"" tasks # !"" task1.yml # !"" task2.yml $"" templates $"" template.j2

Slide 63

Slide 63 text

$ ansible-playbook playbook.yml

Slide 64

Slide 64 text

{ "type": "openstack", "identity_endpoint": "https://osp.combell.com:5000/v3", "tenant_name": "18324-1", "username": "18324", "password": "", "image_name": "MyBuild-{{isotime \"2006-01-02 03:04:05\"}}", "source_image": "1b9fe43e-4cf2-4986-b7f2-51f5706b120b", "ssh_username": "debian", "domain_name" : "default", "flavor": "m1.medium", "networks": ["a1175c54-cb12-436d-ac7b-d327499dc39b"], "floating_ip_pool" : "public" } ], "provisioners": [ { "type": "ansible", "playbook_file": "./ansible/playbook.yml" } ] }

Slide 65

Slide 65 text

$ ansible-playbook --extra-vars packer_build_name=openstack packer_builder_type=openstack -i /var/folders/j7/ kpxjpxq92vs_t97gg6tqtttm0000gn/T/packer-provisioner- ansible972172074 /Users/thijsferyn/Dropbox/Sites/openstack/ packer-ansible-terraform/ansible/playbook.yml --private-key / var/folders/j7/kpxjpxq92vs_t97gg6tqtttm0000gn/T/ansible- key333617975

Slide 66

Slide 66 text

Packer build Openstack API Boot VM using source image Take VM snapshot Image registry Store VM snapshot as new image Ansible provisioning run Tear down VM

Slide 67

Slide 67 text

Packer build Openstack API Boot VM using source image Take VM snapshot Image registry Store VM snapshot as new image Ansible provisioning run Store build results manifest.json Tear down VM

Slide 68

Slide 68 text

"image_name": "MyBuild-{{isotime \"2006-01-02 03:04:05\"}}", "source_image": "1b9fe43e-4cf2-4986-b7f2-51f5706b120b", "ssh_username": "debian", "domain_name" : "default", "flavor": "m1.medium", "networks": ["a1175c54-cb12-436d-ac7b-d327499dc39b"], "floating_ip_pool" : "public" } ], "provisioners": [ { "type": "ansible", "playbook_file": "./ansible/playbook.yml" } ], "post-processors": [ { "type": "manifest", "output": "manifest.json" } ] }

Slide 69

Slide 69 text

{ "builds": [ { "name": "openstack", "builder_type": "openstack", "build_time": 1508775293, "files": null, "artifact_id": "d534f1a9-1578-41ab-a071-c7a67bc9c24d", "packer_run_uuid": "cd0c6312-dd90-329f-60d4-c5445144ebec" }, { "name": "openstack", "builder_type": "openstack", "build_time": 1509053610, "files": null, "artifact_id": "ef90ad1c-ed64-4ae0-8283-e446e95c33e6", "packer_run_uuid": "b6000539-f3e6-85dd-2733-9fb3ae443e9f" } ], "last_run_uuid": "b6000539-f3e6-85dd-2733-9fb3ae443e9f" }

Slide 70

Slide 70 text

$ openstack image list +--------------------------------------+----------------------------------+--------+ | ID | Name | Status | +--------------------------------------+----------------------------------+--------+ | ef90ad1c-ed64-4ae0-8283-e446e95c33e6 | MyBuild-2017-10-26 02:31:24 | active | | aa0a5244-0d57-477d-b985-653d6b881292 | Windows-2012-R2 | active | | 31e84bbb-abbb-4d5a-b620-ecebf4697d16 | centos-6-64bit | active | | 9eac74f9-6e6c-45a9-bd93-915d3e390687 | centos-7-64bit | active | | 3a69a110-775f-41ad-9d63-32079db57203 | cirros-0.3.4-64bit | active | | 244cbbde-77b6-4f1e-837f-9250520ee78b | coreos-stable | active | | 1b9fe43e-4cf2-4986-b7f2-51f5706b120b | debian-jessie-64bit | active | | 690b063b-f239-4032-ad23-9ae6337f248f | debian-stretch-64bit | active | | d8034a10-9b15-46b1-9c68-bd98f92d0ffb | ubuntu-server-precise-lts-64-bit | active | | 040f9d1d-bb18-4466-abd7-9f2172e6db70 | ubuntu-server-trusty-lts-64-bit | active | | 5be2b652-a965-4ecb-a2b4-b9f83d7779e6 | ubuntu-server-xenial-lts-64-bit | active | +--------------------------------------+----------------------------------+--------+

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

Deploy the VM image

Slide 73

Slide 73 text

Orchestration

Slide 74

Slide 74 text

✓ Boot up webservers ✓ Configure firewalls ✓ Assign loadbalancers ✓ Link floating IP ✓ Assign SSH keys Orchestration

Slide 75

Slide 75 text

✓ CloudFormation (AWS) ✓ Heat (OpenStack) ✓ Resource manager (Azure) Vendor-specific orchestration tools

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

✓ Infrastructure As Code ✓ Plan, graph, execute ✓ terraform.tf file ✓ Multiple providers ✓ Incremental changes Terraform

Slide 78

Slide 78 text

✓ Alicloud ✓ Archive ✓ Arukas ✓ AWS ✓ Bitbucket ✓ CenturyLinkCloud ✓ Chef ✓ Circonus ✓ Cloudflare ✓ CloudStack ✓ Cobbler ✓ Consul ✓ Datadog ✓ DigitalOcean ✓ DNS ✓ DNSMadeEasy ✓ DNSimple ✓ Docker ✓ Dyn ✓ External ✓ Fastly ✓ GitHub ✓ Gitlab ✓ Google Cloud ✓ Grafana ✓ Heroku ✓ HTTP ✓ Icinga2 ✓ Ignition ✓ InfluxDB ✓ Kubernetes ✓ Librato ✓ Local ✓ Logentries ✓ LogicMonitor ✓ Mailgun ✓ Microsoft Azure ✓ Microsoft Azure (Legacy ASM) ✓ MySQL ✓ New Relic ✓ Nomad ✓ NS1 ✓ 1&1 ✓ Oracle Public Cloud ✓ OpenStack ✓ OpsGenie ✓ OVH ✓ Packet ✓ PagerDuty ✓ PostgreSQL ✓ PowerDNS ✓ ProfitBricks ✓ RabbitMQ ✓ Rancher ✓ Random ✓ Rundeck ✓ Scaleway ✓ SoftLayer ✓ StatusCake ✓ Spotinst ✓ Template ✓ Terraform ✓ Terraform Enterprise ✓ TLS ✓ Triton ✓ UltraDNS ✓ Vault ✓ VMware vCloud Director ✓ VMware vSphere Terraform providers

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

terraform.tf

Slide 81

Slide 81 text

variable image_id { default = "aa528a22-8bdf-47f3-ab3c-3513b1f19252" } variable flavor_id { default = "abadcff2-7c20-4e31-8234-a8dcb19de72a" } variable network_id { default = "a1175c54-cb12-436d-ac7b-d327499dc39b" } variable subnet_id { default = "2c380e2a-92cc-464e-b0b7-9142b4a88111" } variable public_key { default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/ gBW3E+AYITjeme6NRz5QdqTEox8WJxfq0/Hsdg8kzJB1bY3wpFV0ug0CMbAQpknpv/Ajma/ ptSlX0dQmqWBCTztV5inKFtYEnfbUNEAEaoE+ZzCDrcow+1m02XpMhqvwHcFUm4NJ8NwvKtiMqz6cIeg QD1bKThyy03LKO7lJgo3xoit+2ladj7x9HAoGk/ epRp4GmuJc1QiR2PgosrGKor8JVY2qUO0QqjFDi5jF3oB+RlTdiWzTSgzRxZW1tO1N/ jsW9FpgR0OVAVF3lp/ YSfqKgFZOKaeF5wxbTOyPf1aiVe9bqwFjaC5UIJVe+TojXCUR8cpU0egT6DphA6E9 [email protected]" }

Slide 82

Slide 82 text

provider "openstack" { user_name = "aaa" tenant_name = "aaa" password = "aaa" auth_url = "https://osp.combell.com:5000/v3" domain_name = "default" } resource "openstack_compute_keypair_v2" "key" { name = "key_${terraform.workspace}" public_key = "${var.public_key}" }

Slide 83

Slide 83 text

resource "openstack_compute_secgroup_v2" "secgroup" { name = "secgroup_${terraform.workspace}" description = "Security group that allows access to ports 80 and 22" rule { from_port = 22 to_port = 22 ip_protocol = "tcp" cidr = "0.0.0.0/0" } rule { from_port = 80 to_port = 80 ip_protocol = "tcp" cidr = "0.0.0.0/0" } } resource "openstack_compute_instance_v2" "web_1" { name = "web_1_${terraform.workspace}" image_id = "${var.image_id}" flavor_id = "${var.flavor_id}" key_pair = "${openstack_compute_keypair_v2.key.name}" security_groups = ["${openstack_compute_secgroup_v2.secgroup.name}"] network { uuid = "${var.network_id}" name = "private" } }

Slide 84

Slide 84 text

resource "openstack_compute_instance_v2" "web_2" { name = "web_2_${terraform.workspace}" image_id = "${var.image_id}" flavor_id = "${var.flavor_id}" key_pair = "${openstack_compute_keypair_v2.key.name}" security_groups = ["${openstack_compute_secgroup_v2.secgroup.name}"] network { uuid = "${var.network_id}" name = "private" } } resource "openstack_lb_loadbalancer_v2" "lb" { name = “lb_${terraform.workspace}" vip_subnet_id = "${var.subnet_id}" } resource "openstack_networking_floatingip_v2" "floatingip" { pool = "public" port_id = "${openstack_lb_loadbalancer_v2.lb.vip_port_id}" } output "address" { value = "${openstack_networking_floatingip_v2.floatingip.address}" }

Slide 85

Slide 85 text

resource "openstack_lb_listener_v2" "listener" { name = "listener_${terraform.workspace}" protocol = "HTTP" protocol_port = 80 loadbalancer_id = "${openstack_lb_loadbalancer_v2.lb.id}" } resource "openstack_lb_pool_v2" "pool" { name = "pool_${terraform.workspace}" protocol = "HTTP" lb_method = "ROUND_ROBIN" listener_id = "${openstack_lb_listener_v2.listener.id}" } resource "openstack_lb_monitor_v2" "monitor" { name = "monitor_${terraform.workspace}" pool_id = "${openstack_lb_pool_v2.pool.id}" type = "HTTP" url_path = "/" expected_codes = "200" http_method = "GET" delay = 20 timeout = 10 max_retries = 5 depends_on = ["openstack_compute_instance_v2.web_1","openstack_compute_instance_v2.web_2"] }

Slide 86

Slide 86 text

resource "openstack_lb_member_v2" "web_1_member" { address = "${openstack_compute_instance_v2.web_1.access_ip_v4}" protocol_port = 80 pool_id = "${openstack_lb_pool_v2.pool.id}" subnet_id = "${var.subnet_id}" depends_on = ["openstack_compute_instance_v2.web_1"] } resource "openstack_lb_member_v2" "web_2_member" { address = "${openstack_compute_instance_v2.web_2.access_ip_v4}" protocol_port = 80 pool_id = "${openstack_lb_pool_v2.pool.id}" subnet_id = "${var.subnet_id}" depends_on = ["openstack_compute_instance_v2.web_2"] }

Slide 87

Slide 87 text

$ terraform init Loads provider plugins for project

Slide 88

Slide 88 text

$ terraform providers . $"" provider.openstack

Slide 89

Slide 89 text

$ terraform plan

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

$ terraform graph | dot -Tpng > graph.png

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

$ terraform apply

Slide 94

Slide 94 text

delay: "" => "20" expected_codes: "" => "200" http_method: "" => "GET" max_retries: "" => "5" name: "" => "monitor_default" pool_id: "" => "36e94ffb-39c9-4741-9fdc-ef2f76f3dc38" region: "" => "" tenant_id: "" => "" timeout: "" => "10" type: "" => "HTTP" url_path: "" => "/" openstack_lb_member_v2.web_1_member: Still creating... (10s elapsed) openstack_lb_monitor_v2.monitor: Still creating... (10s elapsed) openstack_lb_member_v2.web_2_member: Still creating... (10s elapsed) openstack_lb_member_v2.web_1_member: Creation complete after 13s (ID: 526c0998- db35-48cc-86e0-012cc315144a) openstack_lb_member_v2.web_2_member: Creation complete after 13s (ID: 9dfd6de0- e731-4209-b134-024df2f246d4) openstack_lb_monitor_v2.monitor: Creation complete after 14s (ID: decbf0fe-30f5-4996-9af9-0e4b7dba2aae) Apply complete! Resources: 5 added, 0 changed, 0 destroyed. Outputs: address = 185.115.216.125

Slide 95

Slide 95 text

✓ vars.tf ✓ output.tf ✓ secgroup.tf ✓ keypair.tf ✓ compute.tf ✓ network.tf ✓ provider.tf Organize Terraform files

Slide 96

Slide 96 text

Multiple resources in 1 resource definition

Slide 97

Slide 97 text

resource "openstack_compute_instance_v2" "master" { count = "${var.servercount}" name = "${format("my-webserver-%02d", count.index+1)}" image_name = "${var.image}" flavor_name = "${var.flavor}" network { name = "${var.network}" } security_groups = ["${openstack_networking_secgroup_v2.web.id}"] key_pair = "my_keypair" }

Slide 98

Slide 98 text

variable "servercount" { default = "3" } variable "image" { default = "debian-stretch" } variable "flavor" { default = "m1.medium" } variable "network" { default = "private" } variable "float-pool" { default = "public" }

Slide 99

Slide 99 text

Remote state

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

Similar to etcd & zookeeper

Slide 102

Slide 102 text

terraform { backend "consul" { address = "127.0.0.1:8500" path = "example/terraform_state" } }

Slide 103

Slide 103 text

$ terraform init $ terraform workspace new wsp1 $ terraform workspace new wsp2 $ terraform workspace select wsp1 $ terraform plan $ terraform apply $ terraform workspace select wsp2 $ terraform plan $ terraform apply

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

Blue/green deployments

Slide 106

Slide 106 text

Build terraform script to relink floating IP

Slide 107

Slide 107 text

Or to change the DNS record AWS route53 DYN PowerDNS DNSimple DNSMadeEasy UltraDNS Custom DNS service

Slide 108

Slide 108 text

$ terraform workspace select wsp1 $ terraform destroy

Slide 109

Slide 109 text

There are way more features in Terraform for AWS, Azure & GCP

Slide 110

Slide 110 text

Hybrid solutions

Slide 111

Slide 111 text

https://feryn.eu https://twitter.com/ThijsFeryn https://instagram.com/ThijsFeryn

Slide 112

Slide 112 text

No content