Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mon héritage

Ce livre est l'héritage de mes connaissances, en fonction du temps que j'ai pour l'écrire, et ce que je pense à écrire.

Mon expérience

Même si j'ai connu MS-DOS, Windows 3.1, Windows 95, ce n'est qu'à la découverte de GNU/Linux que mon aventure informatique démarre rééllement.

Et même si j'ai testé beaucoup de distros, il est possible de ce contenter de cette timeline grossière:

AnnéeDistro/OS
1997Linux Slackware
1998Redhat
2000Debian
2005Gentoo
2008Archlinux
2024NixOS

Solutions à des problèmes

Hardening

Filesystem

Empêcher une application de saturer le disque système, par exemple via l'écriture de logs.

Services

Restreindre les droits d'un service

ZFS

ZFS est un système de fichier incroyable, qui résoud un ensemble de problèmes "du quotidien" de manière élégante et fiable.

Ce système de fichier a tellement bousculé l'univers des systèmes de fichiers qu'il a créé une concurrence, qui du coté du monde linux s'appelle Btrfs (mais qui n'est pas au niveau).

Ces dernières années, j'ai eu de nombreuses occasions de sortir ce fabuleux gif, suite à des incidents chronophages qui n'auraient pas existés, ou bien auraient étés résolus bien plus rapidement, si nous avions utilisé ZFS:

On a pas utilisé ZFS

En effet, lorsque les bras vous en tombent, d'avoir à résoudre manuellement des problèmes basiques, parce que nous n'avons pas pus étudier la mise en place d'autres solutions, il ne vous reste que la création de gifs.

Histoire

ZFS est un système de fichiers initialement développé par Sun Microsystems en 2005.

Il se distingue à l'époque sur plusieurs aspects clairement novateurs:

  1. Résilient aux pannes, nous avons à l'époque des conférences des ingénieurs Sun qui nous montrent qu'ils peuvent percer les disques d'un raid ZFS actuellement en cours d'utilisation, sans impact sur la disponibilité du raid.
  2. Prévu pour le futur avec des limites sur le nombre de fichiers, leur taille maximale, la taille maximale du zpool...
  3. La possibilité de créér des datasets (re)configurables contrairement aux classiques partitions.
  4. La possibilité de créér des snapshots sans coût, instantannés, et une gestion très fine des données entre les snapshots.

Mon expérience

J'ai utilisé ZFS sur du perso dès 2009.
Je l'ai utilisé sur de la prod dès 2012.

J'ai géré jusqu'à ~400 serveurs de prod avec du ZFS on root, ce qui me permet d'être solide sur mon expérience avec ce système de fichier, et donc, de savoir les gains qu'il apporte, les problèmes qu'il permet d'éviter.

À ce jour (2025), mon PC perso est toujours sur ZFSEat your own dog food.

Sources

  1. ZFS - Wikipédia.
  2. GNU/Linux Magazine - article de 2009, qui m'a lancé dans l'aventure ZFS.
  3. ZFS for Dummies

Les cas pratiques

Datasets

Les datasets sur ZFS sont des volumes qui sont créés sur un zpool existant, et qui vont porter un ensemble de propriétées qui leur seront propres ou héritées.

Chaque dataset est le fils d'un dataset ou directement du zpool.

Ce dataset sera mount comme un volume classique (par ZFS).

Les datasets peuvent être créés et détruits à tous moments. Il est donc possible, en cas de nouveau besoin, d'adapter le système de fichiers à celui-ci (par exemple un dataset par stack applicative ou par utilisateur).

Pourquoi c'est pratique

Réservation disque

En configurant une réservation disque à l'avance, vous pourrez vous assurer que cet espace lui soit dès le début attribué, même s'il n'en fait pas l'usage immédiat.

C'est pour simplifier de la planification.

Exemple:

# zfs set reservation=5G zroot/root/home/web-user
# zfs list
NAME                        USED  AVAIL  REFER  MOUNTPOINT
zroot/root/home             5.00G  33.5G  8.50K  /home
zroot/root/home/web-user    15.0K  33.5G  8.50K  /home/web-user

L'espace est donc directement consommé sur zroot/root/home (qui est lui aussi un dataset), même si zroot/root/home/web-user ne contient encore aucunes données.

Sources:

