infrastructure as code

development environment

this is your first day at work

let's fetch the app and make it work

install a package manager

don't fear the command line

on windows, run console as administrator

turn Hyper-V off when using Virtualbox and reboot

$ bcdedit /set hypervisorlaunchtype off

to turn Hyper-V back on

$ bcdedit /set hypervisorlaunchtype auto

install curl

$ choco install curl -y
$ brew install curl
$ sudo apt-get install curl

$ curl --version
curl 7.30.0 (i386-pc-win32) libcurl/7.30.0 OpenSSL/0.9.8{ zlib/1.2.7
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IPv6 Largefile NTLM SPNEGO SSL SSPI libz
						

install git

$ choco install git -params "/GitAndUnixToolsOnPath" -y
$ brew install git
$ sudo apt-get install git

$ git --version
git version 1.9.4.msysgit.2
						

install virtualbox

$ choco install virtualbox -y
$ brew cask install virtualbox
$ sudo apt-get install virtualbox

$ virtualbox --help
Oracle VM VirtualBox Manager 4.3.24
						

install vagrant

$ choco install vagrant -y
$ brew install vagrant
$ sudo apt-get install vagrant

$ vagrant --version
Vagrant 1.6.5
						

install node.js

$ choco install nodejs -y
$ brew install nodejs
$ curl -sL https://deb.nodesource.com/setup | sudo bash -
$ sudo apt-get install nodejs
$ sudo apt-get install build-essential

$ node --version
v0.12.2
						

$ npm --version
2.7.5
						

install bower

 $ npm install --global bower
$ sudo npm install --global bower

$ bower --version
1.4.1
						

install gulp

 $ npm install --global gulp
$ sudo npm install --global gulp

$ gulp --version
[18:08:14] CLI version 3.8.11
						

clone and serve todomvc

$ git clone https://github.com/tastejs/todomvc.git
$ cd todomvc
$ npm install
$ bower install

$ gulp serve
[08:05:18] Using gulpfile ~/Dropbox/Projects/todomvc/gulpfile.js
[08:05:18] Starting 'serve'...
[08:05:18] Finished 'serve' after 3.28 ms
						

$ curl --silent localhost:8000
<!doctype html>
...
						

$ curl --silent localhost:8000 | awk 'NR == 1'
<!doctype html>
						

$ curl --silent localhost:8000 | sed '1q;d'
<!doctype html>

						

$ curl --silent localhost:8000 | perl -ne 'print if $. == 1'
<!doctype html>

						

build


$ gulp
[09:42:44] Using gulpfile ~/Dropbox/Projects/todomvc/gulpfile.js
[09:42:44] Starting 'clean'...
[09:42:44] Finished 'clean' after 5.42 ms
[09:42:44] Starting 'default'...
[09:42:44] Starting 'styles'...
[09:42:44] Starting 'copy'...
[09:42:45] 'styles' all files 4.88 kB
[09:42:45] Finished 'styles' after 954 ms
[09:42:47] 'copy' all files 47.73 MB
[09:42:47] Finished 'copy' after 2.34 s
[09:42:47] Starting 'jshint'...
[09:42:47] Starting 'html'...
[09:42:48] Starting 'images'...
[09:42:49] Finished 'jshint' after 2.06 s
[09:42:55] 'html' all files 396 kB
[09:42:55] Finished 'html' after 8.3 s
[09:42:56] 'images' all files 49.49 kB
[09:42:56] Finished 'images' after 8.07 s
[09:42:56] Finished 'default' after 12 s
						

$ ls dist
CNAME bower_components/ examples/ index.html learn.json main.min.css main.min.js site-assets/
						

takeaways?

virtual production environment

Marco Polo style

start a virtual machine


$ vagrant init ubuntu/trusty64
						

A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
						

$ vagrant up
						

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'ubuntu/trusty64' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'ubuntu/trusty64'
    default: URL: https://vagrantcloud.com/ubuntu/trusty64
==> default: Adding box 'ubuntu/trusty64' (v20150420.1.1) for provider: virtualbox
    default: Downloading: https://atlas.hashicorp.com/ubuntu/boxes/trusty64/versions/20150420.1.1/providers/virtualbox.box
==> default: Successfully added box 'ubuntu/trusty64' (v20150420.1.1) for 'virtualbox'!
==> default: Importing base box 'ubuntu/trusty64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'ubuntu/trusty64' is up to date...
==> default: Setting the name of the VM: todomvc_default_1429689274676_40740
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => /Users/emilianl/Dropbox/Projects/todomvc
						

vagrant ssh


$ vagrant ssh
						

Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-49-generic x86_64)

...

vagrant@vagrant-ubuntu-trusty-64:~$$
						

install nginx


$$ sudo apt-get update
						

$$ sudo apt-get install nginx
						

$$ curl localhost:80
<!doctype html>
						

$$ exit
logout
Connection to 127.0.0.1 closed.
						

