Provisioning voor developers

Ontwikkelaars hebben vaak hun desktop of laptop volstaan met allerlei development software, waarin veel tijd is geïnvesteerd en dat ondertussen ook alweer verouderd is. Als alternatief kan je Oracle Virtualbox images maken, maar dit neemt weer veel schijfruimte in beslag. Daarnaast hebben we vaak geen idee wat de status is van deze VM’s. Gelukkig is hiervoor een oplossing en dat is server provisioning met behulp van Vagrant.

Vagrant zorgt ervoor dat een Virtualbox of VMware VM wordt aangemaakt en kan na het opstarten een provisioning tool -zoals Puppet of Chef- starten. Naast de kleine basis VM heb je nu alleen maar een paar MB aan provisioning data. Hiermee is het mogelijk om binnen een paar minuten een werkende VM te verkrijgen, waarvan je exact weet wat erop draait, hoe het tot stand is gekomen en die eenvoudig is aan te passen met de laatste versie van de software. Daarbij is deze omgeving via GitHub of via SSH eenvoudig te delen met anderen. Indien je de omgeving niet meer nodig hebt, is de VM altijd weer eenvoudig te verwijderen of te herstellen.

 

In dit artikel gaan we een Fedora Virtualbox VM maken, waarbij Puppet wordt gebruikt voor de provisioning. Op de VM worden de volgende zaken geïnstalleerd en geconfigureerd: MariaDB, Apache met AJP en Wildfly als applicatieserver.

 

Overzicht van onze Puppet Vagrant omgeving.

 