Configurer un quota

Il est possible de définir un usage disque max sur un dataset.
Sela permet d'empêcher une application, un utilisateur, ou un élément système de consommer l'intégralité de l'espace du zpool en cas de défaut.

Le cas le plus classique étant la création de logs qui viennent saturer le système.

Même si journalctl est configurable pour disposer d'une taille max des logs, les applications n'utilisent pas toutes journalctl.

Exemple:

# zfs set quota=10G zroot/root/var/log
# zfs get quota zroot/root/var/log
NAME                PROPERTY  VALUE  SOURCE
zroot/root/var/log  quota     10G    local

Sources:

Compresser les données

Si vous crééz un dataset dont vous savez à l'avance que les données se compressent bien, alors vous pouvez activer.

Il est possible de choisir l'algorithme de compression, ainsi qu'obtenir des stats sur son efficacité.

Il est évident que cela va surtout très bien s'appliquer pour un dataset qui va contenir des logs.

Exemple:

# zfs set compression=on zroot/root/var/log
# zfs get compression zroot/root/var/log
NAME               PROPERTY     VALUE      SOURCE
zroot/root/var/log compression  on         local

Snapshots

Supposons un site web PHP classique avec une db MariaDB sous forme de stack docker compose.
Cette stack serait déclarée dans un dossier /srv/docker/victim.org.
Le nom du dataset sera zroot/srv/docker/victim.org.

Création d'un snapshot

zfs snap zroot/srv/docker/victim.org@$(date +%Y-%m-%d-%H-%M-%S)

Liste des derniers snapshots

$  /s/d/victim.org  zfs list -H -rt snapshot -o name zroot/srv/docker/victim.org | tail -n5                                                                                                                                                                                                                                    4359ms  mar. 08 août 2023 16:14:41
zroot/srv/docker/victim.org@2023-08-04-00-00-08
zroot/srv/docker/victim.org@2023-08-05-00-00-13
zroot/srv/docker/victim.org@2023-08-06-00-00-04
zroot/srv/docker/victim.org@2023-08-07-00-00-04
zroot/srv/docker/victim.org@2023-08-08-00-00-06

Fichiers modifiés depuis le dernier snapshot

$  /s/d/victim.org  just diff                                                                                                                                                                                                                                                         mar. 08 août 2023 16:13:49
zfs diff $(zfs list -H -rt snapshot -o name zroot/srv/docker/victim.org | tail -n1)
M   /srv/docker/victim.org/db/ibdata1
M   /srv/docker/victim.org/db/ib_logfile0
M   /srv/docker/victim.org/db/ib_logfile1
M   /srv/docker/victim.org/db/victim/wp_options.ibd
M   /srv/docker/victim.org/code/wp-content
M   /srv/docker/victim.org/db/ibtmp1
+   /srv/docker/victim.org/backup/1691460000_2023-08-08_victim.sql
M   /srv/docker/victim.org/backup

Pour voir le contenu du snapshot 2023-08-08-00-00-06 de notre stack, nous pouvons aller dedans (read-only):

cd /srv/docker/victim.org/.zfs/snapshots/2023-08-08-00-00-06

Rollback la stack à un snapshot

zfs rollback -r zroot/srv/docker/victim.org@2023-08-08-00-00-06

Exporter la stack

Grâce à zfs send, il est possible d'exporter un snapshot comme bon nous semble.

Si notre stack docker compose ne déclare que des volumes de type bind mount, situés dans le même dossier, alors déplacer toute la stack devient trivial!

zfs send pourra être invoqué ainsi:

zfs send zroot/srv/docker/victim.org@2023-08-08-00-00-06

Exporter en tant que fichier:

zfs send zroot/srv/docker/victim.org@2023-08-08-00-00-06 >/root/backup.victim.org.raw

Exporter via SSH:

zfs send zroot/srv/docker/victim.org@2023-08-08-00-00-06 | ssh $host "zfs recv zroot/srv/docker/victim.org"

Outils

zfs-prune-snapshots

bahamas10/zfs-prune-snapshots permet de gérer le nombre de snapshots à conserver.

zrepl

zrepl permet de répliquer des datasets entre plusieurs serveurs, que ce soit en mode push ou pull.

