Aperçu

Formations préalables

Temps estimé

Objectifs

Préparation des participant.e.s

Avant la formation, chaque participant.e devrait valider ses accès aux machines virtuelles.

Si vous participez à la formation et que vous ne faites pas partie de l'équipe sysadmin de Koumbit, assurez-vous d'avoir un client ssh qui soit fonctionnel: les exercices seront exécutés sur des machines virtuelles accessibles sur internet via SSH.

Préparation de la part de l'animateur.trice

Pour une formation à l'équipe infra de Koumbit:

Pour les formations externes à Koumbit:

Qu'est-ce que c'est Puppet et quel est son rôle?

Puppet c'est un logiciel qui sert de service de gestion centralisée de configurations. Comme le terme l'indique, grâce à ce logiciel on peut imposer une configuration sur des serveurs et avoir un seul point à partir d'où exercer ce contrôle. C'est une des idées fondamentales de l'infrastructure en tant que code (nous en verrons un peu plus sur ce terme dans la prochaine section).

Dans l'idée précédente, par configuration on veut dire tout ce qui défini qu'est-ce qui s'exécute sur une machine et comment. Donc quels logiciels sont installés, quels fichiers sont créés et quel est leur contenu pour que les logiciels se comportent de la façon dont on l'espère, mais également quels services (daemons) doivent être actifs.

La gestion centralisée de configurations permet donc en fait d'automatiser l'installation et la configuration de serveurs. Quelques avantages remarquables par rapport à ça sont:

Le problème de gestion automatisée de machines n'est pas un problème simple. Puppet rembli bien le rôle de représenter une configuration désirée sous forme de code, envoyer ce code du serveur aux clients, puis appliquer ce code pour que l'état désiré sur la machine soit bien en place.

Par contre il nous faudra utiliser quelques logiciels additionnels pour certaines autres tâches spécifiques. Donc en fait quand on commence à utiliser Puppet, on plonge en fait dans une suite de logiciels inter-reliés qui permettent de remplir au total la fonction complexe de gestion de configuration. Nous verrons dans une section plus bas quels sont les autres logiciels qui accompagnent généralement Puppet et un peu plus bas encore comment Puppet interagit avec ces outils (nous n'aurons pas besoin nécessairement d'interagir directement avec chacun mais il est tout de même important de connaître leur existance et leur rôle).

Serveur vs. client

