Infrastructure as Code
Bruno Devic // Monobit Solutions Ltd bdevic@monobit.co
What is it?
ONE OF THE ASPECTS OF ...
Continuous DELIVERY
Set of practices and principles aimed at, building, testing and releasing software faster and more frequently.
How long would it take your organization to deploy a change that involves just one single line of code? Do you do this on a repeatable, reliable basis?
TARGET
better project tracking
release frequently
done means done
reduce risk of release
increase quality
early integration
deploy less
reduce cycle time
better planning
build the minimum viable product
reduce WIP
BOTTOM LINE

releases must be boring
the system must always be releasable
every build is a potential release candidate
SOME PERSPECTIVE
WHERE IS ContinUous DELIVERY

WHERE IS INFRASTRUCTURE AS CODE

NOT THERE YET...
CONFIGURATION MANAGEMENT
version everything
database
application configuration
infrastructure
dependencies
externalize configuration
have reproducable infrastructure
devops
Infrastructure as CODE
Building and maintaining infrastructure resembles the way software developers build and maintain application source code
Infrastructure code needs to be version controlled, tested, maintained, reviewed, deployed and crafted as regular source code
Why is it useful
single point of truth
versioning environments
standard format to describe infrastructure
fast deployment of infrastructure changes
scalable infrastructure automation
stop configuration drift
TOOLSET

VAGRANT 101
open-source (MIT) tool for building and managing virtualized development environments
synthetic sugar around VMs and provisioning
written in ruby
runs on windows, linux, mac os x
extensible via plugins
easy to use and configure
CONCEPTS
pre-packaged base virtual machine
virtualization technology running the VM
- virtualbox (default), vmware, aws, docker, lxc, kvm, cloudstack, etc.
alter the virtual machine to a desired state
- file, shell, ansible, puppet, cfengine, chef, salt, etc.
BASIC USAGE
vagrant box add base http://files.vagrantup.com/lucid32.box
// download predefined vm and register as 'base'
vagrant init
// create default Vagrantfile
vagrant up
// unpackage box, create vm from box, start VM and, if first run, provision vm
vagrant status
// check status of vm defines in Vagrantfile
vagrant ssh
// ssh to running vm
vagrant provision
// run provisioner(s) specified in Vagrantfile
vagrant halt
// stop a running vm
vagrant destroy
// stop and delete vm
vagrant reload
// restart vm using new Vagrantfile
vagrant suspend
// suspend vm
vagrant resume
// resume vm
BENEFITS
reduced setup time
isolation
each project has its own isolated env
CONSISTENCY
exact same vm available to all
REPRODUCIBILITY
up, destroy, up, destroy
DISTRIBUTABLE
easy to transfer to all targets
MORE ADVANCED EXAMPLE
# Vagrantfile to create images that run WebSphere Application Server
Vagrant.configure("2") do |config|
config.ssh.forward_x11 = true
ips = {
:was6nd => "10.10.10.4",
:was6sa => "10.10.10.6",
:was7nd => "10.10.10.2",
:was7sa => "10.10.10.7",
:was8nd => "10.10.10.3",
:was8sa => "10.10.10.5",
:was85nd => "10.10.10.8",
:was85sa => "10.10.10.9"
}
[:was6nd, :was6sa, :was7nd, :was7sa, :was8nd, :was8sa, :was85nd, :was85sa].collect do |version|
config.vm.define version do |was_config|
was_config.vm.network :private_network, ip: ips[version]
was_config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "4096"]
vb.customize ["modifyvm", :id, "--name", ENV['VM_PREFIX'].to_s + version.to_s]
end
was_config.vm.box = "basebox"
was_config.vm.box_url = "http://monobit.co/vagrant/basebox.box"
was_config.vm.synced_folder ENV["CATALOG"], "/catalog"
was_config.vm.synced_folder "../../scripts/files", "/librarian-files"
was_config.vm.provision :shell, :path => "../../scripts/librarian.sh"
was_config.vm.provision :puppet do |puppet|
puppet.manifests_path = "manifests"
puppet.manifest_file = "#{version.to_s}-install.pp"
end
end
end
end
EcosySTEM
BOX REPOS

CONCEPTS
Declarative language
file, service, user, package
tell what state you want, not how
Idempotence
B(file1, file2, service1) -- no change --> B(file1, file2, service1)
CONVERGENCE
A (file1) -- state converges --> B(file1, file2, service1)

