Outils de provisionning

Ansible, Chef, Puppet et Salt

AFUP

Apéro PHP les 29 du mois à l'Antre Autre

Talks dans cette salle tous les deux mois

http://lyon.afup.org

AFPY

Apéro python tous les 4émes mercredi du mois à l'Antre Autre

http:/afpy.org

Hello!

Michael Scherer

Ansible

Julien Bianchi

Chef

Benoît Marcelin

Puppet

Gaston Tjebbes

Salt

Provisionning

C'est quoi ?

“Le provisioning, mot anglais désignant l'approvisionnement, est un terme utilisé dans le monde de l'informatique, désignant l'allocation automatique de ressources.
Les outils de provisioning sont des outils de gestion de configuration (on parle également de «gestion de paramétrage») permettant d'installer et de configurer des logiciels à distance...”

http://fr.wikipedia.org/wiki/Provisioning

Pourquoi ?

  • Pour décrire les procédures d'installation et de configuration
  • Pour installer/configurer des applications de manière automatique
  • Pour installer/configurer des applications à distance

Comment ?

  • Ansible
  • Chef
  • Puppet
  • Salt
  • CFEngine
  • Docker (builder)
  • ...

Radically simple IT
automation platform

En résumé

Python, GPL v3

Exeécution de tâches
sur des serveurs

via ssh

Commandes ad-hoc

ansible prod -m shell -a "yum upgrade -y"

Playbook

YAML + des bouts de Jinja

Orchestration

---
- hosts: jboss_servers
  serial: 10%
  tasks:
  - nagios: action=disable_alerts service=host host={{ inventory_hostname }}
    delegate_to: 127.0.0.1

  - shell: yum upgrade -y

  - shell: reboot

  - wait_for: port=80 delay=10 host={{ inventory_hostname }}
    delegate_to: 127.0.0.1

  - nagios: action=enable_alerts service=host host={{ inventory_hostname }}
    delegate_to: 127.0.0.1
						

Gestion de configuration

---
- hosts: web_servers
  roles:
  - role: website
    url: www.example.org
    document_root: /srv/sites/www/

  - role: website
    url: webmail.example.org
    document_root: /srv/sites/webmail/
    modules:
    - php

  - role: website
    url: calendar.example.org
    redirect: webmail.example.org
						

Avec plus de details

Modules

Idempotents

Couvrent de nombreux besoins

Inventaire

  • Fichier plat
  • Dossier
  • Script

[web_servers]
www[1,5].example.org ansible_ssh_user=root

[redis_servers]
redis[1,3].example.org ansible_ssh_user=centos ansible_sudo=yes
redis-test.example.org ansible_ssh_user=fedora ansible_sudo=yes
						

Variables

Utilisables en Jinja

Dans le playbook

---
- hosts: webbuilder
  vars:
    builder_user: builder_middleman
    error_mail:   misc@example.org
  roles:
  - role: builder
    name: manageiq
    git_url: "https://git.example.com/example/website.git"
    git_version: master
    remote_location: /var/www/html
    remote_server: www.example.org
    remote_user: root
						

Fournies par Ansible

$ ansible all -m setup -c local -i '127.0.0.1,'
127.0.0.1 | success >> {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.76.131"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::ea2a:eaff:fe15:9d20"
        ],
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "03/28/2014",
        "ansible_bios_version": "CJFT85RW (2.24 )",
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-3.10.0-210.el7.x86_64",
            "LANG": "fr_FR.UTF-8",
						

Stocké dans des fichiers à part

$ ls *
deploy.yml    hosts    requirements.yml

group_vars:
webservers.yml    redis_servers.yml

host_vars:
redis-test.yml

roles:
builder    website    redis
						

Anatomie d'un rôle