Puppet utilise un modèle de diffusion d'information où les agents (clients) "tirent" ("pull") leur état en demandant au serveur de leur fournir. C'est alors l'agent qui appliquera la configuration fournie par le serveur et qui fera les changements nécessaire. Donc si l'agent ne fonctionne pas, les changements ne se font pas (donc il est important de s'assurer que ce mécanisme est en bon état).

Par contraste, certains autres outils qui remplissent la même fonction que puppet utiliseront un modèle où l'outil lui-même se connectera sur la machine pour y imposer ("push") la configuration et les changements.

Donc puppet utilise le concept de serveur vs. client pour que les clients obtiennent leur configuration d'un seul point central.

puppet_run_lifecycle.jpg

  1. l'agent se connecte de manière périodique au serveur, obtient les facts de la part de facter et les envoie au serveur pour lui demander s'il y a des changements à appliquer

  2. le serveur compile le code, qu'on appellera manifestes, écrit par les administratrices.teurs sous un format plus compacte et facile pour le programme client à utiliser. Le code compilé, qu'on appellera catalogue, est alors envoyé à l'agent ainsi que tout contenu de fichier nécessaire pour que l'agent puisse appliquer les changements requis.

  3. l'agent applique le catalogue sur la machine où il s'exécute, puis envoie au serveur un rapport d'exécution qui indique s'il y a eu des erreurs d'application et combien, et aussi combien de temps ça aura pris à l'agent pour appliquer les changements qui amènent la machine à l'état décrit par le catalogue.
  4. le serveur peut réacheminer le rapport d'exécution à un service de stockage tel que PuppetDB

Dans le cas de Puppet, il existe des clients pour *nix (e.g. FreeBSD, OpenBSD, etc), Linux, MacOS X et Windows, donc on peut contrôler des machines de toutes ces plateformes là sous un même serveur central!

Configuration sans serveur

Comme on le verra un peu plus tard, Puppet fournit une commande qui applique des changements sans les demander à un serveur central. On peut appliquer des changements soit en donnant le code directement via un argument, soit en pointant l'outil vers un fichier qui contient le code que l'on veut appliquer.

Ça veut donc dire qu'il est possible d'utiliser puppet sans le serveur centralisé. Ce genre de configuration là ne permettra par contre pas, ou bien avec plus de difficulté, l'échange d'information entre les serveurs (comme par exemple avec le modèle serveur-client on peut configurer automatiquement un service de monitoring selon quels services sont installés par puppet sur d'autres machines)

Code déclaratif

Les développeurs du logiciel Puppet ont fait un choix important dès la conception initiale de l'outil, et qui se démarque encore des outils alternatifs: l'outil s'attend à recevoir une déclaration de quel est l'état final d'une machine, et non quelles sont les instructions pour se rendre à l'état final. Donc le code Puppet utilise un modèle déclaratif -- ça veut dire que lorsqu'on écrit des manifestes on veut spécifier ce qui doit être présent sur la machine.

Tout l'aspect procédural de comment changer les choses pour se rendre à l'état déclaré est caché "sous le capot". Il y du code pour chaque type de ressource qui sait comment créer, retirer et modifier les choses sur la machine pour pouvoir se rendre à l'état désiré. Donc on n'a pas besoin de savoir comment faire les changements, mais seulement de demander à puppet de les faire pour nous. Donc quand on écrit du code Puppet, on se soucie seulement de qu'est-ce que l'état final doit être.

Le code à nature déclaratif utilise une propriété très importante pour éviter de toujours apporter des changements à une machine: Le code a une idempotence d'exécution: on peut lancer Puppet autant de fois qu'on veut et celui-ci ne devrait pas refaire les modifications si elles ne sont pas nécessaires. En d'autre mots, si une ressource correspond déjà à l'état souhaité, elle ne subira pas de changements.

L'infrastructure en tant que code (Infrastructure as Code)

Voir: https://fr.wikipedia.org/wiki/Infrastructure_as_code

L'idée qui a été nommée Infrastructure as code est un concept relativement simple mais qui a permis de complètement refaçonner la nature du travail d'administration de serveurs. C'est une des idées fondatrices de ce qui est souvent appelé DevOps.

Au lieu de gérer une infrastructure à l'aide d'une série de procédures manuelles, on représente ce que cette infrastructure devrait être dans des instructions (du code) qui est exécuté par des logiciels. Le travail de gestion d'une infrastructure devient donc en partie du travail de développement de logiciel -- d'où l'idée du nom DevOps, ou la fusion entre le développement et les opérations!

L'idée d'abstraire la représentation d'une infrastructure en tant que code apporte les avantages suivant:

Quels autres outils accompagnent généralement Puppet?

Comme on l'a déjà mentionné plus tôt, Puppet est généralement accompagné d'outils additionnels qui remplissent une fonction spécifique complémentaire. On peut utiliser plusieurs des outils plus bas directement sur la ligne de commande pour interroger les informations spécifiques que chacun permet d'obtenir, mais lors de l'utilisation de Puppet ces outils seront intégrés de manière transparente. Voici une liste des outils les plus communs et importants qui se rattachent à Puppet:

Jargon utilisé autour du logiciel Puppet

puppet_software_blocks.jpg

agent
Client Puppet. C'est le logiciel qui roule sur la majorité des machines et qui demande au serveur de lui fournir son code de configuration. C'est également l'agent qui applique les modifications nécessaires selon ce que le serveur a spécifié.
serveur

(était anciennement nommé puppet master) point central de l'infrastructure qui fournit aux clients la configuration. Cette machine est spéciale et contient beaucoup d'information sensible (puisqu'elle connaît toute la configuration, les mots de passe, les certificats, etc.) de toutes les machines. On veut donc s'assurer de la protéger de manière stricte!

manifest

nom donné aux fichiers qui contiennent du code Puppet. Ces fichiers auront normalement une extension .pp. Les manifests sont utilisés pour décrire plus qu'une seule machine: le même code peut s'adapter selon différentes valeurs, soit provenant des facts, soit de hiera

catalogue

C'est le code Puppet qui est propre à une seule machine et qui a été compilé à partir des manifests. un catalogue est un format de type byte-code du code Puppet. L'agent peut utiliser le catalogue pour appliquer les changements qui lui sont nécessaires. Comme un catalogue est spécifique à une machine, chaque agent ne connaît pas les configurations des autres machines

fact

une donnée extraite par l'outil facter. cette donnée ne changera pas durant la compilation du catalogue et elle peut être utilisée par le code pour créer des configurations différentes selon les valeurs des facts. Les facts sont disponible dans le code sous la variable globale $facts (tableau de données)

ressource
Bloc de construction de base dans le code Puppet. Chaque ressource représente une chose qui doit être présente sur la machine où l'agent s'exécute. Plusieurs types de ressources existent déjà dans Puppet, et on peut en créer des nouveaux.
ressource exportée

Représentation d'une ressource dans une structure de données qui est sauvegardée dans la base de données de PuppetDB. On peut ensuite importer cette ressource sur une ou plusieurs autres machines. (dans la documentation, l'importation est nommée collecting resources)

paramètre
une paire de clef et valeur qui modifie le comportement d'une ressource. C'est un peu comme un paramètre de fonction dans du code: la clef identifie ce qu'on modifie, et la valeur nous permet de donner une valeur différente pour chaque ressource.
classe

type de ressource de base qui est utilisé dans les manifests pour regrouper plusieurs autres ressources ensemble dans un bloc logique. Identifié dans le code par le mot class. C'est un conteneur pour du code plus précis. Une classe n'est traitée qu'une seule fois par machine lors de la compilation des catalogues -- ça nous assure ainsi qu'un certain groupe de ressources est présent, mais pas plus d'une fois. Les classes peuvent avoir des paramètres, défini dans le code lors de la construction de la classe, pour modifier son comportement.

types de données

les paramètres des ressources peuvent être contraint à utiliser un certain type de données en particulier. si on rend le type de données le plus spécifique possible, ça nous permet de réduire les imprévus dans le code. Il existe plusieurs types de données de base dans Puppet, et on peut également en créer de nouveaux en combinant les types de bases. Le module stdlib écrit par Puppetlabs contient plusieurs types complexes additionnels qui sont très pratiques (par exemple pour représenter une chaîne de caractères qui devrait être une adresse IP)

type défini

type de ressource de base qui regroupe plusieurs autres ressources ensemble. attention! ici on se réfère à un type de ressource alors que les types de données se réfèrent à des paramètres (la surcharge du mot "type" peut facilement devenir mélangeante). identifié dans le code par le mot define. C'est très similaire à une classe! Mais la différence est qu'un type défini peut être utilisé plusieurs fois dans une même machine dans le but de déclarer plusieurs choses différentes. Un exemple de cas d'utilisation pourrait être un vhost apache. tout comme pour les classes, les types défini peuvent avoir des paramètres définis dans le code qui permettent d'en modifier le comportement

fonction

Code, généralement écrit en ruby, qui permet de modifier une certaine donnée. Par exemple on pourrait utiliser la fonction join() pour prendre toutes les valeurs d'un tableau de données et les coller ensemble dans une seule chaîne de caractères avec chaque valeur séparée par un délimiteur. Les fonctions sont exécutées sur le serveur puppet lors de la compilation du catalogue.

module

regroupement de manifests, de définitions de fonctions, et d'autres fichiers pour former un bloc logique de code. Le plus souvent un module représente tout ce qui est nécessaire pour l'installation et la configuration d'un logiciel particulier. Par exmple le module mysql installe et configure mysql.

Exercice: Découvrir de l'information à propos d'une machine à l'aide de facter

On peut lancer manuellement l'outil facter pour découvrir les mêmes informations à propos d'une machine que Puppet trouverait lors de son exécution.

On peut demander une information précise:

facter processors.count

On peut séparer les noms des valeurs demandées par un . ce qui veut dire dans l'élément de gauche, chercher l'élément de droite, e.g. l'élément processors est en fait un tableau de données qui contient un élément qui s'appelle count.

facter

Sans donner de nom de valeur, on obtient toutes les valeurs connues par facter.

Trouver dans la réponse de la commande:

Demander à facter seulement la valeur de la version majeure de la distribution linux du système.

Lorsque puppet demande de l'information à facter, certaines informations additionnelles sont affichées. On peut demander à facter de nous les afficher en ajoutant un argument:

facter -p

Identifier la version de puppet dans la réponse de l'outil

Il est à noter: toutes les valeurs qui sont présentes dans la réponse de la commande facter sont accessibles au code puppet à travers la variable globale $facts.

Pour accéder à un fact spécifique dans du code puppet, on doit utiliser des crochets pour accéder à un élément du tableau.

Dans les quelques exemples suivant, on utilise la ressource de type notify pour afficher le contenu de la variable sur le terminal dans la réponse du client puppet:

notify { $facts['package_provider']: }  # identifie le logiciel qui est utilisé pour l'installation de packages
notify { $facts['processors']['count']: }  # le nombre de processeurs dans la machine

Comment est-ce que Puppet communique avec les différents outils?

Relations entre le puppetmaster et les autres sources de données

Communication entre agent et serveur

facter

hiera

PuppetDB

git

Exercice: Se familiariser avec l'agent (client) Puppet

L'outil de ligne de commande de Puppet s'appelle puppet (tout en minuscules). puppet offre des détails sur comment on peut l'utiliser:

# Cette commande vous offre une série de sous-commandes possibles à utiliser.
puppet --help
# Pour obtenir de l'aide à propos d'une des sous-commandes, on peut utiliser la sous-commande 'help':
puppet help agent
puppet help apply

Comme le nom de la sous-commande l'implique, agent permet de rouler en tant qu'un agent, et donc d'obtenir les modifications à partir d'un serveur central.

# en premier lieux, on veut activer l'agent, qui a été désactivé pour le début de la formation
# en temps normal, l'agent devrait rester activé en tout temps, sauf si on veut explicitement
# mettre l'agent sur pause pour investiguer quelque chose sur la machine et éviter que puppet ne
# change quelque chose pendant notre investigation
puppet agent --enable
# lancer l'agent. l'option -t active la trace des activités de l'agent à l'écran
puppet agent -t`
## Constater ici dans la réponse les différentes étapes suivies par l'agent ainsi que qu'est-ce qui a été modifié

La sous-commande apply permet de faire des modifications sur la machine en utilisant du code soit passé en argument, soit via un fichier qui se trouve sur la machine même (contrairement au cas de l'agent où les fichiers de code se trouvent obligatoirement sur le serveur).

# -e permet de donner le code sur la ligne de commande
puppet apply -e 'file { "/tmp/hello_world": ensure => present, content => "mon premier fichier"}'
## Constatez que le fichier a bel et bien été modifié sur la machine.
# Donc il faut faire attention si on test quelque chose via `puppet apply` puisque le changement est vraiment appliqué.
# on peut ajouter --noop à la commande pour que `puppet apply` n'effectue pas les changements de mandés sur la machine.
# l'outil affiche alors seulement quels seraient les changements qui auraient été appliqués, mais sans les faire.

# ici au lieu d'utiliser -e, on donne un nom de fichier (qui existe présentement sur disque)
# pour que le code dans ce fichier soit appliqué
puppet apply /etc/puppet/code/environments/production/brise.pp
## Ce fichier nous donne une erreur! Constater quel est le format de cette erreur et tenter de corriger cette erreur
## Le fichier comprend en effet plusieurs erreurs. Continuez d'appeler `puppet apply` pour vérifier quelles nouvelles erreurs
## l'outil affiche et tentez de les corriger dans le fichier, jusqu'à ce que puppet effectue les changements sans erreur

En utilisant puppet apply -e '...' comme plus haut, et en vous basant sur les exemples dans la section d'exercice par rapport à facter, affichez la capacité totale de mémoire système (RAM).

Quelques exemples simples de structures du langage Puppet

On plongera beaucoup plus en détail dans le langage de programmation Puppet dans la FormationPupppetDSL. Cependant, pour pouvoir commencer à explorer puppet tout de suite, nous verrons ici quelques idées de base qui nous permettront d'exprimer les choses les plus imporantes: déclarer une ressource et ordonnancer l'application des changements pour chacune.

Commentaires

Comme dans tous les langages de programmation, il est très utile d'ajouter des commentaires dans le code que l'on écrit pour offrir des explications additionnelles comme par exemple pourquoi certains cas spéciaux devraient être présent ou encore quel est le comportement qu'un paramètre modifie et quelles en sont les valeurs possibles.

Les commentaires dans le code Puppet commencent par un dièse #. On peut placer un dièse en début de ligne pour avoir toute une ligne en commentaire, ou alors placer un dièse à la droite d'une ligne de code pour ajouter un commentaire sur la même ligne que le code.

Par exemple (ici les mots @summary et @param sont utilisés par l'outil puppet-strings pour créer la documentation pour un fichier de code):

# @summary Ce commentaire décrit en général ce que le bloc de code fait, et comment on peut
#   modifier son comportement.
#
# @param blah
#  Nombre entier qui permet de spécifier combien de `blah` se retrouvent dans le fichier de configuration `foo`
#
class foo (
  Integer $blah = 1,  # 1 ici c'est la valeur par défaut si "blah" n'est pas spécifié
)
{
  # ...
}

Ressources de base dans Puppet

Puppet contient déjà du code pour représenter plusieurs types de choses dans un ordinateur. La liste complète est visible dans la documentation de puppet (C'est une page très utile à garder en marque-page)

Avec les types de ressources de base, on peut déjà configurer une grande majorité des services possibles. On peut également créer des types de ressources plus complexes qui contiennent plusieurs ressources de base d'une certaine façon spécifique (à l'aide de classes et types définis). Nous verrons ces ressources complexes dans une formation future.

Les ressources de base qui sont utilisées de manière la plus commune sont, en ordre:

Relations d'ordre entre les ressources

Dans le code Puppet on déclare qu'est-ce qui devrait être contenu dans une machine. Mais des fois, il faut absolument qu'une chose existe avant qu'une autre puisse exister.

Par exemple, avant de pouvoir configurer un logiciel, il faut que celui-ci soit installé.

On peut déclarer l'ordre entre deux ressources en utilisant l'opérateur -> (flèche à droite) entre les deux ressources. Ça indique à Puppet que la ressource qui précède (est à gauche de) la flèche doit être traitée avant celle qui suit la flèche.

Par exemple:

# Le répertoire my.conf.d doit exister pour qu'on puisse créer des fichiers dedans
file { '/etc/mysql/my.conf.d':
  ensure => directory,
  owner  => 'root',
  group  => 'mysql',
  mode   => '0700',
}
-> file { '/etc/mysql/my.conf.d/tuning.conf':
  ensure => present,
  owner  => 'root',
  group  => 'root',
  mode   => '0640',
}

On peut également avoir une relation d'ordre qui en plus envoie un signal à la ressource qui suit la flèche. On utilise pour ceci une flèche avec un tilde au lieu du tiret, ~>.

Ce ne sont pas tous les types de ressources qui réagissent à un signal. Le plus commun type de ressource utilisé avec ce type d'ordonnancement est service.

Lorsqu'un changement est apporté à la ressource précédent un service dans une relation de flèche avec tilde (avec signal), le service sera alors redémarré automatiquement. Ça nous assure ainsi que les changements que puppet a apporté à la configuration seront pris en compte immédiatement par un service.

Le service dans ce cas ne sera pas redémarré dans les cas où Puppet considère qu'aucun changement n'a été nécessaire aux ressources précédent les flèches avec tilde (donc si la configuration ne change pas, on ne redémarre pas le service pour rien)

Par exemple:

file { '/etc/apache2/conf-enabled/security.conf':
  ensure => link,
  target => '/etc/apache2/conf-available/security.conf',
}
~> service { 'apache2':
  ensure => running,
}

Avec les deux types de flèches, on peut utiliser l'opérateur flèche plusieurs fois pour définir des relations de plusieurs ressources avec une seule ressource finale. On peut donc par exemple s'assurer que plusieurs fichiers de configuration devront exister avant qu'un service soit lancé et également que le service soit redémarré si n'importe lequel des fichiers de configuration subit une modification.

Nous verrons les relations d'ordonnancement plus en détail dans une formation future.

Quelques outils alternatifs à Puppet

Exercice: Ecrire un premier script

Voilà, vous avez reproduit le pattern qui est utilisé dans environs 80 à 90% des cas pour la gestion de différents logiciels sur les serveurs! :)

Dans le cas de la gestion via le serveur, la différence c'est simplement que le fichier manifeste, test.pp, devrait se trouver au bon endroit sur le serveur au lieu du client, et à ce moment on l'applique en appelant puppet agent -t.

Rétrospective

Pendant un maximum de 15 minutes, les participant.e.s sont invité.e.s à partager les éléments qui ont bien ou moins bien fonctionnés et les idées qui pourraient survenir pour des manières d'améliorer le processus.

Quelques éléments qui peuvent faire partie de la rétrospective, dépendant de la grosseur du projet ou de la formation:

  • Sommaire collectif (e.g. résumé rapide en termes que tout le collectif peut comprendre)
    • Pas trop utile pour les projets vraiment simples ou les formations.

  • Chronologie des événements marquant pour le projet
    • Surtout utile pour les projet qui se sont étalés sur plusieurs jours ou plus ou bien quand beaucoup de choses se sont produites simultanément, ce qui a rendu la compréhension des influences de chaque événement complexe.

  • Les bons coups -- qu'est-ce qui a bien fonctionné et qu'on veut tenter de reproduire
  • Les problèmes
    • échecs -- avec l'aide de la chronologie (si elle a été faite), tenter de situer les échecs dans un contexte selon ce qui était connu des participant.e.s aux moments qui ont mené à l'échec
    • problèmes techniques
    • manques de ressources
    • perturbations externes
  • Une liste d'actions à court et/ou à plus long terme pour améliorer les choses telles que soulignées pendant les points précédents
    • Transférer les actions dans redmine pour qu'elles puissent être suivies!

N'hésitez pas à partager les échecs à l'extérieur de l'équipe puisqu'on peut apprendre beaucoup de ceux-ci, mais surtout évitez de les formuler comme un blâme sur la/les personne(s) ayant échoué.

Une rétrospective est surtout utile quand on la partage: ça permet aux autres d'apprendre de nos erreurs et aussi de nos idées d'améliorations. On peut par exemple envoyer une forme écrite par email, ou bien sauvegardée comme page wiki.

Information complémentaire


CategoryFormation CategoryFormationPublique

FormationPuppetIntroduction (last edited 2023-07-20 13:57:22 by virgile)