Infrastructure testing with Jenkins, Puppet and Vagrant - Agile Testing Days 2013

Post on 08-Sep-2014

16.222 views 2 download

Tags:

description

Extend Continuous Integration to automatically test your infrastructure. Continuous Integration can be extended to test deployments and production environments, in a Continuous Delivery cycle, using infrastructure-as-code tools like Puppet, allowing to manage multiple servers and their configurations, and test the infrastructure the same way continuous integration tools do with developers’ code. Puppet is an infrastructure-as-code tool that allows easy and automated provisioning of servers, defining the packages, configuration, services, … in code. Enabling DevOps culture, tools like Puppet help drive Agile development all the way to operations and systems administration, and along with continuous integration tools like Jenkins, it is a key piece to accomplish repeatability and continuous delivery, automating the operations side during development, QA or production, and enabling testing of systems configuration. Using Vagrant, a command line automation layer for VirtualBox, we can easily spin off virtual machines with the same configuration as production servers, run our test suite, and tear them down afterwards. We will show how to set up automated testing of an application and associated infrastructure and configurations, creating on demand virtual machines for testing, as part of your continuous integration process.

Transcript of Infrastructure testing with Jenkins, Puppet and Vagrant - Agile Testing Days 2013

Infrastructure testing with Jenkins, Puppet and Vagrant

Carlos Sanchez@csanchezhttp://csanchez.orghttp://maestrodev.com

How we got here

Agile

planningiterative developmentcontinuous integration

release soon, release often

Fear of changeRisky deployments

It works on my machine!Siloisation

Dev Change vs. Ops stability

OPs requirements

Operating Systemconfig filespackages installedmulti stage configurationsdevQApre-productionproduction

Deployment

How do I deploy this?documentationmanual stepsprone to errors

Cloud

How do I deploy this?to hundreds of servers

DevOps

DevQaOps ?

DEV QA OPS

DEV

QA

OPS

SpecsPackagesVersions

DEV PROD

TestabilityDEV QA

MetricsLogsSecurity updates

DEV PROD

is not about the toolsbut

how can I implement IT

Tools can enable change in behavior and eventually change culturePatrick Debois

everyone is intelligent enoughevery tool is cloud enabledevery tool is DevOps(tm)

3 key concepts

Continuous Delivery

Continuous delivery

Infrastructure as Codeit’s all been invented, now it’s standardized

manifestsruby-likeERB templates

exec { "maven-untar": command => "tar xf /tmp/x.tgz", cwd => "/opt", creates => "/opt/apache-maven-${version}", path => ["/bin"], } -> file { "/usr/bin/mvn": ensure => link, target => "/opt/apache-maven-${version}/bin/mvn", } file { "/usr/local/bin/mvn": ensure => absent, require => Exec["maven-untar"], } file { "$home/.mavenrc": mode => "0600", owner => $user, content => template("maven/mavenrc.erb"), require => User[$user], }

infrastructureIS code

package { 'openssh-server': ensure => present,}

declarative modelstate vs processno scripting

service { 'ntp': name => 'ntpd', ensure => running, }

Follow development best practicestaggingbranchingreleasingdev, QA, production

new solutions

new challenges

Self servicing

Infrastructure always availablevirtualization & cloudempower developersreduce time-to-market

devs buy-inWith great power comes great responsibility

Vagrantempower developersdev-ops collaborationautomation

Vagrant

Vagrant

Virtual and cloud automationVirtualBox

VMWare Fusion

AWS

Rackspace

Easy Puppet and Chef provisioningKeep VM configuration for different projects

Share boxes and configuration files across teamsbase box + configuration files

Vagrant base boxes

www.vagrantbox.espuppet-vagrant-boxes.puppetlabs.com

anywhere! just (big) files

using Vagrant

$ gem install vagrant$ vagrant box add centos-6.0-x86_64 \ http://dl.dropbox.com/u/1627760/centos-6.0-x86_64.box $ vagrant init myproject$ vagrant up$ vagrant ssh$ vagrant suspend$ vagrant resume$ vagrant destroy

