Aller au contenu principal

Introduction à Chef Infra

Chef Infra est un gestionnaire de configuration qui fonctionne principalement soit en mode client-serveur, soit en mode autonome. Je me limiterai dans cette présentation au mode autonome qui utilise la commande chef-solo.

Chef Infra prend en charge la configuration des serveurs Linux, Windows, MacOS mais aussi Unix.

Chef ne cesse d'évoluer et c'est ce qui m'a poussé à écrire ce billet. En effet, la plupart des ressources en français datent et font référence à des commandes qui ont été dépréciées ou renommées.

Faire ses premiers pas avec Chef Infra

Terminologie

Dans un premier temps il faut que je définisse le vocabulaire que l'on rencontre, tout tourne autour de la cuisine :

  • cookbook : Les cookbooks, livres de recettes, sont des packages qui regroupent plus recipes qui permettent de configurer un composant spécifique sur les nœuds cibles.
  • recipe : Ce sont les actions qui vont être executées sur les noeuds cibles écrit en Ruby.
  • databags : à définir
  • kitchen : Outils de test.

Installation de Chef-Workstation

Auparavant, on installait le ChefDK mais il a été remplacé par Chef-Workstation qui inclut la plupart des outils nécessaires pour développer des cookbooks.

Pour installer Chef-Workstation, il suffit de se rendre sur le site de Chef pour récupérer les packages à destination de vos machines.

Voilà comment l'installer sur une Ubuntu, une fois le lien récupéré :

wget https://packages.chef.io/files/stable/chef-workstation/21.10.640/ubuntu/20.04/chef-workstation_21.10.640-1_amd64.deb
sudo dpkg -i chef-workstation_21.10.640-1_amd64.deb

On vérifie que tout est bien installé :

chef -v
Chef Workstation version: 21.10.640
Chef Infra Client version: 17.6.18
Chef InSpec version: 4.46.13
Chef CLI version: 5.4.2
Chef Habitat version: 1.6.351
Test Kitchen version: 3.1.0
Cookstyle version: 7.25.6

Passons aux choses sérieuses en écrivant notre premier cookbook.

Générer la structure de notre premier cookbook

Pour ne pas perdre de temps et surtout pour partir sur de bonnes bases, nous allons utiliser la commande chef pour générer notre premier cookbook.

Dans un répertoire vierge, créez un dossier cookbooks et lancez la commande chef generate cookbook dedans.

mkdir cookbooks;cd cookbooks

chef generate cookbook my_first_cookbook
Generating cookbook my_first_cookbook
Loading Chef InSpec profile files:
Loading Chef InSpec input files:
Loading Chef InSpec waiver files:
- Ensuring correct cookbook content
- Committing cookbook files to git

Your cookbook is ready. Type `cd my_first_cookbook` to enter it.
...

Affichons le contenu pour identifier les principaux éléments :

tree .
.
└── my_first_cookbook
    ├── CHANGELOG.md
    ├── chefignore
    ├── kitchen.yml
    ├── LICENSE
    ├── metadata.rb
    ├── Policyfile.rb
    ├── README.md
    ├── recipes
    │   └── default.rb
    └── test
        └── integration
            └── default
                └── default_test.rb

C'est dans le fichier recipes/default.rb que nous allons décrire les actions que notre recette va exécuter.

Ces actions sont déclarées en ruby et contiennent des ressources fournies par chef. Une ressource est décrite de cette manière :

type 'name' do
  attribute 'value'
  action :type_of_action
end

Par exemple, nous allons utiliser la ressource package qui installe des packages sur toutes les distributions prises en charge par Chef.

Dans notre fichier de recette recipes/default.rb, ajoutez ces lignes :

package 'nmap' do
  action :install
end

Comment tester notre Cookbook ?

Mise en place du terrain de test avec Vagrant

Plutôt que de tester nos cookbooks sur notre machine de développement, nous allons utiliser une machine virtuelle instanciée avec Vagrant. Ça tombe bien puisque Vagrant mets à disposition un provisionner chef-solo qui se charge d'installer chef-solo, de copier les cookooks sur la machine cible avant de lancer leurs exécutions.

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu2204"
  config.vm.provision :chef_solo do |chef|
    chef.arguments = "--chef-license accept"
    chef.cookbooks_path = "./cookbooks"
    chef.add_recipe = 'my_first_cookbook'
  end
end

Tester notre premier cookbook sur notre machine cible

Maintenant que notre machine est prête, nous allons lancer sa première exécution :

vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Checking if box 'generic/ubuntu2204' version '4.1.6' is up to date...
==> default: Auto-generating node name for Chef...

...

==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 192.168.121.243:22
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Rsyncing folder: /tmp/test/cookbooks/ => /tmp/vagrant-chef/21e67ad2b7e7c1c72838d8a9db2ffe90/cookbooks
==> default: Running provisioner: chef_solo...
    default: Installing Chef (latest)...
==> default: Generating chef JSON and uploading...
==> default: Running chef-solo...
==> default: [2022-08-25T08:47:14+00:00] INFO: Persisting a license for Chef Infra Client at path /etc/chef/accepted_licenses/chef_infra_client
==> default: [2022-08-25T08:47:14+00:00] INFO: Persisting a license for Chef InSpec at path /etc/chef/accepted_licenses/inspec
==> default: +---------------------------------------------+
==> default: ✔ 2 product licenses accepted.
==> default: +---------------------------------------------+
==> default: [2022-08-25T08:47:14+00:00] INFO: Started Chef Infra Zero at chefzero://localhost:1 with repository at /tmp/vagrant-chef/21e67ad2b7e7c1c72838d8a9db2ffe90 (One version per cookbook)
==> default: Chef Infra Client, version 17.10.3
==> default: Patents: https://www.chef.io/patents
==> default: Infra Phase starting
==> default: [2022-08-25T08:47:14+00:00] INFO: *** Chef Infra Client 17.10.3 ***
==> default: [2022-08-25T08:47:14+00:00] INFO: Platform: x86_64-linux
==> default: [2022-08-25T08:47:14+00:00] INFO: Chef-client pid: 2193
==> default: [2022-08-25T08:47:22+00:00] INFO: Setting the run_list to ["recipe[my_first_cookbook]"] from CLI options
==> default: [2022-08-25T08:47:22+00:00] INFO: Run List is [recipe[my_first_cookbook]]
==> default: [2022-08-25T08:47:22+00:00] INFO: Run List expands to [my_first_cookbook]
==> default: [2022-08-25T08:47:22+00:00] INFO: Starting Chef Infra Client Run for vagrant-d6b95fb9
==> default: [2022-08-25T08:47:22+00:00] INFO: Running start handlers
==> default: [2022-08-25T08:47:22+00:00] INFO: Start handlers complete.
==> default: Resolving cookbooks for run list: ["my_first_cookbook"]
==> default: [2022-08-25T08:47:22+00:00] INFO: Loading cookbooks [my_first_cookbook@0.1.0]
==> default: Synchronizing cookbooks:
==> default: [2022-08-25T08:47:22+00:00] INFO: Storing updated cookbooks/my_first_cookbook/README.md in the cache.
==> default: [2022-08-25T08:47:22+00:00] INFO: Storing updated cookbooks/my_first_cookbook/chefignore in the cache.
==> default: [2022-08-25T08:47:22+00:00] INFO: Storing updated cookbooks/my_first_cookbook/LICENSE in the cache.
==> default: [2022-08-25T08:47:22+00:00] INFO: Storing updated cookbooks/my_first_cookbook/metadata.rb in the cache.
==> default: [2022-08-25T08:47:22+00:00] INFO: Storing updated cookbooks/my_first_cookbook/CHANGELOG.md in the cache.
==> default: [2022-08-25T08:47:22+00:00] INFO: Storing updated cookbooks/my_first_cookbook/recipes/default.rb in the cache.
==> default:
==> default: - my_first_cookbook (0.1.0)
==> default: Installing cookbook gem dependencies:
==> default: Compiling cookbooks...
==> default: Loading Chef InSpec profile files:
==> default: Loading Chef InSpec input files:
==> default: Loading Chef InSpec waiver files:
==> default: Converging 0 resources
==> default: [2022-08-25T08:47:22+00:00] INFO: Chef Infra Client Run complete in 0.339408708 seconds
==> default: Running handlers:
==> default: [2022-08-25T08:47:22+00:00] INFO: Running report handlers
==> default: Running handlers complete
==> default: [2022-08-25T08:47:22+00:00] INFO: Report handlers complete
==> default: Infra Phase complete, 0/0 resources updated in 08 seconds

Vous voyez Vagrant s'est bien chargé d'installer chef-solo et de copier notre cookbook avant de l'exécuter.

Vérifions que nmap a bien été installé sur notre machine :

