I'm Sam!
Red Hat
Software Engineer, Virtualization R&D
Package management
Files, users, groups, sysctl, etc.
Orchestration (kinda)
Why do we need configuration management?
Reproducability
Drift prevention
State management
Sounds pretty good, huh?
Agent/Client -> Master
Controller -> Node (SSH)
Tonight's tools:

Inventory systems

macaddress_eth0 => 42:01:0A:F0:18:46
mtu_eth0 => 1460
mtu_lo => 16436
mtu_sit0 => 1480
mtu_teql0 => 1500
mtu_tunl0 => 1480
netmask => 255.255.255.255
netmask_eth0 => 255.255.255.255
netmask_lo => 255.0.0.0
network_eth0 => 10.240.24.70
network_lo => 127.0.0.0
operatingsystem => CentOS
operatingsystemmajrelease => 6
operatingsystemrelease => 6.4
osfamily => RedHat
path => /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
physicalprocessorcount => 1
processor0 => Intel(R) Xeon(R) CPU @ 2.60GHz
processor1 => Intel(R) Xeon(R) CPU @ 2.60GHz
processorcount => 2
ps => ps -ef
puppetversion => 3.1.1
rubysitedir => /usr/lib/ruby/site_ruby/1.8
rubyversion => 1.8.7
selinux => false
        
DSL's: Domain specific language
External DSL
class ntp {
  package { "ntp":
   ensure => present
  }

  file { '/etc/ntp.conf':
    content => template('ntp/ntp.conf.erb'),
    notify => Service['ntpd']
  }

  service { 'ntpd':
    ensure => running,
    enable => true
  }
}
Internal DSL
package 'ntp'

template '/etc/ntp.conf' do
  source    'ntp.conf.erb'
  notifies  :restart, 'service[ntpd]'
end

service 'ntpd' do
  action [:enable, :start]
end
Markup
tasks:
 - name: install requirements
    action: yum pkg=$item state=installed
    with_items:
      - ntp
Why/why not use an external DSL:
Personal preference

Let's dive in...


https://github.com/skottler/configuration-management-demo

Puppet
  • Operates in both master and masterless modes
  • External DSL that's extensible with Ruby
  • Widely used - Google, CERN, SpaceX, Zynga
Manifest
package { ['ntp', 'ntpdate':
  ensure => present
}

service { 'ntpd':
  ensure => running,
  enable => true
}

file { '/etc/ntp.conf':
  ensure => present,
  owner => "root",
  group => "root",
  mode => 0644,
  content => template("ntp/ntp.conf.erb"),
  require => Package['ntp']
}
      
Class
class mysql {
  include mysql::client

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

  service { 'mysqld':
    ensure => enabled,
    enable => true,
    require => Package['mysql-server']
  }
}

class mysql::client {
  package { 'mysql-client':
    ensure => present
  }
}
      
Module layout
  • files
  • lib
  • manifests
  • spec
  • templates
  • tests

External node classifier

---
  parameters:
    root_ssh_recovery_key: "[redacted]"
    puppetmaster: localhost
    foreman_env: production
    nagios_ip: "[redacted]"
    owner_name: "Sam Kottler"
    hostgroup: Base/foreman
    root_pw: [redacted]
    owner_email: "sam@kottlerdevelopment.com"
  classes:
    "munin::client":
    utility:
    foreman_proxy:
      ssl_cert: false
      ssl: false
      ssl_key: false
      manage_sudoersd: false
      ssl_ca: false
    "munin::server":
    users
      

Authentication


PKI

puppet cert --sign newmachine.example.com

Chef

  • Widely used
  • Many large deployments: LivingSocial, 37Signals, Facebook
  • It's just Ruby!
  • Often favored by Ruby developers
  • Incredibly vibrant ecosystem
Cookbooks & recipes
"run_list": ["role[app]"],
  "sudo" : {
     "add_vagrant" : false
   },
  // rubygems Rails application attributes
  "application": {
    "name": "rubygems",
    "repository": "https://github.com/rubygems/rubygems.org.git",
    "rails_env": "production",
    "rails_root": "/applications/rubygems/production",
    "server_names": ["app01.rubygems.org"],
    "use_ssl": true,
    "force_ssl": true,
    "ssl_key": "dev.rubygems.org.key",
    "ssl_cert": "dev.rubygems.org.crt",
    "app_server": {
      "name": "thin",
      "concurrency": 4

        
name "app"
description "Just enough sauce to run the app server."
run_list(
  "role[base]",
  "recipe[memcached]",
  "recipe[redis::server]",
  "recipe[rubygems::stat-update]",
  "role[rubygems]"
)

default_attributes({"redis" => {
                       "maxmemory" => "8gb",
                       "dir" => "/var/lib/redis_data"}})
        
user "postgres" do
  shell "/bin/bash"
  comment "PostgreSQL Server"
  home "/var/lib/pgsql"
  gid "postgres"
  system true
  uid 26
  supports :manage_home => false
end

node['postgresql']['server']['packages'].each do |pg_pack|
  package pg_pack
end

service "postgresql" do
  service_name node['postgresql']['server']['service_name']
  supports :restart => true, :status => true, :reload => true
  action [:enable, :start]
end

Some cool tools:

  • knife
  • test-kitchen
  • berkshelf
  • librarian-chef
Ansible & Salt

Ansible

  • Playbooks
  • Orchestration & Configuration
  • Moving quickly and improving a lot
  • Uses Facter or Ohai
  • Uses SSH as the transport
---
- hosts: webservers
  sudo: yes
  gather_facts: no

  tasks:
  - name: ensure apt cache is up to date
    action: apt update_cache=yes
  - name: ensure packages are installed
    action: apt name={{item}}
    with_items:
        - postgresql
        - libpq-dev
        - python-psycopg2

- hosts: webservers
  sudo: yes
  sudo_user: postgres
  gather_facts: no

  vars:
    dbname: myapp
    dbuser: django
    dbpassword: mysupersecreetpassword
        

Salt

  • Uses a master and agent (minion)
  • Configuration language
  • Uses PKI for management
apache:
   pkg:
     - installed
   service:
     - running
     - require:
       - pkg: apache