Vagrant.configure("2") do |config|

# Every Vagrant virtual environment requires a box to build off of. config.vm.box = "CentOS-6.4-x86_64-minimal" config.vm.box_url = "https://.../CentOS-6.4-x86_64-minimal.box"

# web server config.vm.define :www do |config| config.vm.hostname = "www.acme.local" config.vm.network "forwarded_port", guest: 80, host: 10080 config.vm.network "private_network", ip: "192.168.33.12" end

config.vm.provision :puppet do |puppet| puppet.module_path = "modules" puppet.manifest_file = "site.pp" end

end

Vagrant

Geppetto

Maven and Puppet

What am I doing to automate deployment

Ant tasks pluginssh commands

Assembly pluginCargo

Capistrano

What can I do to automate deployment

Handle full deployment including infrastructurenot just webapp deployment

Help Ops with clear, automated manifestsAbility to reproduce production environmentsin local box using Vagrant / VirtualBox / VMWare

Use the right tool for the right job

Maven-Puppet module

A Maven Puppet module

https://github.com/maestrodev/puppet-maven

fetches Maven artifacts from the repomanages them with Puppet

no more extra packaging

Installing Maven

$repo1 = { id => "myrepo", username => "myuser", password => "mypassword", url => "http://repo.acme.com",}

# Install Mavenclass { "maven::maven": version => "2.2.1",} ->

# Create a settings.xml with the repo credentialsclass { "maven::settings" : servers => [$repo1],}

New Maven type

maven { "/tmp/maven-core-2.2.1.jar": id => "org.apache.maven:maven-core:jar:2.2.1", repos => ["http://repo1.maven.apache.org/maven2",

"http://mirrors.ibiblio.org/pub/mirrors/maven2"], }

New Maven type

maven { "/tmp/maven-core-2.2.1.jar": groupId => "org.apache.maven", artifactId => "maven-core", version => "2.2.1", packaging => "jar", repos => ["http://repo1.maven.apache.org/maven2",

"http://mirrors.ibiblio.org/pub/mirrors/maven2"], }

Examples

Infrastructure

Jenkins

Archiva

wwwhttpd

QAhttpd,

tomcat, postgres

tomcat1tomcat

dbpostgres

Tomcat cluster + postgres

postgresdb.acme.com

tomcattomcat1.acme.com

httpdwww.acme.com

tomcattomcat2.acme.com ...

Continuous Delivery

developer

commit git repo

jenkins

binary repository

QA vm

db

tomcat*

www

post commit hook

build

integration testing

production

Puppet Modules required

$ bundle install && librarian-puppet install

forge 'http://forge.puppetlabs.com'

mod 'puppetlabs/java', '>=1.0.0'mod 'puppetlabs/apache', '>=0.9.0'mod 'puppetlabs/postgresql', '>=3.0.0'mod 'puppetlabs/firewall'mod 'camptocamp/tomcat', :git => 'https://github.com/carlossg/puppet-tomcat.git', :ref => 'setclasspath'mod 'maestrodev/maven', '>=1.0.0'mod 'stahnma/epel', '>=0.0.2'mod 'maestrodev/avahi', '>=1.0.0'mod 'acme', :path => 'mymodules/acme'

mymodules/acme/manifests/db_node.pp

class 'acme::db_node' {

class { 'postgresql::server': ip_mask_allow_all_users => '192.168.0.0/0', listen_addresses => '*', postgres_password => 'postgres', } ->

postgresql::server::db { 'appfuse': user => 'appfuse', password => 'appfuse', grant => 'all', }

firewall { '100 allow postgres': proto => 'tcp', port => '5432', action => 'accept', }}

mymodules/acme/manifests/tomcat_node.pp I

