Cuisinez vos serveurs comme un Chef – Seconde partie

Section intitulée initialisation-du-projetInitialisation du projet

Nous avons mis en place, dans un premier article, tout l’infrastructure nécessaire pour écrire nos premiers scripts Chef. Pour initialiser notre projet Chef, il suffit d’utiliser la commande suivante (Placez vous dans le répertoire de votre VM Vagrant avant d’exécuter la commande) :

cd /chemin/box/vagrant
knife solo init chef

Cette commande vient de créer le répertoire chef avec l’arborescence suivante :

chef/
├── cookbooks/
├── data_bags/
├── nodes/
├── roles/
├── site-cookbooks/
└── solo.rb

Le seul répertoire qui va nous intéresser pour le moment est le repertoire cookbooks (À ne pas confondre avec le dossier site-cookbooks, qui par convention contient les dépendances). Ce dernier contient, comme son nom l’indique, un ensemble de cookbooks, des « livres de recettes » qui fournissent des scripts Ruby permettant l’installation d’un ou plusieurs applicatifs et leurs configurations

Section intitulée initialisation-de-notre-premier-livre-de-recetteInitialisation de notre premier livre de recette

Initialiser notre recette

Nous allons commencer par écrire notre premier cookbook sur PHP. Pour cela rien de plus simple, placez vous dans le répertoire de votre box Vagrant et exécutez la commande suivante :

knife cookbook create php -o cookbooks

Nous venons de créer notre livre de recette PHP dans le dossier cookbooks, avec cette arborescence :

chef/
└── cookbooks/
    └── php/
        ├── attributes/
        ├── definitions/
        ├── files/
            └── default/
        ├── libraries/
        ├── providers/
        ├── recipes/
            └── default.rb
        ├── resources/
        ├── templates/
            └── default/
        ├── CHANGELOG.md
        ├── README.md
        └── metadata.rb

Recipes, attributes et templates sont les trois répertoires qui nous intéressent pour le moment.

Section intitulée creation-de-notre-premiere-recetteCréation de notre première recette

Chaque fichier Ruby (.rb) du dossier recipes est une recette décrivant l’installation d’un logiciel, le fichier default.rb étant la recette par défaut. Dans la recette par défaut, nous voulons installer PHP, notre fichier va donc ressembler à cela :

package "php5"

Nous spécifions à Chef d’utiliser le package manager de l’OS pour installer PHP. Rien de plus compliqué pour le moment ; il nous reste plus qu’à tester notre recette !

Section intitulée tester-nos-recettesTester nos recettes

Pour voir notre recette à l’œuvre, nous allons utiliser la box Vagrant installée dans l’article précédent. Ouvrez le fichier de configuration de Vagrant (VagrantFile) et remplacez son contenu par le suivant :

Vagrant::Config.run do |config|
  config.vm.box = "lucid64"
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "chef/cookbooks"
    chef.roles_path     = "chef/roles"
    chef.data_bags_path = "chef/data_bags"
    chef.add_recipe "php"
  end
end

Maintenant il ne reste plus qu’à relancer notre box Vagrant, ce qui va automatiquement partager les répertoires de vos recettes et effectuer la provision :

vagrant reload

Il se peut que vous ayez quelques problèmes, la box utilisée dans cette article est un peu vieille et les paquets ne sont plus à jour : apt-get va donc certainement renvoyer une erreur. Avant de relancer la box, il est conseillé de mettre à jour les paquets (nous verrons dans un prochain article comment éviter ce genre d’erreur) par le biais des commandes suivantes :

vagrant ssh
sudo apt-get update

Section intitulée et-c-est-toutEt c’est tout ?

Mauvaise recette

Autant vous le dire de suite : cette recette est nulle… Pourquoi ? Ceux qui possèdent une box sur Centos vont vite comprendre :-). Nous avons demandé l’installation du paquet php5, alors que sur d’autres systèmes ce paquet peut avoir un autre nom : par exemple, il s’appelle php sur Centos/Rhel 6.x ou encore php53 sur Centos/Rhel 5.x.