Voor dit artikel is de laatste versie van Oracle VirtualBox (https://www.virtualbox.org/)  en Vagrant (http://www.vagrantup.com/) nodig.

 

Een nieuwe vagrant omgeving

We beginnen met het maken van een folder, genaamd ‘javamagazine’.

 


open cmd.exe of een terminal window
mkdir javamagazine
cd javamagazine
vagrant init

 

 

Vagrant init maakt dan een bestand aan genaamd: Vagrantfile. De Vagrantfile komt standaard met een configuratie voor de volgende onderdelen:

 

  • Base image;
  • Port forwarding;
  • Private network address;
  • Shared folder tussen de VM en de desktop;
  • Virtualbox parameters;
  • Provisioning details.

 

Na het opruimen van alle irrelevante commentaarregels houden we het volgende over:

 


# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "base"
  # config.vm.network "forwarded_port", guest: 80, host: 8080
  # config.vm.network "private_network", ip: "192.168.33.10"
  # config.vm.synced_folder "../data", "/vagrant_data"
  # config.vm.provider "virtualbox" do |vb|
  #   vb.gui = true
  #   vb.customize ["modifyvm", :id, "--memory", "1024"]
  # end
  # config.vm.provision "puppet" do |puppet|
  #   puppet.manifests_path = "manifests"
  #   puppet.manifest_file  = "site.pp"
  # end
end

 

Voordat we kunnen beginnen met het maken van een Virtualbox image, is een vagrant box nodig waar Puppet al geïnstalleerd is. Op één van de volgende websites is een geschikte vagrant box te vinden.

 

https://vagrantcloud.com/discover/popular

http://www.vagrantbox.es/

 

Verander vervolgens in het Vagrantfile bestand config.vm.box = "base" naar config.vm.box = "hashicorp/precise64". Dit zorgt ervoor dat eenmalig een box wordt geïmporteerd. Met vagrant up wordt een Ubuntu VM aangemaakt, welke terug te vinden is in de Oracle VirtualBox Manager. Na het downloaden start vagrant de VM, activeert SSH port forwarding en maakt een gedeelde folder aan tussen de host en de VM genaamd /vagrant.

 

Nu kan met SSH worden aangelogd op de VM. Gebruik ssh vagrant@127.0.0.1 -p 2222

(gebruikersnaam = vagrant met als wachtwoord vagrant). Ux desktops kunnen in plaats van SSH vagrant ssh gebruiken.

 

Voordat we verder gaan, zijn de volgende vagrant commando’s wellicht nuttig om te weten:

  • vagrant up                   = starten VM
  • vagrant halt                 = stoppen VM
  • vagrant suspend         = uitzetten in huidige status VM
  • vagrant destroy          = verwijderen VM

 

Vagrant box

Mocht je geen geschikte box vinden, dan kan je altijd nog besluiten om een eigen box te maken met behulp van Packer (http://www.packer.io/). Packer is in staat om met PXE boot een VM te maken die geschikt is voor VirtualBox, VMware, Docker etc. en kan als laatste stap ook een Puppet installatie script starten. Dit bespaart veel werk met het configureren van een VM.

 

Voor dit artikel hebben wij op Dropbox een Fedora 20 box klaar staan. Voor het maken van je eigen box met Packer, verwijzen we je naar: https://github.com/biemond/packer-vagrant-builder.

 

Vagrant provisioning configuratie

Voordat we verder gaan, verwijderen we eerst onze Ubuntu VM (vagrant destroy). Verander in de vagrantfile de Ubuntu box naar onze Fedora box met daarbij de Dropbox url.

 


config.vm.box = "fedora-20-x86_64.box"
config.vm.box_url = https://dl.dropboxusercontent.com/s/ohazhdin4nibmx9/fedora-20-x86_64.box

 

Provisioning met Puppet

We gaan de vagrantfile aanpassen, zodat deze geschikt is voor Puppet. Voer de volgende aanpassingen door:

 

 


  config.vm.hostname = "dev.example.com"
  config.vm.network :private_network, ip: "10.10.10.10"
 
  config.vm.synced_folder ".", "/vagrant", :mount_options => ["dmode=777","fmode=777"]
 
  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "2048"]
    vb.customize ["modifyvm", :id, "--name"  , "dev"]
    #vb.gui = true
  end
 
  config.vm.provision :puppet do |puppet|
      puppet.manifests_path    = "puppet/manifests"
      puppet.module_path       = "puppet/modules"
      puppet.working_directory = '/vagrant'
      puppet.manifest_file     = "site.pp"
      puppet.options           = ['--verbose','--report',]
  end

 

Maak vervolgens op je desktop de volgende folders aan (in dezelfde directory als de vagrantfile).

 

puppet

puppet/modules

puppet/manifests

 

Maak tevens een tekstbestand genaamd site.pp, zogenaamde puppet manifest, en zet deze in de puppet/manifests folder.

 

Open site.pp en voeg de volgende inhoud toe.

 

 


node default {
  notify{'Hello Puppet':}
} 

 

Met node default zorgt puppet ervoor dat deze puppet manifest op elke VM wordt uitgevoerd. Als de VM wordt opgestart met vagrant up, dan wordt nu ook de puppet provisioning gestart. Wijzigingen in de site.pp kan je direct uittesten op de draaiende VM door vagrant provision uit te voeren.

 

Eerste Puppet steps

De volgende stap is het maken van een Puppet class met daarin onze specifieke OS instellingen. In Puppet classes kan je code samenvoegen in blokken. Om te beginnen plaatsen we alle code die betrekking heeft op het OS in class my_os. Deze class kennen we toe aan onze default node via een include statement. Open de file site.pp en voeg class my_os toe en vervang de eerder gemaakte notify door een include.

 


node default {
  include my_os
} 
 
class my_os {
 
  host{'localhost':
    ip           => "127.0.0.1",
    host_aliases => ['localhost.localdomain','localhost4',
                     'localhost4.localdomain4'],
  }
  host{'dev.example.com':
    ip           => "10.10.10.10",
    host_aliases => 'dev',
  }
 
  service { iptables:
    enable    => false,
    ensure    => false,
    hasstatus => true,
  }
 
  $install = ['binutils.x86_64','wget']
 
  package { $install:
    ensure  => present,
  }
}

 

In de class my_os worden een aantal acties beschreven. Hiervoor gebruiken we de standaard Puppet Types. Voor alle beschikbare Puppet Types, kijk je op:

http://docs.puppetlabs.com/references/latest/type.html.

 

De belangrijkste my_os class acties zijn:

 

  • host beschrijft de  /etc/hosts file entries.
  • service beschrijft de status die een service moet hebben. De firewall mag in ons geval niet actief zijn.
  • package beschrijft de status van een package. In de array staan een aantal packages die aanwezig moeten zijn. Als de package nog niet geïnstalleerd is, zal Puppet de package installeren. Hiervoor gebruikt puppet een specifieke provider zoals yum, rpm of apt-get.

 

Als we vervolgens vagrant provision starten, zal puppet de benodigde OS wijzigingen doorvoeren.

 

Modules

Voor de installatie van de benodigde software maken we gebruik van modules. Modules zijn autonoom gebundelde stukken code die je kan aanroepen in een manifest. Deze modules downloaden of installeren we vanuit Puppet Forge (http://forge.puppetlabs.com).

 

MySQL

De eerste module die we gebruiken is MySQL. Hiervoor downloaden we deze module van GitHub https://github.com/puppetlabs/puppetlabs-mysql/tree/2.3.x. Vanwege het feit dat Fedora en RedHat zijn overgestapt van MySQL naar MariaDB, kunnen we de versie van Puppet Forge nog niet gebruiken. Hernoem de puppet module naar mysql en plaats hem in de eerder aangemaakte puppet/modules folder.

 

In vrijwel iedere module wordt een bestand genaamd README.md meegeleverd. Dit bestand is ook te bekijken op github of Puppet Forge. In de README.md wordt de module met daarbij alle opties uitgebreid beschreven. Voeg onderstaande class my_mysql toe aan de site.pp.

 


node default {
  include my_os
  include my_mysql
} 
 
class my_mysql {
  require my_os
 
  class { '::mysql::server':
    root_password    => 'password',
    override_options => {
      'mysqld' => {
        'max_connections' => '1024' ,
        'bind-address'    => '10.10.10.10',
      }
     },
    users => {
      'petshop@%' => {
         ensure        => 'present',
         password_hash => '*8C4212B9269BA7797285063D0359C0C41311E472',
       }, 
     },  
    grants => {
      'petshop@%/petshop.*'  => {
        ensure     => 'present',
        options    => ['GRANT'],
        privileges => ['DROP','ALTER','SELECT', 'INSERT', 'UPDATE', 'DELETE'],
        table      => 'petshop.*',
        user       => 'petshop@%',
      },
     }, 
    databases => {
      'petshop' => {
        ensure  => 'present',
        charset => 'utf8',
      },
     }, 
    service_enabled => true, 
  }
}

 

De MySQL module heeft een afhankelijkheid met de puppetlabs/stdlib module. Nu we de MySQL module handmatig hebben geïnstalleerd, komt de stdlib module niet automatisch mee in de puppet modules folder. Deze kunnen we alsnog toevoegen via het puppet module commando. Voer hiervoor de volgende commando’s uit:

 


vagrant ssh of ssh vagrant@127.0.0.1 -p 2222 of via putty naar 10.10.10.10
sudo puppet module search stdlib

 

 

Dit geeft ons een Puppet Forge overzicht en de exacte naam van de stdlib module.

 


sudo puppet module install puppetlabs-stdlib --target-dir /vagrant/puppet/modules

 

 

Hiermee downloaden we de module van Puppet Forge en in de puppet modules folder.

 


exit

 

We zien nu naast de mysql module ook de stdlib module. Als we vervolgens vagrant provision uitvoeren, zal Puppet MySQL op onze VM configureren.

 

Apache

Vervolgens installeren we een Apache webserver die we gebruiken als Front-End op onze Wildfly applicatieserver. Log in als vagrant.

 


sudo puppet module install puppetlabs-apache --target-dir /vagrant/puppet/modules
exit

 

Voeg onderstaande class my_apache toe aan de site.pp

 


class my_apache {
  require my_os
 
  class { 'apache':
    default_mods        => true,
    default_confd_files => true,
  }
 
  apache::mod { 'proxy_ajp': }
 
  apache::vhost { 'dev.example.com':
    vhost_name       => '*',
    port             => '81',
    docroot          => '/var/www/petshop',
    proxy_pass => [
      { 'path' => '/petshop', 'url' => 'ajp://10.10.10.10:8009' },
    ],
  }
}

 

Include my_apache class in onze default node en voer vervolgens vagrant provision uit.

 

JDK8

Uiteraard hebben we voor Wildfly AS ook een JDK nodig. Log in als vagrant.

 


sudo puppet module install tylerwalts-jdk_oracle --target-dir /vagrant/puppet/modules
exit

 

Deze module download helaas niet de laatste versie van Oracle JDK8, maar dit kunnen we gelukkig vrij eenvoudig aanpassen. Voer hiervoor de volgende stappen uit:

 


cd puppet/modules/jdk_oracle/manifests

 

Open de init.pp manifest in een editor. In de 8 waarde van de $version case statement passen we vervolgens het volgende aan:

 


case $version {
  '8': {
    $javaDownloadURI = "http://download.oracle.com/otn-pub/java/jdk/8u5-b13/jdk-8u5-linux-${plat_filename}.tar.gz"
    $java_home = "${install_dir}/jdk1.8.0_05"
}

 

Voeg de onderstaande class my_ java toe aan de site.pp.

 


class my_java {
  require my_os
 
  class { 'jdk_oracle':
    version => "8",
  }
}

 

Include deze class aan de default node. Bij een volgende vagrant provision wordt de JDK gedownload en uitgepakt.
 

Wildfly AS 8.1.0

De laatste stap is het importeren van de Wildfly module. Dit gaat op dezelfde manier. Log in als vagrant op de VM.

 


sudo puppet module install biemond-wildfly --target-dir /vagrant/puppet/modules
sudo puppet module install maestrodev-wget --target-dir /vagrant/puppet/modules
exit

 

Voeg onderstaande class my_ wildfly toe aan de site.pp, deze class heeft extra een afhankelijkheid met de my_java class.

 


class my_wildfly{
  require my_os,my_java
 
  class { 'wildfly::install':
    version           => '8.1.0',
    install_source    => 'http://download.jboss.org/wildfly/8.1.0.Final/wildfly-8.1.0.Final.tar.gz',
    install_file      => 'wildfly-8.1.0.Final.tar.gz',
    java_home         => '/opt/jdk-8',
    dirname           => '/opt/wildfly',
    mode              => 'standalone',
    config            => 'standalone-full-ha.xml',
  }
 
  wget::fetch { "download sample.war":
    source      => 'https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war',
    destination => '/opt/wildfly/standalone/deployments/sample.war',
    timeout     => 0,
    verbose     => false,
    require => Class['wildfly::install'],
  }
}

 

Voor het testen van de Wildfly applicatieserver deployen we een demo war. We lenen hiervoor een sample war van Tomcat die via de wget module downloaden en plaatsen in de deployment folder. Include deze class in de definitie van de default node en voer opnieuw een vagrant provision uit. Dit was de laatste stap van onze provisioning en we zijn klaar om de VM te testen.

 

Testen van de configuratie

MySQL testen we met een MySQL client. Hiervoor maken we een connectie naar 10.10.10.10 op poort 3306. De wildfly management console is te bereiken op: http://10.10.10.10:9990/console. Gebruik hier wildfly als gebruikersnaam en wachtwoord. De demo applicatie is ook rechtstreeks te benaderen op: http://10.10.10.10:8080/sample/ of via Apache http://10.10.10.10:81/petshop/sample/.

 

Conclusie

Het is dus mogelijk om met vagrant en een provisioning tool vanuit niets op een eenvoudige en snelle manier VM’s te maken. Daarbij is genoeg flexibiliteit aanwezig om allerlei grote VM aanpassingen te doen. Vervolgens kan je deze configuratie via github op een gemakkelijke manier met anderen delen. De vagrant demo omgeving is te vinden op github https://github.com/biemond/vagrant-fedora20-puppet. Als klein extraatje bevat deze omgeving ook een PostgreSQL database.