Provision and deploy with Puppet – @michaelpeacock – Puppet Primer



Provision and deploy with Puppet – @michaelpeacock – Puppet Primer

0 0


puppet-lightning-talk


On Github mkpeacock / puppet-lightning-talk

Provision and deploy with Puppet

@michaelpeacock

Hello! I'm going to talk today about using Puppet to provision your servers and deploy your application; so you can go from a bare box to a working application in minutes. We will start by walking through Puppet, and how it works, and then run through building a sample puppet project to setup and deploy a project on a production server.

Puppet Primer

Lets start with a puppet primer. Be warned, this contains a mixture of good and bad practices. My self-teaching approach always takes the route of cobble something together that works, wait at least a year, realise how to use the tool properly, slowly re-work it. I'll try and point out the good and the bad.

Resources

  • cron to install and manage cron jobs
  • exec to run shell commands
  • user create and manage user accounts
  • group create and manage user groups
  • file create and manage files, their contents, folders and symlinks
  • package install or remove software packages
  • service manage running services

The different aspects of your server puppet can manage, are referred to as resources; there are many different types of resources, and for aspects where features don't exist, modules can often fill the gaps brilliantly. Some of the key resources we will look at include

  • cron to install and manage cron jobs
  • exec to run shell commands
  • user create and manage user accounts
  • group create and manage user groups
  • file create and manage files, their contents, folders and symlinks
  • package install or remove software packages
  • service manage running services

Using resources

resource_type { 'title':
	attribute => value,
	attribute => value
}
user { 'michael':
	ensure => "present", # create user if not there
	gid => "wheel", # use this group
	password => "somehash"
}
To use a resource, you specify its type, provide a title, and a set of attribtues. The title is unique and allows other resources to refer to each other; typicall the title doubles as a specific attribute. For example, on an exec it refers to the command you are running, however you can use a more friendly string as the title, and override the command by specifying the command attribute.

Requirements

You can set one resource to depend on another using the require attribute

  • Resource type must start with a capital letter
  • Group multiple requirements within []
  • You can even require an entire class of resources
user { 'michael':
	ensure => "present", # create user if not there
	gid => "wheel", # use this group
	password => "somehash",
	require => [Group['wheel'], Class['chump']]
}

Run stages [avoid]

stage { 'first':
	before => Stage['main'],
}

class { 'chump-module':
	stage => first
}
Either requiring an Exec resource, or an Exec requiring an Exec, has never been reliable for me. Stages are one solution to this. They let you group chunks of your puppet code together, and have certain groups run before the other

Notify, Subscribe & Refreshonly

  • Notify another resource when this resources runs*
  • Tell this resource to wait (Subscribe) for another resource
  • Only run a resource if the resource being subscribed to also runs (refreshonly)
service { "nginx":
	ensure => "running",
	require => Package["nginx"],
	subscribe => Service["php5-fpm"]
}

Modules

Typically related, reusable resources, structured in a configurable way.

modules
---- mymodule
---- ---- manifests
---- ---- ---- init.pp
---- ---- ---- othermanifests.pp
---- ---- /files
---- ---- ---- some-file.txt
---- ---- /templates
---- ---- ---- some-template.erb

Access a modules files from within the module

file { '/etc/nginx/sites-available/default':
    source => "puppet:///modules/nginx/config-file",
    owner => 'root',
    group => 'root',
    notify => Service['nginx'],
    require => Package['nginx']
 }

Classes [bad]

class mysql {

  package { "mysql-server":
    ensure => present
  }

  package { "mysql-client":
    ensure => present
  }

  package { "libmysqlclient15-dev":
    ensure => present
  }

}/modules/mysql/manifests/init.pp
import "mysql"
include mysqlmanifests/site.pp
Why is this bad? It provides no options for configuration, also a MySQL module would let us do things with the database server, such as create and manage MySQL users.

Classes [better]

class iptables ($file = 'iptables') {
    exec { 'load-rules':
        command => "/sbin/iptables -F && /sbin/iptables-restore < /etc/iptables.up.rules",
        require => File['/etc/iptables.up.rules'],
        refreshonly => true
    }

    file { '/etc/iptables.up.rules':
        source => "puppet:///modules/iptables/${file}",
        owner => 'root',
        group => 'root',
        notify => Exec['load-rules']
    }

    file { '/etc/network/if-pre-up.d/iptables':
        source => 'puppet:///modules/iptables/up',
        owner => 'root',
        group => 'root',
        mode => 755
    }
}
modules/iptables/manifests/init.pp
class {
    'iptables':
        file => 'external-staging-rules'
}manifests/site.pp

Existing modules

Puppet Forge is the online repository of existing Puppet modules; most are well documented, and are on GitHub so you can include them as a submodule for your Puppet project. Make sure you also include dependencies.

As with code components, existing modules are a mixed bag and a balancing act; some give you lots of flexibility, others don't - so check that they support your needs

Manifests

There are typically two types of manifest files; ones within modules, of which init.pp is called automatically when the module is invoked, and the manifests which relate to a specific server, and specify the modules which should be used and how they should be used

Provision and deploy

See: sample-project

Setup puppet

Provision