The goal of Continuous Delivery is, briefly, to get features into your users' or customers' hands as quickly and confidently as possible. In order to succeed, Development and Operations teams need to align and come up with both working and deployable software in short, regular intervals. Chef, Puppet, Ansible & Co. enable teams to code up application runtime environments, but alone do not allow for building quality into their processes. In this presentation I will show how you can apply the "Red, Green, Refactor Cycle" of Test-Driven Development and combine it with your configuration management or orchestration tool of choice in order to come up with better infrastructure that can automatically be tested using Ansible, Test Kitchen, Docker, Serverspec and RSpec.
7. 7 #Dynatrace
Utmost Goal: Minimize Cycle Time
feature cycle time time
Customer
This is when you
create value!
minimize
8. 8 #Dynatrace
Utmost Goal: Minimize Cycle Time
feature cycle time time
Customer
You
This is when you
create value!
minimize
9. 9 #Dynatrace
Utmost Goal: Minimize Cycle Time
feature cycle time time
Customer
You
minimize
It’s about getting your features into your users’ hands
as quickly and confidently as possible!
12. 12 #Dynatrace
Align Development and IT Operations
IT OPERATIONS
DEVELOPMENT
current iteration
(e.g. 2-week time-box)
time
Planning
13. 13 #Dynatrace
Align Development and IT Operations
IT OPERATIONS
DEVELOPMENT
current iteration
(e.g. 2-week time-box)
time
Planning
Implementing
and testing
14. 14 #Dynatrace
Align Development and IT Operations
IT OPERATIONS
DEVELOPMENT
current iteration
(e.g. 2-week time-box)
time
Planning
Implementing
and testing
Working and
deployable code
17. 17 #Dynatrace
“Make it work. Make it right. Make it fast.”
Kent Beck, Creator of Extreme Programming and Test-Driven Development
Get the code to
operate correctly
Make the code clear,
enforce good design Optimize
18. 18 #Dynatrace
The Red, Green, Refactor Cycle of TDD
Write a Failing Test
Make the Test PassClean Up your Code
Small increments
Able to return to known working code
Designed and
tested code
Protects against regressions
19. 19 #Dynatrace
» Refactoring
» simplify
» modularize (use 3rd-party Ansible roles)
» Migrating to different Platforms
» OS
» Cloud Providers
» Migrating to different Automation Tool
» Ansible, Chef, Puppet
» Bash, Perl, etc.
Why you shouldn’t rely on a single tool?
20. 20 #Dynatrace
» Refactoring
» simplify
» modularize (use 3rd-party Ansible roles)
» Migrating to different Platforms
» OS
» Cloud Providers
» Migrating to different Automation Tool
» Ansible, Chef, Puppet
» Bash, Perl, etc.
Why you shouldn’t rely on a single tool?
With TDD you express your intentions twice:
once in the code and once in the test.
If they don’t match, tests fail and you’ve caught a bug!
24. 24 #Dynatrace
Drivers let you run your code on various...
Cloud Providers
» Azure, Cloud Stack, EC2, Digital Ocean, GCE, Rackspace,...
Virtualization Technologies
» Vagrant, Docker, LXC
Test Kitchen: Drivers
26. 26 #Dynatrace
Platforms are the Operating Systems you want to run on.
Platforms
» Linux- or Windows-based (since Test Kitchen 1.4.0)
How to manage dependencies?
» Automatically resolved when using Docker or Vagrant
» Build your own and link them in the configuration file
Test Kitchen: Platforms
28. 28 #Dynatrace
Provisioners are the tools used to converge the environment.
Provisioners
» Ansible, Chef, CFEngine, Puppet, SaltStack
Why cool?
» Useful if you need to support multiple of these tools
Test Kitchen: Provisioners
30. 30 #Dynatrace
Test Suites define the tests to run against each platform.
Test Frameworks
» Bash, Bats, Cucumber, RSpec, Serverspec
Test Kitchen: Test Suites
34. 34 #Dynatrace
Create an Ansible Role
Initialize Test Kitchen
$ mkdir –p ansible/roles/my-role
$ cd ansible/roles/my-role
Test Kitchen: Testing an Ansible Role
$ kitchen init --driver=docker --provisioner=ansible_playbook
create .kitchen.yml
create test/integration/default
Configuration goes here!
Tests go here!
35. 35 #Dynatrace
.kitchen.yml (as provided via `kitchen init`)
---
driver:
name: docker
provisioner:
name: ansible_playbook
platforms:
- name: ubuntu-14.04
- name: centos-7.1
suites:
- name: default
run_list:
attributes:
Test Kitchen: Testing an Ansible Role
Names resolve to
Docker Images on
the Docker Hub
37. 37 #Dynatrace
$ kitchen list
Instance Driver Provisioner Transport Last Action
default-ubuntu-1404 Docker AnsiblePlaybook Ssh <Not Created>
default-centos-71 Docker AnsiblePlaybook Ssh <Not Created>
`kitchen list`: List Test Kitchen Instances
Test Kitchen: Installation
This will change...Test Suite Platform
39. 39 #Dynatrace
Create an Ansible Playbook for Test Suite ‘default’
Test Kitchen: Testing an Ansible Role
$ kitchen init --driver=docker --provisioner=ansible_playbook
create .kitchen.yml
create test/integration/default
Configuration goes here!
Tests go here!
42. 42 #Dynatrace
RSpec is a TDD tool for Ruby programmers.
RSpec
require ‘foo’
describe Foo do
before do
@foo = Foo.new
end
it ‘method #bar does something useful’ do
@foo.bar.should eq ‘something useful’
end
end
43. 43 #Dynatrace
Serverspec is RSpec for your infrastructure.
Serverspec
require ‘serverspec’
describe user(‘foo’) do
it { should exist }
it { should belong_to_group ‘foo’ }
end
describe file(‘/opt/bar’) do
it { should be_directory }
it { should be_mode 777 }
it { should be_owned_by ‘foo’ }
it { should be_grouped_into ‘foo’ }
end
describe service(‘bar’) do
it { should be_enabled }
it { should be_running }
end
describe port(8080) do
it { should be_listening }
end
describe command(‘apachectl –M’) do
its(:stdout) { should contain(‘proxy_module’) }
end
Resource
Matcher
45. 45 #Dynatrace
`kitchen test`: Run Test Kitchen Tests
Test Kitchen: Testing an Ansible Role
$ kitchen test default-ubuntu-1404
$ kitchen test ubuntu
$ kitchen test
regex!
$ kitchen list
Instance Driver Provisioner Transport Last Action
default-ubuntu-1404 Docker AnsiblePlaybook Ssh <Not Created>
default-centos-71 Docker AnsiblePlaybook Ssh <Not Created>
46. 46 #Dynatrace
Test Kitchen: Stages
test = converge verify destroy
Instance created and provisioned
Instance tested and verified
47. 47 #Dynatrace
`kitchen verify`: Run Test Kitchen Tests
$ kitchen verify ubuntu
...
User "foo"
should exist
should belong to group "foo"
Finished in 0.14825 seconds (files took 0.6271 seconds to load)
2 examples, 0 failures
Finished verifying <default-ubuntu-1404> (0m37.21s).
Test Kitchen: Testing an Ansible Role
48. 48 #Dynatrace
`kitchen list`: List Test Kitchen Instances
Test Kitchen: Testing an Ansible Role
$ kitchen list
Instance Driver Provisioner Transport Last Action
default-ubuntu-1404 Docker AnsiblePlaybook Ssh Verified
default-centos-71 Docker AnsiblePlaybook Ssh <Not Created>
And as we are dealing with code - “infrastructure as code” namely – why shouldn’t we apply the same principles that help us create better software to create better infrastructure? After all, a bug in the environment may have more severe consequences than a bug in a software.