PUPPET 101
configuration management system that allows you to define the state of your IT infrastructure, then automatically enforces the correct state
Apache 2.0 open source, first created in 2005
declarative language based on Ruby
client-server and standalone deployment model
CONCEPTS
describes an aspect of a system - file, service, package etc., resource types and attributes are predefined
execution order must be explicitly defined
puppet program, has .pp extension, it contains one or more classes
classes are groups of resources, e.g. DB server, load-balancer; classes are organized into modules and are singletons
type { 'title':
attribute => value,
}
CONCEPTS CONT.
custom resource like types, very similar to classes but can be used multiple times
organize, distribute and reuse puppet code
my_module
- manifests # puppet code stored here (classes, types etc.)
- files # static config file
- templates #ruby erb config files
- lib # custom functions, facts, providers
- tests # simple manifest for manual testing
- spec # automated tests
class nginx {
# Install the nginx package. This relies on apt-get update
package { 'nginx':
ensure => 'present',
require => Exec['apt-get update'],
}
# Make sure that the nginx service is running
service { 'nginx':
ensure => running,
require => Package['nginx'],
}
# Add a vhost template
file { 'vagrant-nginx':
path => '/etc/nginx/sites-available/localhost',
ensure => file,
source => 'puppet:///modules/nginx/localhost',
require => Package['nginx'],
notify => Service['nginx'],
}
# Disable the default nginx vhost
file { 'default-nginx-disable':
path => '/etc/nginx/sites-enabled/default',
ensure => absent,
require => Package['nginx'],
}
# Symlink our vhost in sites-enabled to enable it
file { 'vagrant-nginx-enable':
path => '/etc/nginx/sites-enabled/localhost',
target => '/etc/nginx/sites-available/localhost',
ensure => link,
notify => Service['nginx'],
require => [
File['vagrant-nginx'],
File['default-nginx-disable']
],
}
}EXAMPLE
SOME RESOURCE TYPES
service { 'apmd':
ensure => 'running',
enable => 'true',
}package { 'ampd':
ensure => installed
}user { 'foo':
ensure => present,
uid => '507',
gid => 'admin',
shell => '/bin/zsh',
home => '/home/foo',
managehome => true,
}file { "/etc/init.d/tomcat":
source => "puppet:///modules/tomcat/tomcat",
group => 'root',
owner => 'root',
mode => 'ugo+x,go-w,go+r',
}group { 'foo':
ensure => present
}exec { "extract-tomcat-server":
command => "tar -xvzf 'apache-tomcat-8.0.8.tar.gz' -C /opt",
creates => "/opt/${tomcat_dir}",
}IMPORTANT METAPARAMETERS
type { 'some_type':
require => ...,
before => ...,
notify => ...,
subscribe => ...,
alias => ...,
schedule => ...
}
also possible to model via chaining operators -> and ~>
group { 'tomcat_group':
name => 'tomcat',
ensure => 'present'
} ->
user { 'tomcat_user':
name => 'tomcat',
ensure=> 'present',
gid => 'tomcat'
}
DOCKER 101
Docker is an open-source engine that automates the deployment of any application as a lightweight, portable, self-sufficient container that will run virtually anywhere.
Docker brings LXC to the masses
Docker first started in 2013 and is very HOT at the moment
500+ commiters
support from major tech companies (Google, RedHat, Microsoft, IBM, RackSpace etc.)
fast growing ecosystem
WHY CONTAINERS ?
DEPENDENCY HELL MATRIX

UNIVERSAL CONTAINER

CONTAINERS vs. VMs

VM without the overhead of a VM
Processes are isolated, but run straight on the host
BENEFITS
more efficient, consistent, and repeatable
no configuration drift between envs
you package it, i'll ship it
improved speed, reliability, scalability and portability
IMAGE STACKING, easy and fast to deploy changes
QUICK START
$ docker search ubuntu # search docker.io hub for all ubuntu images
// lots of results
$ docker pull ubuntu:latest # download image locally
ubuntu:latest: The image you are pulling has been verified
d497ad3926c8: Pull complete
ccb62158e970: Pull complete
e791be0477f2: Pull complete
3680052c0f5c: Pull complete
22093c35d77b: Pull complete
5506de2b643b: Pull complete
511136ea3c5a: Already exists
Status: Downloaded newer image for ubuntu:latest
$ docker images # list local images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu latest 5506de2b643b 5 days ago 199.3 MB
$ docker run ubuntu echo "Hello world" # run container, execute command and stop container
Hello world
§ docker run -i -t ubuntu /bin/bash # run container in interactive mode
root@b38ea8c7b345:/#dOCKER CLI
$ docker search # search docker.io hub
$ docker pull # download image
$ docker push # upload image
$ docker images # list local images
$ docker build # builds image from Dockerfile
$ docker rmi # remove image
$ docker ps # list containers
$ docker run # initiates a container from image
- d # run in daemon mode
- i -t # run in interactive mode
- p <host>:<guest> # expose port to host
$ docker start / stop / kill # control existing container
$ docker attach # connect to container
$ docker rm # remove containerMANUAL PROVISIONING IS JUST BAD
Dockerfile
instructions how to automatically build an image
FROM # defines base image
MAINTAIN # authod metadata
ADD # add local file to image
RUN # execute command
ENV # set env variable
EXPOSE # expose a port
CMD # default command to execute on run
VOLUME # create a mount point
SYNTAX
$ docker build -t <tag> .MORE ADVANCED SCENARIOS
linking containers together
$ docker run -d --name db bdevic/postgres
$ docker run -d -P --name web --link db:db bdevic/webapp python app.py
# exposes ports from db to webapp, creates env variables and updates hosts
Storing data with mapped data volumes
$ docker run -d -P --name web -v /src/webapp:/opt/webapp bdevic/webapp python app.py
# map /src/webapp from host to /opt/webapp, bypasses the union filesystem
Storing data with DATA CONTAINERS
$ docker run -d -v /dbdata --name dbdata bdevic/postgres # data-only container
$ docker run -d --volumes-from dbdata --name real-db bdevic/postgres
# mounts the /dbdata volume from the dbdata container

THANK YOU!
Infrastructure as Code
By Bruno Dević
Infrastructure as Code
- 537