Même s'il peut être difficile de démarrer avec zrepl (j'ai trouvé la documentation peu claire), le résultat est vraiment convaincant.

Nix

Nix

Nix c'est:

  1. Un langage de programmation.
  2. Un gestionnaire de packages.
  3. Un système de build.

Pour cela, il mobilise plusieurs concepts:

  1. C'est un langage de programmation purement fonctionnel.
  2. Il est déclaratif.
  3. Il est paresseux
  4. Le résultat de son travail est reproductible
  5. Le résultat de son travail est portable

NixOS

NixOS c'est:

  1. Une distribution GNU/Linux initiée en 2006.
  2. Une première version stable en 2013.
  3. Une OS entièrement créé de manière déclarative, et reproductible

NixOS est clairement un OVNI dans le monde GNU/Linux tant il se distingue.

Son seul concurrent dans son domaine est GNU/Guix.

Sources

Histoire

Nix est un projet démarré en 2003 par Eelco Dolstra, qui prendra du temps à se mettre en place, car il bouscule tout l'existant.

Mon expérience

Bien que j'ai pris connaissance de NixOS en 2017 via une brève sur LinuxFR.org, mon intérêt était focalisé sur d'autres projets, et j'étais encore bien trop lié à Archlinux (depuis 2008).

J'ai commencé Nix en 2023 via Devbox, qui a été convaincant, m'a poussé a essayer home-manager.

1 an plus tard, je passai mon PC perso sous NixOS et commençait à écrire des flakes.

Il me semble, à ce jour, que c'est un excellent moyen de s'embarquer dans l'aventure Nix, par étapes.

Sources

Devbox

Devbox permet de créér des environnements reproductibles entre différentes machines.

Ce projet se distingue des autres par son extrême simplicité:
vous n'avez pas besoin de savoir utiliser nix pour utiliser devbox.

Il s'agit d'une surcouche à nix et aux flakes, afin de rendre le tout immédiatement utilisable pour créér des environnements de travail sur des projets!

Exemple Ansible

En local sous archlinux

Depuis un PC sous Archlinux avec nix + Devbox, j'ai ansible qui a été installé depuis les packages archlinux:

 kuri@Nomad  ansible  16:33  which ansible
/usr/sbin/ansible
 kuri@Nomad  ansible  16:33  ansible --version