$ curl localhost:80
						

:(
						

give access to port 80


$ vagrant halt
						

==> default: Attempting graceful shutdown of VM...
						

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu/trusty64"

  config.vm.network :forwarded_port, host: 8888, guest: 80
end
						

$ vagrant up
						

==> default: Forwarding ports...
    default: 80 => 8888 (adapter 1)
    default: 22 => 2222 (adapter 1)
						

$ curl localhost:8888
<!doctype html>
						

deploy app on nginx


$ vagrant ssh
						

$ sudo vim /etc/nginx/sites-available/default
						

root /vagrant/dist;
						

sudo service nginx reload
						

$ exit
logout
Connection to 127.0.0.1 closed.
						

$ curl localhost:8888
<!doctype html>
						

let's do that again ... and again ... and again

takeaways?

virtual production environment

Henry Ford style

ready to automate?

nginx with puppet


$ vagrant destroy
						

$ vagrant up
						

// manifests/default.pp
package { "nginx":
    ensure => installed
}

service { "nginx":
    require => Package["nginx"],
    ensure => running,
    enable => true
}
						

$ vagrant ssh
						

$$ sudo puppet apply /vagrant/manifests/default.pp
						

$$ curl localhost:80
						

remove existing configuration


// manifests/default.pp
file { "/etc/nginx/sites-enabled/default":
    require => Package["nginx"],
    ensure  => absent,
    notify  => Service["nginx"]
}
						

$$ sudo puppet apply manifests/default.pp
						

$$ curl localhost:80
						

add new configuration


// manifests/default.pp
file { "/vagrant/dist":
    ensure => "directory"
}
						

file { "/etc/nginx/sites-available/todomvc":
    require => [
        Package["nginx"],
        File["/vagrant/dist"]
    ],
    ensure => "file",
    content => 
        "server {
            listen 80 default_server;
            server_name _;
            location / { root /vagrant/dist; }
        }",
    notify => Service["nginx"]
}
						

file { "/etc/nginx/sites-enabled/todomvc":
    require => File["/etc/nginx/sites-available/todomvc"],
    ensure => "link",
    target => "/etc/nginx/sites-available/todomvc",
    notify => Service["nginx"]
}
						

$$ sudo puppet apply manifests/default.pp
						

automate the apply step


$ vagrant destroy
						

Vagrant.configure("2") do |config|
  config.vm.provision "puppet"
end
						

$ vagrant up
						

==> default: Running provisioner: puppet...
==> default: Running Puppet with default.pp...
==> default: stdin: is not a tty
==> default: Warning: Could not retrieve fact fqdn
==> default: Notice: Compiled catalog for vagrant-ubuntu-trusty-64 in environment production in 0.21 seconds
==> default: Notice: /Stage[main]/Main/Package[nginx]/ensure: ensure changed 'purged' to 'present'
==> default: Notice: /Stage[main]/Main/File[/etc/nginx/sites-available/todomvc]/ensure: defined content as '{md5}d7f46245a21721bb4b8c169ff8a53354'
==> default: Notice: /Stage[main]/Main/File[/etc/nginx/sites-enabled/default]/ensure: removed
==> default: Notice: /Stage[main]/Main/File[/etc/nginx/sites-enabled/todomvc]/ensure: created
==> default: Notice: /Stage[main]/Main/Service[nginx]: Triggered 'refresh' from 3 events
==> default: Notice: Finished catalog run in 15.13 seconds
						

$ curl --silent localhost:8888
						

now let's do that again


$ vagrant destroy
						

$ vagrant up
						

$ curl --silent localhost:8888
						

now you know what provision means

takeaways?

production environment in the cloud

meet digital ocean

destroy previous vm


$ vagrant destroy
						

create a ssh key


$ ssh-keygen -t rsa -C "your_email@example.com"
						

install digitalocean and puppet plugins


$ vagrant plugin install vagrant-digitalocean
						

$ vagrant plugin install vagrant-puppet-install
						

add the digitalocean provider


Vagrant.configure("2") do |config|
  # ...
  config.puppet_install.puppet_version = "3.7.3"
  config.vm.provider :digital_ocean do |digital_ocean, override|
    digital_ocean.token = ENV['VAGRANT_DIGITALOCEAN_TOKEN']
    digital_ocean.image = "ubuntu-14-04-x64"
    digital_ocean.region = "ams2"
    digital_ocean.size = "512mb"

    override.vm.box = "digital_ocean"
    override.vm.box_url = 
      "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
    override.ssh.username = "ubuntu"
    override.ssh.private_key_path = "~/.ssh/id_rsa"
  end
end
						

give it a spin


$ vagrant up --provider=digital_ocean
						

$ curl _the_ip_
						

$ vagrant destroy
						

takeaways?

  • infrastructure can be code
  • works well with cloud
  • tools are plenty
  • immutable infrastructure
  • anti-fragility

credits