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)
Inventory systems
- Facter (Puppet)
- Ohai (Chef)
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:
- Concise language for describing cases
- Requires people who work with CM to know the new language
- Potential for bugs in parser for the DSL
- Fewer advanced language features
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