ansible [core 2.20.0]
  config file = None
  configured module search path = ['/home/kuri/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.13/site-packages/ansible
  ansible collection location = /home/kuri/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/sbin/ansible
  python version = 3.13.11 (main, Dec  7 2025, 13:01:45) [GCC 15.2.1 20251112] (/usr/bin/python)
  jinja version = 3.1.6
  pyyaml version = 6.0.3 (with libyaml v0.2.5)

Nous avons ansible + jinja + python ainsi que diverses librairies python afin que notre installation d'ansible soit fonctionnelle.

Pour cela, sous archlinux, j'ai fait pacman -S ansible.

Le problème c'est les autres

Si j'ai 3 collègues, sous les OS suivants:

  1. Windows (WSL)
  2. macOS
  3. Ubuntu

Je vais devoir leur dire de se débrouiller, pour voir comment installer ansible sur leurs machines.

La solution c'est devbox

Ou alors, je passe à la méthode Devbox:

 kuri@Nomad  ansible  16:35  devbox init
 kuri@Nomad  ansible  16:39  devbox add ansible
Info: Adding package "ansible@latest" to devbox.json
 kuri@Nomad  ansible  16:39  devbox shell
Info: Ensuring packages are installed.
✓ Computed the Devbox environment.
Starting a devbox shell...
Linux Nomad 6.17.9-arch1-1 x86_64
 16:40:06  up   8:34,  1 user,  load average: 0,38, 0,24, 0,28
(devbox)  kuri@Nomad  ansible  16:40  ansible --version
ansible [core 2.20.0]
  config file = None
  configured module search path = ['/home/kuri/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /nix/store/06p0i8w8zqrinjwldnypkva8s6ivz0r0-python3.13-ansible-core-2.20.0/lib/python3.13/site-packages/ansible
  ansible collection location = /home/kuri/.ansible/collections:/usr/share/ansible/collections
  executable location = /nix/store/06p0i8w8zqrinjwldnypkva8s6ivz0r0-python3.13-ansible-core-2.20.0/bin/ansible
  python version = 3.13.9 (main, Oct 14 2025, 13:52:31) [GCC 14.3.0] (/nix/store/3lll9y925zz9393sa59h653xik66srjb-python3-3.13.9/bin/python3.13)
  jinja version = 3.1.6
  pyyaml version = 6.0.3 (with libyaml v0.2.5)

Si ce dossier se trouve être un dépôt git, dans lequel je commit les fichiers devbox.{json,lock}, tout personne qui le clone va travailler avec les mêmes versions de packages que ceux définis dans devbox.lock.
Et donc, à moins d'un bug spécifique à l'OS, tout le reste fonctionnera à l'identique (y compris sous ARM).

Installer ansible-core 2.16

Que ce soit via devbox search ansible ou Nixhub, je peux lister d'autres versions d'ansible disponibles.

Dans le cas de gestion de serveurs d'une autre époque (article écrit en décembre 2025), par exemple:

  1. CentOS 7
  2. Amazon Linux 2
  3. Debian 10

La version 2.17 casse le support de ces versions, et nous devons donc utiliser la version 2.16, qui n'est globalement plus packagée.

Dans un monde ancien, nous aurions sous le coude une VM sous une version périmée de Debian (genre la 10), qui pointe sur le dépôt des archives, et qui aurait ansible 2.16 + toutes les deps à la bonne version, et on bichonnerait cette VM comme le saint graal.

Ou, encore pire, on considère que des outils de gestion de config/conformité, c'est mal, car les dernières versions ne supportent plus les dinos (le vrai problème étant qu'on ne sait pas MAJ les serveurs).

Maintenant, réglons ce problème à la manière de Devbox:

 kuri@Nomad  ansible  17:22  devbox rm ansible
 kuri@Nomad  ansible  17:22  devbox add ansible@2.16.5
Info: Adding package "ansible@2.16.5" to devbox.json
Info: Installing the following packages to the nix store: ansible@2.16.5
 kuri@Nomad  ansible  17:23  devbox shell
Info: Ensuring packages are installed.
✓ Computed the Devbox environment.
Starting a devbox shell...
Linux Nomad 6.17.9-arch1-1 x86_64
 17:23:16  up   9:18,  1 user,  load average: 0,95, 0,50, 0,65
(devbox)  kuri@Nomad  ansible  17:23  ansible --version
ansible [core 2.16.5]
  config file = None
  configured module search path = ['/home/kuri/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /nix/store/a5k2lpbxj419kzn2pyz55gql35pbg8xx-python3.12-ansible-core-2.16.5/lib/python3.12/site-packages/ansible
  ansible collection location = /home/kuri/.ansible/collections:/usr/share/ansible/collections
  executable location = /nix/store/a5k2lpbxj419kzn2pyz55gql35pbg8xx-python3.12-ansible-core-2.16.5/bin/ansible
  python version = 3.12.4 (main, Jun  6 2024, 18:26:44) [GCC 13.3.0] (/nix/store/04gg5w1s662l329a8kh9xcwyp0k64v5a-python3-3.12.4/bin/python3.12)
  jinja version = 3.1.4
  libyaml = True

Que je sois sous Archlinux, NixOS, Ubuntu, macOS, Windows, et peu importe les versions, tant que j'ai devbox (et donc nix), j'ai cette reproductibilité sur des milliers de packages, ainsi que les anciennes versions de ces packages, dans des envs isolé et reproductibles!

Sources

flakes

les nix flakes sont un moyen d'écrire des expressions nix dans le but de:

  • Packager un outil.
  • Créér une VM.
  • Installer/Configurer son système.
  • Installer/Configurer un système distant.
  • Créér un environnement de développement.

Bien qu'extrêmement puissant, il s'agit d'un outil fort compliqué à utiliser, car il requiert de savoir écrire dans le langage nix.

C'est pourquoi je ne recommande pas de se lancer dans l'aventure nix en partant directement sur nixos + des flakes pour décrire intégralement son OS et ses environnements de travail.

Il faut savoir s'approprier les outils par étapes, pour ne pas s'en dégouter ou se dévaloriser suite à un effort trop complexe pour être fait en une seule fois.

Devbox est un moyen beaucoup plus rapide pour commencer à créér des environnements de travail, tout en effectuant un premier pas vers nix!

Modules

Il est possible d'écrire des flakes sous forme de modules, qui pourront être utilisés par d'autres flakes, afin de ne pas toujours ré-inventer la roue.

Sources

direnv

direnv est un outil qui se greffe sur votre shell afin de pouvoir automatiquement installer/charger des outils, et executer des commandes, lorsque vous entrez dans un répertoire (cd).

Se reposant sur les gains que permet nix (et surtout les flakes), il permettra de configurer automatiquement des envs de travail, en faisant au maximum abstraction de l'OS que l'on utilise.

Sans avoir à connaitre par avance les spécificitées d'un projet (ses dépendances), il sera possible de commencer à travailler dessus.

Exemples d'usages:

  • Installer les outils rust+cargo+cc pour compiler un projet rust.
  • Installer mdBooks ou mkdocs pour build/visualiser de la documentation.
  • Installer les bonnes versions d'ansible ou terraform pour être compatible avec les contraintes d'une infra.

Sources

home-manager

home-manager est du code nix sous forme de flakes qui vont vous permettre de gérer des environnements utilisateurs.

Classiquement, sous GNU/Linux, vous installez des outils au niveau système, et tous ces outils sont disponibles à tous les utilisateurs.

Avec home-manager, vous allez pouvoir séparer les outils, c'est à dire que vous continuerez d'avoir des outils disponibles au niveau système, mais vous pourrez enrichir les environnements de certains utilisateurs.

l'idée est donc de garder la partie système la plus light possible, et de seulement charger les utilisateurs qui ont besoins d'outils.

Il va aussi permettre de gérer les dotfiles, mais à un niveau inégalé par les différents outils de gestion de dotfiles existants.

Utilisateur GNU/Linux depuis 1997, le sujet des dotfiles d'une machine à l'autre, ou à force de réinstalls, je l'ai clairement poncé.

Absolument rien n'a été plus pratique que home-manager qui hérite des gains de nix, des flakes, et donc va non seulement permettre d'installer des packages en espace utilisateur, mais va créér des services systemd en espace utilisateur, et permettre de générer les dotfiles de façon reproductible grâce à nix!

home-manager est Multi-OS, je m'en suis d'abord servit sous Archlinux, vous pouvez vous en servir sous macOS... Il n'est pas necessaire d'être sous NixOS.

Sources

Systemd

systemctl

portable services

Depuis la v239 (2018) de Systemd, est introduit la notion de Portable Services.

En quoi cela va nous interesser?

Isolation

  • Il est possible de donner accès à une partie du système de fichiers du host via BindPaths= et BindReadOnlyPaths=, pour y stocker des datas dites "dynamiques", ressemblant aux volumes sur Docker.
    Pour le reste, le service est chroot.
  • Si le service est compromis, les accès au système sont restreints.
  • Pour les mises à jour, on detach l'image .raw de la version précédente du service, et on attach la nouvelle version!
    C'est tout!
    Pas besoin de MAJ le système, votre démon est indépendant du système sur lequel il s'execute!. Vous pouvez MAJ le système sans impact sur le service, et inversement!

Il va donc être possible d'avoir par exemple un dossier /srv/startpage/ contenant:

.r--r--r-- root root 5.7 MB Thu Jan  1 01:00:01 1970  startpage_1.1.0.raw
.r--r--r-- root root 5.7 MB Thu Jan  1 01:00:01 1970  startpage_1.2.0.raw
.r--r--r-- root root 5.7 MB Thu Jan  1 01:00:01 1970  startpage_1.3.0.raw

et pouvoir upgrade le service dans le temps, et rollback sur l'image d'avant en cas de problème.

Reproductibilité

  • On package notre démon dans une image .raw. Cette image embarque le service et toutes ses dépendances. Peu importe la distribution, il se comportera de la même manière.
  • Nix sait construire des images Portable Services via pkgs.portableService.

Léger

  • C'est plus léger que docker (pas de surcouche / isolation réseau).

Pour quelles limites?

Lorsque l'on commence à vouloir faire discuter plusieurs services, docker compose (ou similaire) va s'imposer naturellement pour continuer de bosser en isolation, avec reproductibilité.

Sources

Docker

Histoire

traefik

watchtower