De plus, le paquet PHP va installer par défaut le paquet apache2 et ses dépendances alors que, pour rappel, nous avons besoin d’une machine qui effectue des traitement PHP en mode cli, et donc apache nous est inutile.

Le paquet qui correspond le mieux à notre besoin serait donc php5-cli avec php-common (ou php-cli ou php53-cli…). Changeons donc notre recette :

pkgs = value_for_platform(
  %w(centos redhat scientific fedora) => {
    %w(5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8) => %w(php53-cli php53-common),
    'default' => %w(php-cli php-common)
  },
  [ "debian", "ubuntu" ] => {
    "default" => %w{ php5-cli php5-common }
  },
  "default" => %w{ php5-cli php5-common }
)

pkgs.each do |pkg|
  package pkg do
    action :install
  end
end

La première ligne va créer une liste selon le système d’exploitation utilisé et sa version, tout en permettant de spécifier un ensemble de paquets par défaut quand le système n’est pas listé.

Par exemple, pour Centos 5.0 à 5.9, cela retourne un tableau contenant php53-cli et php53-common. Chaque valeur sera ensuite considérée comme un paquet à installer.

Notre recette est maintenant valide sur Debian/Ubuntu/Centos/Redhat/Scitentific/Fedora.

Il nous reste plus qu’à la tester… Sauf que… Dans la recette précédente, nous avons installé php5 avec toutes ses dépendances, et comme nous sommes des gens propres il serait préférable de tester avec un système nu. En effet, notre recette ne va strictement rien faire, les paquets php5-cli et php5-common étant déjà installé par dépendance du paquet php5. Vagrant devient alors très utile, car il suffit juste de supprimer et recréer la box :

vagrant destroy
vagrant up

Et si nous voulons simplement rejouer notre recette ? Si, par exemple, le script que nous avons écrit plante à cause d’une erreur, il n’est pas nécessaire de relancer ou supprimer/recréer notre box : en effet, Vagrant possède une commande qui permet de jouer uniquement les scripts de provisionnement :

vagrant provision

Section intitulée allons-un-peu-plus-loin-avec-chef-template-amp-attributesAllons un peu plus loin avec Chef : Template & Attributes

PHP est maintenant installé sans aucun serveur Web, et nous aimerions bien pouvoir le configurer avec nos propres paramètres. Pour cela, nous utilisons la notion de template fournie par Chef. Un « template » est juste un fichier qui est copié depuis le cookbook vers un dossier du serveur.

Section intitulée creation-d-un-templateCréation d’un template

Tout d’abord, il faut créer un fichier de configuration php.ini.erb dans notre cookbook à l’emplacement suivant (erb est une implémentation de eRuby, un système de templating Ruby) :

chef/
└── cookbooks/
    └── php/
        └── templates/
            └── default/
                └── php.ini.erb

Collons-y le contenu suivant :

https://gist.github.com/joelwurtz/5188891

Une fois notre fichier créé, il suffit de spécifier dans la recette le remplacement du fichier par défaut de PHP par ce dernier : rajoutons pour cela les lignes suivantes à la fin de notre script (dans le fichier default.rb) :

template  "/etc/php5/cli/php.ini" do
  source "php.ini.erb"
  owner  "root"
  group  "root"
  mode   "0644"
end

En plus du remplacement, nous indiquons aussi, au passage, les droits et le propriétaire du fichier. Rejouons maintenant notre provisionnement pour appliquer ces changements :

vagrant provision

En inspectant le fichier sur le serveur, nous constatons qu’il possède le même contenu :

vagrant ssh
more /etc/php5/cli/php.ini

Section intitulée injection-de-parametres-dans-notre-templateInjection de paramètres dans notre template

Ce fichier de configuration est statique, et par défaut PHP va être executé avec 128Mo de ram, ce qui peut être suffisant pour l’instance de développement locale, mais risque d’être limitant sur le serveur de production, qui va traiter beaucoup plus de données. Comme nous l’avons vu, le fichier php.ini du livre de recettes est un template erb, et il est donc tout à fait possible de lui passer des variables. Modifions cette ligne dans le template :

memory_limit           = 128Mo

en :