class acme::tomcat_node( $db_host = 'db.local', $repo = 'http://carlos-mbook-pro.local:8000/repository/all/', $appfuse_version = '2.2.2-SNAPSHOT', $service = 'tomcat-appfuse', $app_name = 'appfuse', $tomcat_root = '/srv/tomcat') {

# install java class { 'java': }

# install tomcat class { 'tomcat': } ->

# create a tomcat server instance for appfuse # It allows having multiple independent tomcat servers in different ports tomcat::instance { 'appfuse': ensure => present, http_port => 8080, }

# where the war needs to be installed $webapp = "${tomcat_root}/${app_name}/webapps/ROOT"

mymodules/acme/manifests/tomcat_node.pp II

# install maven and download appfuse war file from our archiva instance class { 'wget': } -> class { 'maven::maven' : version => '3.0.4', } -> # clean up to deploy the next snapshot exec { "rm -rf ${webapp}*": } -> maven { "${webapp}.war": id => "org.appfuse:appfuse-spring:${appfuse_version}:war", repos => [$repo], require => File["${tomcat_root}/${app_name}/webapps"], notify => Service[$service], } ->

firewall { '100 allow tomcat': proto => 'tcp', port => '8080', action => 'accept', }}

mymodules/acme/manifests/www_node.pp

class acme::www_node($tomcat_host = 'tomcat1.local') {

class { 'apache': } class { 'apache::mod::proxy_http': }

# create a virtualhost that will proxy the tomcat server apache::vhost { "${::hostname}.local": port => 80, docroot => '/var/www', proxy_dest => "http://${tomcat_host}:8080", }

firewall { '100 allow apache': proto => 'tcp', port => '80', action => 'accept', }}

manifests/site.pp

import 'nodes/*.pp'

node ‘parent’ { class {'epel': } ->

class {'avahi': firewall => true, }}

manifests/nodes/tomcat.pp

# tomcat1.acme.com, tomcat2.acme.com,...node /tomcat\d\..*/ inherits ‘parent’ {

file {'/etc/motd': content => ”tomcat server: ${::hostname}\n”, }

class {'acme::tomcat_node'}}

manifests/nodes/qa.pp

node /qa\..*/ inherits ‘parent’ { class {'acme::db_node': }

class {'acme::tomcat_node': db_host => 'localhost', }

class {'acme::www_node': tomcat_host => 'localhost', }}

Infrastructure unit testing

rspec-puppet

Unit testing your puppet manifestsEnsuring packages, config files, services,...

spec/hosts/db_spec.pp

require 'rspec-puppet'

describe 'db.acme.com' do let(:facts) { { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => ‘6.3’} }

it { should contain_class('postgresql::server') }end

spec/hosts/www_spec.pp

require 'rspec-puppet'

describe 'www.acme.com' do let(:facts) { { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => ‘6.3’} }

it { should contain_package('httpd') }end

Example code and slides

Available athttp://slideshare.csanchez.org

http://github.csanchez.orghttp://blog.csanchez.org

csanchez@maestrodev.comcarlos@apache.org@csanchez

Danke!

http://csanchez.orghttp://maestrodev.com

Photo Credits

Brick wall - Luis Argerichhttp://www.flickr.com/photos/lrargerich/4353397797/

Agile vs. Iterative flow - Christopher Littlehttp://en.wikipedia.org/wiki/File:Agile-vs-iterative-flow.jpg

DevOps - Rajiv.Panthttp://en.wikipedia.org/wiki/File:Devops.png

Pimientos de Padron - Howard Walfishhttp://www.flickr.com/photos/h-bomb/4868400647/

Compiling - XKCDhttp://xkcd.com/303/

Printer in 1568 - Meggs, Philip Bhttp://en.wikipedia.org/wiki/File:Printer_in_1568-ce.png

Relativity - M. C. Escherhttp://en.wikipedia.org/wiki/File:Escher%27s_Relativity.jpg

Teacher and class - Herald Posthttp://www.flickr.com/photos/heraldpost/5169295832/