$ ls roles/builder/*
roles/builder/defaults:
mail.yml

roles/builder/files:
builder.sh

roles/builder/handlers:
mail.yml

roles/builder/meta:
main.yml

roles/builder/tasks:
main.yml

roles/builder/templates:
config.ini
						

Structure de contrôle

  • when
  • with_items
  • register

When


- name: install Epel
  yum: pkg=epel-release state=installed
  when: ansible_distribution == 'CentOS'
						

With_items


- name: install base rpms
  yum: pkg={{ item }} state=installed
  with_items:
  - screen
  - htop
  - iftop
  - iotop
  - strace
  - vim-enhanced
  - tcpdump
  - chrony
						

Register


- user:
   name=builder_middleman
   generate_ssh_key=yes
  register: result

- authorized_key:
      key="{{ result.ssh_public_key }}"
      user=copy_user
  delegate_to: www.example.org
						

Plus d'informations

http://www.ansible.com/

#ansible sur Freenode

ansible-users sur Google groups

Questions

OpsCode Chef

Chef, c'est quoi donc ?

“Chef is a systems and cloud infrastructure automation framework that makes it easy to deploy servers and applications to any physical, virtual, or cloud location, no matter the size of the infrastructure.”

http://docs.chef.io

Un framework

Un cadre

Des conventions

Des outils

Un peu de vocabulaire

Cookbooks
Recettes (recipes)
Ressources
Attributs (attributes)

Attributs

“An attribute is a specific detail about a node”

http://docs.chef.io/attributes.html

En gros, c'est une variable configurable et/ou dépendante de la plateforme.

Attributs

Défini par

# my_app/attributes/default.rb

default['my_app']['environment'] = 'prod'

Accédé par

# my_app/recipes/default.rb

puts node['my_app']['environment']

Ressource

“A resource is a statement of configuration policy. It describes the desired state of an element of your infrastructure, along with the steps needed to bring that item to the desired state.”

http://docs.chef.io/resources.html

Ressource

# my_app/recipes/packages.rb

package 'hhvm' do
    action :install
end
“Chef, installe le paquet hhvm s'il n'est pas déjà installé.
Merci !”

Ressources

50+ ressources natives

file, directory, execute, package, ruby_block, service, user, group, ...

http://docs.chef.io/resources.html#platform-resources

Recette (recipe)

“A recipe is the most fundamental configuration element within the organization.“

http://docs.chef.io/recipes.html

Recette (recipe)

Une recette contient une ou plusieurs ressources

# recipes/packages.rb

yum_repository 'epel' do
    mirrorlist 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch'
    gpgkey 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'
    action :create

    notifies :run, 'execute[yum-clean-all]', :immediately
end

execute 'yum-clean-all' do
    command 'yum clean all'
    action :nothing
end

package 'php'
“Chef, pour installer le paquet php, il faut commencer par ajouter le dépôt EPEL. Ensuite tu pourras installer php

Cookbook

“A cookbook is the fundamental unit of configuration and policy distribution. Each cookbook defines a scenario, such as everything needed to install and configure MySQL”

http://docs.chef.io/cookbooks.html

Cookbook

.
├── attributes/
│   └── default.rb
├── files/
│   └── default/
├── libraries/
├── metadata.rb
├── providers/
├── recipes/
│   ├── default.rb
│   └── packages.rb
├── resources/
└── templates/
    └── default/

Et c'est pas fini !

  • Databags
  • Providers
  • Portabilité (value_for_platform, ohai)
  • Notifications (notifies) et Abonnements (subscribes)
  • Gardes (only_if, not_if)
  • Surcharges d'attributs

Configuration

Un peu de JSON

{
    "run_list": [
        "recipe[etc_environment]",
        "recipe[my_app::packages]",
        "recipe[my_app]"
    ],
    "etc_environment": {
        "SYMFONY_ENV": "prod",
        "SYMFONY_DEBUG": 0
    }
}

La liste des recettes (run_list) à exécuter ainsi que les attributs

chef-solo

Pour le mode standalone

# /opt/chef/solo.rb

cookbook_path ['/opt/chef/cookbooks']
json_attribs '/opt/chef/solo.json'
$ chef-solo -c /opt/chef/solo.rb

Exécution (run)

Starting Chef Client, version 11.12.8
resolving cookbooks for run list: ["ohai", "proxmox-ohai", "resolver", "timezone", "consul", ...]
Synchronizing Cookbooks:
- ohai
- proxmox-ohai
- resolver
- timezone
- consul
...
Compiling Cookbooks...
Converging 26 resources
Recipe resolver::default
  * template[/etc/resolv.conf] action create (up to date)
Recipe timezone::default
  * package[tzdata] action install (up to date)
  * template[/etc/timezone] action create (up to date)
  * bash[dpkg-reconfigure tzdata] action nothing (skipped due to action :nothing)
Recipe consul::default
...
Chef Client finished, 2/31 resources updated in 3.391670365 seconds

Exécution (run)

Plusieurs étapes

  • Calcul de la configuration du noeud
  • Résolution de la run_list
  • Compilation des ressources
  • Convergence

Compilation / Convergence

Recette

# my_app/recipes/default.rb

# Une fonction Ruby
puts 'Yo'

# Une ressource Chef
log 'Man'

puts 'Hello'
log 'World'

Résultat

Yo
Hello
[2015-01-22T20:51:04+00:00] INFO: Man
[2015-01-22T20:51:04+00:00] INFO:World

Chef Server & chef-client

Pour le mode client/serveur

chef_server_url  "https://chef.myorg.com"
validation_client_name "chef-validator"
node_name "my_app_web"
environment "production"
$ chef-client

Un peu de vocabulaire, encore

Noeuds (nodes) Le système cible décrit par des rôles, des cookbooks/recettes et des attributs
Rôles Une collection de cookbooks/recettes et des attributs
Environnements Un ensemble de contraintes sur les cookbooks et des attributs

Chef Server

  • Héberge les cookbooks
  • Héberge les configurations (noeuds, rôles, environnements et databags)
  • Authentifie les tiers
  • Maintient un index des données

Orchestration

Grâce à l'index :node et à la méthode search.

search(:node, "role:db",
    :filter_result => { 'ip' => [ 'ipaddress' ]}).each do |result|
    puts result['ip']
end

                        

L'écosystème

  • Des outils
  • Des cookbooks libres
  • Des patterns
  • Une communauté

Les outils

knife Commande pour gérer chef server
berks Gestionnaire de dépendances
foodcritic Linter
chefspec Tests unitaires
kitchen CI Tests d'intégration multi-plateforme

Place to be #1

Documentation

http://docs.chef.io

Documentation

Le lien magique

https://docs.chef.io/resource_<resource-name>.html


La liste des ressources

https://docs.chef.io/resources.html#platform-resources

Place to be #2

Supermarket

Dépôt central des cookbooks communautaires

https://supermarket.chef.io

Place to be #3

Github

Code source des cookbooks communautaires

https://github.com/opscode-cookbooks
https://github.com/chef-cookbooks

Les points forts

  • Du ruby partout
  • Une documentation assez énorme
  • Beaucoup de ressources (cookbooks, articles, ...)
  • Un DSL puissant et extensible
  • Un très bon écosystème
  • Une communauté très active

Les points faibles

  • Les débuts peuvent être compliqués
  • La documentation est parfois dure à exploiter
  • Chef server un peu compliqué à installer
  • Manque de qualité de certains cookbooks communautaires

Questions

Ça fait quoi ?

À partir d’un jeu de règles

  • Le master génère un catalogue décrivant l’état cible
  • Le catalogue est envoyé sur la cible
  • L’agent vérifie pour chaque élément du catalogue si c’est l’état actuel, le cas échéant il change l’état
  • Un rapport est renvoyé au master

Exemple simple

node default {
    service { 'sshd':
        enable  => true,
    }
    package { 'sshd':
        ensure  => latest,
        name    => 'openssh-server',
    }
    file { '/etc/ssh/sshd_config':
        file    => 'puppet:///files/sshd_config',
        notify  => Service['sshd'],
        require => Package['sshd'],
    }
}
Liste exhaustive des types natifs supportés.

Différence entre “type” et “class”

Déclaration d’un type de ressource

define monmodule::montype (
    $variable1 = 'valeur par défaut',
    $variable2,
    ) {
    file { "/etc/httpd/conf.d/${variable1}":
        content => $variable2,
    }
}

Déclaration d’une classe

class monmodule::maclasse (
    $variable1 = 'valeur par défaut',
    $variable2,
    ) {
    package { 'httpd': }
    service { 'httpd': }
    file { '/etc/httpd/httpd.conf':
        content => template('monmodule/httpd.conf.erb'),
        notify  => Service['httpd'],
    }
    monmodule::montype { 'default':
        variable2 => '',
    }
}

Comment charger une classe

Deux manières : la bonne et la mauvaise

La bonne

include monmodule::maclasse

La mauvaise

class { monmodule::maclasse: }
class { monmodule::maclasse:
    variable1 => 'valeur',
}

À la place on met les variables de classe dans hiera.

Arborescence

/etc/puppet
├── auth.conf
├── environments
│   └── production
│       ├── manifests
│       │   └── site.pp
│       └── modules
├── fileserver.conf <!-- Utilisé par les requêtes puppet://[serveur]/loc -->
├── hiera.yaml      <!-- Configuration de l’entrepôt de variables -->
├── manifests
│   └── site.pp
├── modules
├── puppet.conf
│   <!-- Mes recommandations -->
├── hieradata
└── sensitive

/etc/puppet/fileserver.conf

[sensitive]
path /etc/puppet/sensitive/%d/%h
allow *

Hiera

hierdata/

├── common.yaml
├── developement.yaml
├── afpy.org.yaml
├── integration.yaml
└── server1.afpy.org.yaml

common.yaml

---
nginx::confd_purge: true
postgresql::globals::encoding: 'UTF-8'
default_vhost_name: "%{fqdn}"
root_keys:
    - user1
jvm_properties:
    Xmx: 5g

Les fonctions

hiera('key', 'default', 'override')
hiera_array('key', 'default', 'override')
hiera_hash('key', 'default', 'override')

Facter

Permet de récupérer des informations à propos de nœuds.

architecture => x86_64
bios_version => MWPNT10N.86A.0083.2011.0524.1600
blockdevice_sda_model => TOSHIBA DT01ACA1
blockdevice_sda_size => 1000204886016
blockdevices => sda sdb sdc
domain => afpy.org
fqdn => exemple1.afpy.org
hostname => exemple1
interfaces => br0,eth0,lo,virbr0,virbr0_nic
ipaddress => 10.10.12.12
ipaddress6_br0 => 2001::1
is_virtual => false
kernel => Linux
kernelmajversion => 3.10
memoryfree => 2.85 GB
memorysize_mb => 3775.95
operatingsystem => CentOS
operatingsystemmajrelease => 7
os => {"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"0", "full"=>"7.0.1406"}}
osfamily => RedHat
partitions => {"sda1"=>{"uuid"=>"aa6f8f14-9e42-495d-8b1b-2a17849494d0", "size"=>"40957952", "mount"=>"/", "filesystem"=>"ext3"}, "sda2"=>{"uuid"=>"5bca139c-67a4-416c-8d6d-b2eda0404b64", "size"=>"1046528", "filesystem"=>"swap"}}
processorcount => 2
selinux => true
virtual => physical

PuppetDB

  • Base de données
  • Facts
  • Catalogues

Ressources exportées

@@dns::record::aaaa { 'wsgi':
    data => $::ipaddress6,
    zone => $::domain,
}
Dns::Record:Aaaa <<| zone == $::domain |>> 

Anatomie d’un module

modules/monmodule/
├── files
│   └── sshd_config
├── lib
│   ├── facter
│   └── puppet
│       ├── parser
│       ├── provider
│       └── type
├── manifests
│   ├── init.pp      <!-- monmodule                 -->
│   ├── maclasse.pp  <!-- monmodule::maclasse       -->
│   ├── montype.pp   <!-- monmodule::montype        -->
│   └── montype
│       └── autre.pp <!-- monmodule::montype::autre -->
├── Modulefile
├── spec / tests
└── templates
    └── httpd.conf.erb

Questions

Saltstack

Gaston TJEBBES

Un master des minions

Salt-syndic

Questions