vagrant ssh
vagrant@ubuntu2204:~$ which nmap
/usr/bin/nmap
nmap -V
Nmap version 7.80 ( https://nmap.org )
Platform: x86_64-pc-linux-gnu
Compiled with: liblua-5.3.6 openssl-3.0.0 nmap-libssh2-1.8.2 libz-1.2.11 libpcre-8.39 libpcap-1.10.1 nmap-libdnet-1.12 ipv6
Compiled without:
Available nsock engines: epoll poll select

Super. Nous pouvons continuer à développer notre recette en piochant dans les ressources mises à notre disposition. La liste se trouve ici

Ajoutons la création d'un user sur notre machine :

package 'nmap' do
  action :install
end

user 'toto' do
  comment 'User toto'
  uid 1234
  gid 'kvm'
  home '/home/toto'
  shell '/bin/bash'
  password '$1$JJsvHslasdfjVEroftprNn4JHtDi'
end

Relançons notre cookbook, mais attention pour que nos modifications soient prises en compte il faut recharger notre machine :

vagrant reload --provision

=> default: Attempting graceful shutdown of VM...
==> default: Creating shared folders metadata...
==> default: Starting domain.
==> default: Waiting for domain to get an IP address...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 192.168.121.243:22
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Host unreachable. Retrying...
...
==> default: Machine booted and ready!
==> default: Rsyncing folder: /tmp/test/cookbooks/ => /tmp/vagrant-chef/21e67ad2b7e7c1c72838d8a9db2ffe90/cookbooks
==> default: Running provisioner: chef_solo...
==> default: Detected Chef (latest) is already installed
==> default: Generating chef JSON and uploading...
==> default: Running chef-solo...
==> default: [2022-08-25T09:01:31+00:00] INFO: Started Chef Infra Zero at chefzero://localhost:1 with repository at /tmp/vagrant-chef/21e67ad2b7e7c1c72838d8a9db2ffe90 (One version per cookbook)
==> default: Chef Infra Client, version 17.10.3
...

Vérifions que notre utilisateur a bien été créé sur la machine cible :

vagrant ssh
id toto
uid=1234(toto) gid=108(kvm) groups=108(kvm)

Utiliser des cookbooks de la communauté

Plutôt que de réinventer la roue, nous allons utiliser les cookbooks mis à disposition par la communauté. Il suffit de faire ses courses dans le supermarket chef.

Attention : Attention vérifier que le cookbook prend en charge votre distribution et ne soit pas trop VIEUX. Je vais tester le cookbook pyenv.

Pour télécharger des cookbooks il faut créer un fichier Berksfile, dans lequel nous allons mettre notre liste de courses :

source 'https://supermarket.chef.io'

cookbook 'pyenv'

Maintenant, nous pouvons le récupérer sur notre machine, pour cela nous allons utiliser l'outil berks :


Resolving cookbook dependencies...
Fetching cookbook index from https://supermarket.chef.io...
Using pyenv (4.1.0)
Vendoring pyenv (4.1.0) to cookbooks/pyenv

Si vous regardez dans le répertoire cookbooks, vous y trouverez le cookbook. Il faut maintenant y ajouter notre recette. Créer un dossier recipes avec le fichier default.rb :

mkdir -p cookbooks/my_first_cookbook/recipes/

Mettez-y ce contenu (exemple récupéré dans le projet source) :

# Install Python system wide
# and make it the global default

version = '3.7.7'
local_folder = '/opt/pyenv_test'

directory local_folder

pyenv_install 'system'

# pyenv_rehash 'for-new-python'

pyenv_python version

pyenv_local version do
  path local_folder
  user 'root'
end

pyenv_global version

pyenv_plugin 'virtualenv' do
  git_url 'https://github.com/pyenv/pyenv-virtualenv'
end

pyenv_pip 'requests' do
  version '2.18.3'
end

En quelques mots, nous demandons à installer pyenv au niveau system et python dans sa version 3.7.7. On installe également le plugin pyenv-virtualenv et le package requests avec pyenv_pip.

Avant de le lancer il faut ajouter la recette pyenv à notre le Vagrantfile :

Vagrant.configure("2") do |config|
  config.vm.box = "generic/ubuntu2204"
  config.vm.provision :chef_solo do |chef|
    chef.arguments = "--chef-license accept"
    chef.cookbooks_path = "./cookbooks"
    chef.add_recipe "my_first_cookbook"
    chef.add_recipe "pyenv"
  end
end

On lance le tout :

vagrant reload --provision

Plus d'infos