Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Incrementalism: An Industrial Strategy For Adopting Modern Automation

578 views

Published on

How can you adopt a modern automated application delivery pipeline? What does the end-to-end result look like?

Published in: Internet
  • Login to see the comments

Incrementalism: An Industrial Strategy For Adopting Modern Automation

  1. 1. ç INCREMENTALISM An Industrial Strategy For Adopting Modern Automation
  2. 2. MONOCULTURE TROUBLEMAKER RDBMS ARE RAD OPERATOR AND ENGINEER BACKGROUND
  3. 3. MONOCULTURE TROUBLEMAKER RDBMS ARE RAD OPERATOR AND ENGINEER BACKGROUND
  4. 4. Industrial Techno Revolution Development and Operational Practices
  5. 5. 1. Development Practices 2. Secrets Management 3. Packaging 4. Developer-centric, Self-Healing Applications 5. Data Center Aware Services 6. Infrastructure Manipulation
  6. 6. YOU ARE A BIT-CHUCKING TECHNO INDUSTRIALIST.
  7. 7. DATA CENTERS ARE YOUR FACTORIES. NETWORKS ARE YOUR ROADS. YOU APP PRODUCES WIDGETS. MICROSERVICES ARE YOUR ROBOTS ON THE FACTORY LINE.
  8. 8. YOU ARE A BIT-CHUCKING TECHNO INDUSTRIALIST. WIDGET SHIPPING ^
  9. 9. REDUNDANCY
  10. 10. CRITICAL INFRASTRUCTURE
  11. 11. PROFILE MESSAGES UPSELL CART RELATED COMMENTSSOCIAL HTML/JSON/gRPC Response
  12. 12. Response Microservices
  13. 13. HTML/JSON/gRPC Response MYAPP
  14. 14. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback
  15. 15. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback BUSINESS VALUE
  16. 16. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback INPUT
  17. 17. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback DEPENDENCY
  18. 18. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback PROPERTIES OF
 THE APPLICATION
  19. 19. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback VALUE
  20. 20. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback DISTRACTING, REQUIRED, NECESSARY COMPLEXITY
  21. 21. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback WIDGET
  22. 22. • New program! • Use a piece of user data • Talks to a database • Returns something useful • Highly-Available • Self-Healing • Feedback INDUSTRIAL COMPUTING RAW MATERIAL REDUNDANT ROBOTS REPLACEABLE PARTS QUALITY-MANAGEMENT WIDGET STORAGE
  23. 23. MY RESULT MYAPP
  24. 24. Codified Development Environment Reproducible Dev Environments Disposable R&D Workspace Shared Developer Workspace Developer-driven Infrastructure
  25. 25. Terminal $ $EDITOR Vagrantfile Vagrant.configure("2") do |config| config.vm.box = "ubuntu/xenial64" config.vm.box_url = "https://cloud-images.ubuntu.com/ xenial/current/xenial-server-cloudimg-amd64-vagrant.box" config.vm.network "private_network", ip: "192.168.33.10" config.vm.provision "shell", path: "setup.sh" end $ cat setup.sh apt-get install postgresql-server tmux
  26. 26. Terminal my-laptop$ vagrant up --destroy-on-error my-laptop$ vagrant ssh vm$ uname -a | tee /vagrant/uname.out Linux compton 2.6.24-19-server #1 SMP Sat Jul 12 00:40:01 UTC 2008 i686 GNU/Linux vm$ logout Shared connection to 192.168.39.130 closed. my-laptop$ cat uname.out Linux compton 2.6.24-19-server #1 SMP Sat Jul 12 00:40:01 UTC 2008 i686 GNU/Linux
  27. 27. Terminal $ $EDITOR Vagrantfile Vagrant.configure("2") do |config| config.ssh.shell = "sh" config.vm.synced_folder ".", "/vagrant", nfs: true, id: "vagrant-root" end
  28. 28. Terminal my-laptop$ $EDITOR myapp.go my-laptop$ GOOS=linux GOARCH=amd64 go build -o myapp-linux my-laptop$ GOOS=freebsd GOARCH=amd64 go build -o myapp-freebsd my-laptop$ vagrant ssh vm$ /vagrant/myapp-linux vm$ logout my-laptop$ vagrant up freebsd-vm1 my-laptop$ vagrant ssh freebsd-vm1 freebsd-vm1$ /vagrant/myapp-freebsd freebsd-vm1$ logout
  29. 29. $HOME/go/src/github.com/hashicorp/myapp/Vagrantfile
  30. 30. Secret Sprawl Break Glass Procedures Audit Logs Secrets Lifecycle Management
  31. 31. "I want to deploy this app to prod. Password-less logins are disabled on the databases! Now what?"
  32. 32. "I want to deploy this app to prod. Password-less logins are disabled on the databases! Now what?" Private GitHub repo Commit passwords inline in SCM Switch creds based on $HOSTNAME? Establish a protocol for acquiring credentials at runtime
  33. 33. Terminal $ vault read postgresql/creds/readonly Key Value --- ----- lease_id postgresql/creds/readonly/5fec46f2-ab40-d9b8-61a2-887c7946eeb6 lease_duration 1h0m0s lease_renewable true password f8a93086-b11d-10cd-8795-f537a10de712 username token-9e57c18f-ac99-8e29-48f2-3fb09066d2b4
  34. 34. Terminal $ VAULT_ADDR=http://vault.service.consul vault read postgresql/creds/readonly Key Value --- ----- lease_id postgresql/creds/readonly/5fec46f2-ab40-d9b8-61a2-887c7946eeb6 lease_duration 1h0m0s lease_renewable true password f8a93086-b11d-10cd-8795-f537a10de712 username token-9e57c18f-ac99-8e29-48f2-3fb09066d2b4
  35. 35. Terminal $ psql -U postgres psql (9.6.1) Type "help" for help. postgres=# du Role name | Attributes | Member of -------------------------------------------+--------------------------+------------ postgres | Superuser, Create ... | {} token-9e57c18f-ac99-8e29-48f2-3fb09066d2b4 | Password valid until ... | {}
  36. 36. Terminal $ vault renew postgresql/creds/readonly/5fec46f2-ab40-d9b8-61a2-887c7946eeb6 Key Value --- ----- lease_id postgresql/creds/readonly/5fec46f2-ab40-d9b8-61a2-887c7946eeb6 lease_duration 1h0m0s lease_renewable true
  37. 37. Terminal $ cat myapp-db-config.yml.ctmpl --- {{- with secret "postgresql/creds/readonly" }} username: "{{ .Data.username }}" password: "{{ .Data.password }}" database: "myapp" {{- end }} $ consul-template -template="myapp-db-config.yml.ctmpl:myapp-db-config.yml" ./myapp <CTRL+C> Received interrupt, cleaning up...
  38. 38. Terminal $ vault write postgresql/roles/readonly sql="CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";" Success! Data written to: postgresql/roles/readonly
  39. 39. Terminal $ tee my-policy.vault | vault write postgresql/roles/readonly sql=- CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}"; Success! Data written to: postgresql/roles/readonly
  40. 40. v2.0.0
  41. 41. Codified Build Environment Reproducible Packaging Shared Packaging Instructions Developer-driven Build and Packaging Steps
  42. 42. compile.json 1/3 { "builders": [{ "name": "myapp", "type": "docker", "image": "centos:6", "commit": true, "privileged": true }], "provisioners": [ { "type": "file", "source": "myapp-linux", "destination": "/usr/local/bin/myapp" }, { "type": "file", "source": "local-config-file.repo", "destination": "/usr/local/etc/myapp.conf" }, { "type": "file", "source": "start_myapp.sh", "destination": "/sbin/start_myapp" },
  43. 43. compile.json 2/3 { "type": "shell", "inline": [ "/usr/bin/yum -y update", "/usr/bin/yum -y install util-linux-ng patch", "/bin/chmod 0600 /usr/local/etc/myapp.conf", "/bin/chmod 0744 /sbin/start_myapp /usr/local/bin/myapp-linux", "/usr/bin/curl -o /usr/local/etc/some-ca.crt https://host.example.com/pki/ ca.crt", ] } ], "post-processors": [ [ { "type": "docker-tag", "repository": "myorg/myapp" }, { "type": "docker-save", "path": "myapp.tar" },
  44. 44. compile.json 3/3 { "type": "artifice", "files": ["myapp.tar"] }, { "type": "compress", "output": "myapp.tar.gz", "compression_level": 9 }, { "type": "atlas", "artifact": "myorg/myapp", "artifact_type": "archive", "metadata": { "created_at": "{{ timestamp }}" } } ] ] }
  45. 45. compile.json 1/3 { "builders": [{ "name": "myapp", "type": "docker", "image": "centos:6", "commit": true, "privileged": true }], "provisioners": [ { "type": "shell", "scripts": [ "setup.sh", "prod-app-script.sh" ] }
  46. 46. v2.0.0
  47. 47. v1.1.2 v2.0.0
  48. 48. What's a Cluster Scheduler?
  49. 49. redis.job job "redis" { datacenters = ["asia-east1", "asia-northeast1"] task "redis" { driver = "docker" config { image = "redis:latest" } resources { cpu = 500 # Mhz memory = 256 # MB network { mbits = 10 port "redis" {} } } } }
  50. 50. redis-service.job job "redis" { datacenters = ["asia-east1", "asia-northeast1"] task "redis" { service { name = "redis" # redis.service.consul port = "redis" check { type = "tcp" interval = "30s" timeout = "2s" } } ... resources { network { mbits = 10 port "redis" { static = "6379" } } }
  51. 51. Declare what you want to run
  52. 52. Scheduler determines where and manages how to run
  53. 53. v1.1.2 QTY: 1
  54. 54. Developer-centric Release Management Reproducible Runtime Environments Provider Agnostic Runtime Native Hybrid-Cloud Consumption Model Self-Healing Infrastructure * Service Discovery and Secure Introduction Support
  55. 55. myapp.job job "myapp" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 1 task "api" { driver = "docker" artifact { source = "https://s3.amazonaws.com/myorg/myapp.tar.gz" options { archive = "tar.gz" } } ...
  56. 56. myapp.job config { load = ["myapp.tar"] image = "myorg/myapp" command = "/sbin/start_myapp" args = [ "-mode=api" ] network_mode = "host" pid_mode = "host" } service { name = "${TASKGROUP}" # myapp.service.consul tags = [ "api" ] # api.myapp.service.consul port = "api" check { type = "http" path = "/health.txt" interval = "5s" timeout = "2s" } } }
  57. 57. myapp.job task "web" { driver = "docker" config { load = ["myapp.tar"] image = "myorg/myapp" command = "/sbin/start_myapp" args = [ "-mode=web" ] network_mode = "host" pid_mode = "host" } service { name = "${TASKGROUP}" # myapp.service.consul tags = [ "web" ] # web.myapp.service.consul port = "web" check { type = "http" path = "/health.txt" interval = "5s" timeout = "2s" } }
  58. 58. myapp.job $ nomad plan myapp.job $ nomad run -check-index 12515398 myapp.job
  59. 59. v1.1.2 v2.0.0 QTY: 0QTY: 20
  60. 60. myapp-green.job job "myapp-green" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 19 task "api" { driver = "docker" artifact { source = "https://s3.amazonaws.com/myorg/myapp-v123.tar.gz" options { archive = "tar.gz" } } ...
  61. 61. myapp-blue.job job "myapp-blue" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 1 task "api" { driver = "docker" artifact { source = "https://s3.amazonaws.com/myorg/myapp-v124.tar.gz" options { archive = "tar.gz" } } ...
  62. 62. myapp-blue.job $ nomad plan myapp-blue.job + Job: "myapp-blue" + Task Group: "myapp" (1 create) + Task: "api" (forces create) Scheduler dry-run: - All tasks successfully allocated.
  63. 63. 100% Green 95% Green 70% Green 90% Blue 100% Bluegreen: myapp-v123 blue: myapp-v124
  64. 64. v1.1.2 v2.0.0 QTY: 0QTY: 20
  65. 65. myapp-green.job job "myapp-green" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 0 task "api" { driver = "docker" artifact { source = "https://s3.amazonaws.com/myorg/myapp-v123.tar.gz" options { archive = "tar.gz" } } ...
  66. 66. myapp-blue.job job "myapp-blue" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 20 task "api" { driver = "docker" artifact { source = "https://s3.amazonaws.com/myorg/myapp-v124.tar.gz" options { archive = "tar.gz" } } ...
  67. 67. myapp-blue.job job "myapp-blue" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" update { # Stagger updates every 120 seconds stagger = "120s" # Update a single task at a time max_parallel = 1 } ...
  68. 68. myapp-blue.job $ nomad status myapp-blue ID = myapp-blue Name = myapp-blue Type = service Priority = 50 Datacenters = asia-east1 Status = running Periodic = false Summary Task Group Queued Starting Running Failed Complete Lost myapp 0 0 1 0 0 0 Allocations ID Eval ID Node ID Task Group Desired Status Created At 24cfd201 81efc2fa 8d0331e9 myapp run running 11/11/16 21:03:19 AEDT
  69. 69. myapp-blue.job $ nomad alloc-status --verbose a7365fe4 ID = a7365fe4-cb28-a6e9-f3d4-f99e49c89776 Eval ID = c3c9a1db-dbeb-8afa-0a83-4f1b8b5a03f5 Name = myapp-blue.myapp[0] Node ID = 1f029d38-8d4b-a552-261f-e457b60f9b4b Job ID = myapp-blue Client Status = running Created At = 11/11/16 22:04:53 AEDT Evaluated Nodes = 1 Filtered Nodes = 0 Exhausted Nodes = 0 Allocation Time = 1.085001ms Failures = 0 ==> Task Resources Task: "api" CPU Memory MB Disk MB IOPS Addresses 500 256 300 0 db: 127.0.0.1:38537 Task: "web" CPU Memory MB Disk MB IOPS Addresses
  70. 70. Terminal $ vault read postgresql/creds/readonly Key Value --- ----- lease_id postgresql/creds/readonly/5fec46f2-ab40-d9b8-61a2-887c7946eeb6 lease_duration 1h0m0s lease_renewable true password f8a93086-b11d-10cd-8795-f537a10de712 username token-9e57c18f-ac99-8e29-48f2-3fb09066d2b4
  71. 71. Terminal $ env VAULT_TOKEN=.... vault read postgresql/creds/readonly Key Value --- ----- lease_id postgresql/creds/readonly/5fec46f2-ab40-d9b8-61a2-887c7946eeb6 lease_duration 1h0m0s lease_renewable true password f8a93086-b11d-10cd-8795-f537a10de712 username token-9e57c18f-ac99-8e29-48f2-3fb09066d2b4
  72. 72. myapp.job job "myapp" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 1 task "api" { driver = "docker" env { VAULT_TOKEN = "7ea47d76-a653-4d43-9507-dbeed3b3747f" } artifact { source = "https://s3.amazonaws.com/myorg/myapp.tar.gz" options { archive = "tar.gz" } }
  73. 73. myapp.job job "myapp" { region = "apac" datacenters = ["asia-east1", "asia-northeast1"] type = "service" group "myapp" { count = 1 task "api" { driver = "docker" vault { policies = ["myapp", "api"] change_mode = "signal" change_signal = "SIGUSR1" } artifact { source = "https://s3.amazonaws.com/myorg/myapp.tar.gz" options { archive = "tar.gz" }
  74. 74. Containerized Virtualized Standalone Docker Windows Server Containers Qemu / KVM Hyper-V Xen Java Jar Static Binaries C# Rkt
  75. 75. Key Value Store HTTP API Host & Service Level Health Checks Datacenter Aware Service Discovery HTTP + DNS
  76. 76. CLIENT CLIENT CLIENT CLIENT CLIENT CLIENT SERVER SERVER SERVER REPLICATION REPLICATION RPC RPC LAN GOSSIP
  77. 77. CLIENT CLIENT CLIENT CLIENT CLIENT CLIENT SERVER SERVER SERVER REPLICATION REPLICATION RPC RPC LAN GOSSIP SERVERSERVER SERVER REPLICATION REPLICATION WAN GOSSIP
  78. 78. DB 1 DB 2 DB N HEALTH CHECKING SERVICE "Are you healthy?" "What about you?" "Yessir!" "Nah"
  79. 79. DB 1 DB 2 DB N HEALTH CHECKING SERVICE 1,000'S OF REQUESTS
  80. 80. CONSUL DB 1 DB 2 DB N My status has changed
  81. 81. CONSUL DB 1 DB 2 DB N 10'S OF REQUESTS
  82. 82. v1.1.2 QTY: 0QTY: 20 v2.0.0
  83. 83. v1.1.2 QTY: 0QTY: 20 v2.0.0
  84. 84. Terminal $ terraform plan -var-file=yow2016.tfvars -out=yow2016.tfplan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. Your plan was also saved to the path below. Call the "apply" subcommand with this plan file and Terraform will exactly execute this execution plan. Path: yow2016.tfplan + consul_key_prefix.myservice_config datacenter: "<computed>" path_prefix: "myservice/mycomponent/" subkeys.%: "3" subkeys.appParam1: "val1" subkeys.appParam2: "var2" subkeys.dbHostname: "my-db.service.consul" Plan: 1 to add, 0 to change, 0 to destroy.
  85. 85. Terminal $ cat myservice-consul-kv-config.tf variable "path_prefix" { default = "myservice/mycomponent" } resource "consul_key_prefix" "myservice_config" { path_prefix = "${var.path_prefix}/" subkeys = { "appParam1" = "val1" "appParam2" = "var2" "dbHostname" = "my-db.service.consul" } }
  86. 86. Terminal $ git diff myservice-consul-kv-config.tf diff --git a/myservice-consul-kv-config.tf b/myservice-consul-kv-config.tf index 76533d8..990d595 100644 --- a/myservice-consul-kv-config.tf +++ b/myservice-consul-kv-config.tf @@ -5,7 +5,5 @@ resource "consul_key_prefix" "myservice_config" { "appParam1" = "val1" "appParam2" = "var2" "dbHostname" = "my-db.service.consul" + "dbHostnameFollower" = "slave.my-db.query.consul" + "dbHostnameLeader" = "master.my-db.query.consul" } }
  87. 87. Terminal $ terraform plan -var-file=yow2016.tfvars -out=yow2016.tfplan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. consul_key_prefix.myservice_config: Refreshing state... (ID: myservice/mycomponent/) Your plan was also saved to the path below. Call the "apply" subcommand with this plan file and Terraform will exactly execute this execution plan. Path: yow2016.tfplan ~ consul_key_prefix.myservice_config subkeys.%: "3" => "5" subkeys.dbHostnameFollower: "" => "slave.my-db.query.consul" subkeys.dbHostnameLeader: "" => "master.my-db.query.consul" Plan: 0 to add, 1 to change, 0 to destroy.
  88. 88. Terminal $ terraform apply yow2016.tfplan consul_key_prefix.myservice_config: Modifying... subkeys.%: "3" => "5" subkeys.dbHostnameFollower: "" => "slave.my-db.query.consul" subkeys.dbHostnameLeader: "" => "master.my-db.query.consul" consul_key_prefix.myservice_config: Modifications complete Apply complete! Resources: 0 added, 1 changed, 0 destroyed. The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command. State path: terraform.tfstate
  89. 89. Terminal $ terraform fmt cat myservice-consul-kv-config.tf cat myservice-consul-kv-config.tf $ cat cat myservice-consul-kv-config.tf resource "consul_key_prefix" "myservice_config" { path_prefix = "${var.path_prefix}/" subkeys = { "appParam1" = "val1" "appParam2" = "var2" "dbHostname" = "my-db.service.consul" "dbHostnameFollower" = "slave.my-db.query.consul" "dbHostnameLeader" = "master.my-db.query.consul" }
  90. 90. Terminal $ cat myservice-consul-kv-config.tf variable "path_prefix" { default = "myservice/mycomponent" } variable "service_db_name" {} resource "consul_key_prefix" "myservice_config" { path_prefix = "${var.path_prefix}/" subkeys = { "appParam1" = "val1" "appParam2" = "var2" "dbHostname" = "${var.service_db_name}.service.consul" "dbHostnameFollower" = "slave.${var.service_db_name}.query.consul" "dbHostnameLeader" = "master.${var.service_db_name}.query.consul" } }
  91. 91. Terminal $ cat yow2016.tfvars "address" = "127.0.0.1:8500" "datacenter" = "yow2016" "token" = "" "service_db_name" = "my-db"
  92. 92. Terminal $ terraform plan -var-file=yow2016.tfvars -out=yow2016.tfplan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. consul_key_prefix.myservice_config: Refreshing state... (ID: myservice/mycomponent/) No changes. Infrastructure is up-to-date. This means that Terraform could not detect any differences between your configuration and the real physical resources that exist. As a result, Terraform doesn't need to do anything.
  93. 93. Terminal $ cat myservice-consul-kv-config.tf variable "db_leader_tag" { default = "leader" } variable "db_follower_tag" { default = "follower" } # snip resource "consul_key_prefix" "myservice_config" { path_prefix = "${var.path_prefix}/" subkeys = { "appParam1" = "val1" "appParam2" = "var2" "dbHostname" = "${var.service_db_name}.service.consul" "dbHostnameFollower" = "${var.db_follower_tag}.${var.service_db_name}.query.consul" "dbHostnameLeader" = "${var.db_leader_tag}.${var.service_db_name}.query.consul" } }
  94. 94. Terminal % git diff diff --git a/myservice-consul-kv-config.tf b/myservice-consul-kv-config.tf index 76590ef..e22eff0 100644 --- a/myservice-consul-kv-config.tf +++ b/myservice-consul-kv-config.tf @@ -1,9 +1,9 @@ variable "db_leader_tag" { - default = "leader" + default = "rw" } variable "db_follower_tag" { - default = "follower" + default = "ro" } variable "path_prefix" {
  95. 95. Terminal $ terraform plan -var-file=yow2016.tfvars -out=yow2016.tfplan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. consul_key_prefix.myservice_config: Refreshing state... (ID: myservice/mycomponent/) Your plan was also saved to the path below. Call the "apply" subcommand with this plan file and Terraform will exactly execute this execution plan. Path: yow2016.tfplan ~ consul_key_prefix.myservice_config subkeys.dbHostnameFollower: "follower.my-db.query.consul" => "ro.my-db.query.consul" subkeys.dbHostnameLeader: "leader.my-db.query.consul" => "rw.my-db.query.consul" Plan: 0 to add, 1 to change, 0 to destroy. $ git reset --hard HEAD is now at 2ab88f9 Revise terminology from master/slave to leader/follower
  96. 96. 1. Codify Everything 2. Pre-Plan outcomes at build-time 3. Create reproducible artifacts 4. Idempotent APIs and Tooling 5. Developer-Centric Operations 6. Make small, well understood changes changes 7. Start where it makes sense for your organization
  97. 97. CONTACT INFO @SeanChittenden sean@hashicorp.com THANK YOU! Questions?
  98. 98. IMBUED TRUST INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  99. 99. SMALL SUCCESS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 VAULT
  100. 100. WIDE EYES INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 VAULT
  101. 101. HA BACKEND INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 VAULT
  102. 102. ROBUSTVAULT! INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 VAULT
  103. 103. HA CONSUL + HAVAULT INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 VAULT
  104. 104. SECRETS AT LAST INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 SECRETS VAULT
  105. 105. AUTOMATION INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 NOMAD SECRETS VAULT
  106. 106. FULL STACK VALUE INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 BUSINESS OBJECTIVE MYAPP NOMAD SECRETS VAULT
  107. 107. RISK MITIGATED INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 BUSINESS OBJECTIVE MYAPP NOMAD SECRETS VAULT SECRETS CONSUL CLUSTERAPPLICATION CONSUL CLUSTER
  108. 108. SELF-HEALING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 TRIAGE DIAGNOSE TREATPREVENT
  109. 109. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  110. 110. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION
  111. 111. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION PLATFORM
  112. 112. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION PLATFORM APP
  113. 113. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION PLATFORM APP "Easy"
  114. 114. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION PLATFORM APP "Easy" Tough
  115. 115. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION PLATFORM APP "Easy" Hard Tough
  116. 116. SELF-ASSEMBLING SYSTEMS INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 FOUNDATION PLATFORM APP
  117. 117. ERROR BUDGET INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  118. 118. ERROR BUDGET INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 Big Budget
 Less Important Smaller Budget
 More Important
  119. 119. PLAN FOR KNOWN FAILURE INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  120. 120. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 PLAN FOR KNOWN FAILURE
  121. 121. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 KNOWN KNOWNS PLAN FOR KNOWN FAILURE
  122. 122. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 KNOWN UNKNOWN PLAN FOR KNOWN FAILURE
  123. 123. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 PLAN FOR KNOWN FAILURE
  124. 124. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 UNKNOWN UNKNOWN PLAN FOR KNOWN FAILURE
  125. 125. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 PLAN FOR KNOWN FAILURE
  126. 126. INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 PLAN FOR KNOWN FAILURE
  127. 127. RISK MANAGEMENT INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  128. 128. RISK MANAGEMENT INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 Insiders OpenSSL Application
 Vulnerabilities
  129. 129. RISK MANAGEMENT INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  130. 130. AUTOMATION INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2
  131. 131. AUTOMATION INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 GOOD BAD UGLY
  132. 132. EMBRACE AUTOMATION INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2 Creative Industrious Lazy Mental Drift
  133. 133. • Self-Healing • Self-Assembly • Error Budgeting • Failure Planning • Risk Management • Automation THINGS WE EMBRACE INCREMENTALISM LIFE CYCLE CODIFY EXAMPLE 1TENETS EXAMPLE 2

×