memory_limit           = <%= @memory_limit %>

Et passons la variable memory_limit au template :

template  "/etc/php5/cli/php.ini" do
  source "php.ini.erb"
  owner  "root"
  group  "root"
  mode   "0644"
  variables({
    :memory_limit => "256Mo"
  })
end

Section intitulée utilisation-des-attributsUtilisation des attributs

Nous pouvons donc passer des variables au template, mais cela ne résout toujours pas notre problème : la valeur est figée dans la recette. Pour gérer différentes valeurs selon différents serveurs, Chef possède une notion d’attributs, qui permettent de personnaliser des valeurs de paramétrage. Tout d’abord, déclarons un attribut en créant un fichier default.rb à l’emplacement suivant :

chef/
└── cookbooks/
    └── php/
        └── attributes/
            └── default.rb

Avec le contenu suivant :

default['php']['memory_limit'] = "128Mo"

Puis modifions la recette pour qu’elle aille chercher la variable depuis l’attribut.

template  "/etc/php5/cli/php.ini" do
  source "php.ini.erb"
  owner  "root"
  group  "root"
  mode   "0644"
  variables({
    :memory_limit => node[‘php’][‘memory_limit’]
  })
end

Ainsi par défaut, la valeur dans le fichier php.ini est de 128Mo, mais il est tout à fait possible de la surcharger, et c’est ce que nous allons faire dans le fichier de configuration de Vagrant :

Vagrant::Config.run do |config|
  config.vm.box = "lucid64"
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "chef/cookbooks"
    chef.roles_path     = "chef/roles"
    chef.data_bags_path = "chef/data_bags"
    chef.add_recipe "php"
    chef.json = {
        "php" => {
            "memory_limit" => "1024Mo"
        }
    }
  end
end

Il ne reste plus qu’à tester en exécutant une nouvelle fois le provisionnement :

vagrant provision

Section intitulée one-more-thingOne more thing

Avec cette recette, il reste encore un problème : nous partons en effet du postulat que php.ini se situe à l’emplacement /etc/php5/cli/php.ini, ce qui est faux pour certains systèmes, notamment ceux basés sur Redhat. Modifions en conséquence nos différents fichiers :

Fichier d’attributs :

default['php']['memory_limit'] = "128Mo"

case node["platform_family"]
when "rhel", "centos"
  default['php']['conf_dir']      = '/etc'
when "debian", "ubuntu"
  default['php']['conf_dir']      = '/etc/php5/cli'
else
  default['php']['conf_dir']      = '/etc/php5/cli'
end

Fichier de recette :


…

template  "#{node['php']['conf_dir']}/php.ini" do
  source "php.ini.erb"
  owner  "root"
  group  "root"
  mode   "0644"
  variables({
    :memory_limit => node['php']['memory_limit']
  })
end

Nous pouvons maintenant tester sur différentes box Vagrant, qu’elles soient basées sur un système Debian ou Redhat \o/

Section intitulée a-la-prochaineÀ la prochaine…

Next time

Les trois notions expliquées dans cet article – recette, template et attributs – sont la base de Chef, et rien qu’avec cela vous pourrez d’ores et déjà créer de nombreuses recettes. Mais Chef ne s’arrête pas la, je vous montrerai des notions plus avancées dans un article suivant : ressources, définitions, noeuds et rôles sont au programme, avec peut-être quelques extras ! Si vous voulez allez plus loin sans attendre les articles suivants, vous pouvez dés maintenant consulter les nombreux cookbooks créés par la communauté.

Section intitulée petit-plusPetit plus

J’en profite aussi pour vous proposer un cookbook PHP écrit par nos soins : à l’instar de celui qui est proposé officiellement par Opscode, celui-ci ne dépend pas de PEAR ni d’apache, et propose de nombreuses extensions pour PHP, ainsi qu’une recette pour Composer. Il sera activement mis à jour selon nos différents besoins, mais une extension en plus ou une correction de bug étant toujours la bienvenue, n’hésitez pas à contribuer !

Commentaires et discussions

Nos articles sur le même sujet

Ces clients ont profité de notre expertise