ITSkillsCenter
Business Digital

CI Nix avec flakes et GitHub Actions : pipeline reproductible

9 دقائق للقراءة

📍 Guide principal : NixOS pour développeurs et serveurs : reproductibilité totale en 2026
Ce tutoriel suppose un flake fonctionnel (cf. Flakes : essentiels) et un dépôt sur GitHub.

L’enjeu d’une CI qui parle Nix

Une chaîne d’intégration continue classique passe son temps à reconstruire un environnement de build. npm install, pip install, apt-get dans un Dockerfile, lecture du Gemfile, du go.sum. Chaque étape consomme du temps et de la bande passante, et chacune peut échouer si une dépendance change subtilement entre votre poste et le runner. Avec un flake Nix, l’environnement de build est défini une fois, lockée dans flake.lock, et la CI charge exactement le même que vos développeurs en local. Les builds deviennent reproductibles à la décimale près, et le cache binaire fait que les paquets ne sont téléchargés qu’une fois pour de bon.

Ce tutoriel monte une CI GitHub Actions complète qui lance nix flake check, build vos packages, pousse les artefacts vers un cache binaire cachix, et déploie sur un serveur si la branche est main. Les patterns valent aussi pour GitLab CI ou Sourcehut.

Prérequis

  • Un flake fonctionnel avec au moins devShells.default et idéalement checks et packages.
  • Un dépôt sur GitHub.
  • Un compte sur cachix.org (gratuit jusqu’à 1 Go) ou un cache binaire à vous.

Étape 1 — Le workflow GitHub Actions minimal

Créez .github/workflows/ci.yml avec le contenu suivant :

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
        with:
          extra_nix_config: |
            experimental-features = nix-command flakes
      - run: nix flake check
      - run: nix build .#default

cachix/install-nix-action installe Nix sur le runner Ubuntu en quelques secondes, configure les flakes, et active le cache cache.nixos.org par défaut. Les deux dernières lignes lancent les vérifications puis le build du package par défaut.

Commit, pousser, ouvrir l’onglet « Actions » sur GitHub. Le job tourne ; à la fin, le statut est vert si tout passe, rouge sinon.

Étape 2 — Comprendre ce que nix flake check vérifie

Cette commande évalue toutes les sorties du flake et signale les erreurs. Si vous avez déclaré des checks.<system>.<nom>, ils sont exécutés. Si vous avez des nixosConfigurations, leur évaluation est testée (mais pas leur build complet). C’est l’équivalent d’un linter pour votre flake.

Pour ajouter des tests utiles, déclarez des checks dans le flake :

checks.${system} = {
  format = pkgs.runCommand "check-format" {} ''
    ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt --check ${./.}
    touch $out
  '';

  unit-tests = pkgs.runCommand "unit-tests" {
    buildInputs = [ pkgs.nodejs_22 pkgs.pnpm ];
  } ''
    cp -r ${./.} ./src
    cd src
    pnpm install
    pnpm test
    touch $out
  '';
};

Désormais, nix flake check en local et en CI lancent les deux : le formatage Nix et les tests unitaires. Si l’un échoue, la CI passe au rouge. Pour ne lancer qu’un seul check : nix build .#checks.x86_64-linux.unit-tests.

Étape 3 — Ajouter cachix pour partager le store entre runs

Sans cache, chaque run de CI repart de zéro : télécharger nixpkgs, recompiler les éventuels paquets custom. Avec cachix, vous mettez en cache vos artefacts entre runs, et les coéquipiers en local profitent du même cache.

Créez un cache sur cachix.org (par exemple monorg-ci), récupérez le token d’auth dans le panneau « Auth Tokens », ajoutez-le comme secret GitHub CACHIX_AUTH_TOKEN. Modifiez le workflow :

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
        with:
          extra_nix_config: |
            experimental-features = nix-command flakes
      - uses: cachix/cachix-action@v17
        with:
          name: monorg-ci
          authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
      - run: nix flake check
      - run: nix build .#default

L’action cachix/cachix-action ajoute le cache monorg-ci.cachix.org aux substituters et configure le pousseur. Tout ce qui est compilé pendant le run est automatiquement poussé vers cachix. Le run suivant qui touche aux mêmes hashes télécharge depuis cachix au lieu de recompiler.

Étape 4 — Profiter du cache cachix en local

Sur votre poste de travail, ajoutez le cache à votre config Nix :

nix.settings = {
  substituters = [
    "https://cache.nixos.org"
    "https://monorg-ci.cachix.org"
  ];
  trusted-public-keys = [
    "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
    "monorg-ci.cachix.org-1:<votre-clé-publique>"
  ];
};

Désormais, vos rebuilds locaux téléchargent depuis cachix les paquets que la CI a déjà compilés — utile pour les paquets custom de votre équipe qui ne sont pas dans cache.nixos.org. Vous gagnez plusieurs minutes par rebuild après un changement collègue.

Étape 5 — Workflow par matrice : tester sur plusieurs nixpkgs

Pour valider que votre projet marche sur la version stable et la version unstable de nixpkgs, utilisez une matrice :

jobs:
  build:
    strategy:
      matrix:
        nixpkgs: [nixos-25.11, nixos-unstable]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
      - run: nix flake update --override-input nixpkgs github:NixOS/nixpkgs/${{ matrix.nixpkgs }}
      - run: nix flake check

Cette matrice lance deux jobs en parallèle, l’un sur la stable, l’autre sur unstable. Si un changement à venir dans nixpkgs casse votre projet, vous le voyez avant qu’il atterrisse en stable. Pratique pour les bibliothèques destinées à plusieurs versions de NixOS.

Étape 6 — Déployer après merge sur main

Pour chaîner la CI vers un déploiement, ajoutez un job conditionnel qui se lance après le build :

  deploy:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: cachix/install-nix-action@v31
      - uses: webfactory/ssh-agent@v0.10.0
        with:
          ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }}
      - run: |
          mkdir -p ~/.ssh
          ssh-keyscan vps01.exemple.fr >> ~/.ssh/known_hosts
          nix run nixpkgs#nixos-rebuild -- switch \
            --flake .#vps01 \
            --target-host deploy@vps01.exemple.fr \
            --use-remote-sudo

Le job deploy ne se lance que sur la branche main et seulement si build a réussi. Il configure une clé SSH stockée comme secret GitHub, ajoute l’empreinte du serveur aux known_hosts, et lance nixos-rebuild --target-host. Le résultat : un git push sur main déploie automatiquement.

Étape 7 — Cas spécial : runner self-hosted NixOS

Pour des projets gros qui dépassent les limites des runners GitHub gratuits (4 vCPU, 16 Go RAM, 7 Go de disque), un runner self-hosted sur un serveur NixOS est rentable. Le runner peut tourner Nix nativement, sans la couche d’installation, et avoir accès à un cache local rapide.

# Sur le serveur runner
services.github-runners.monorunner = {
  enable = true;
  url = "https://github.com/monorg/monorepo";
  tokenFile = "/run/agenix/github-runner-token";
  extraPackages = with pkgs; [ git nix ];
};

Le token vient d’agenix (cf. tutoriel précédent). Le runner s’enregistre auprès de GitHub au démarrage, traite les jobs marqués runs-on: self-hosted. Au prochain rebuild, le service redémarre automatiquement avec la nouvelle version.

Étape 8 — Builds reproductibles en CI : le test ultime

Une CI Nix bien configurée doit produire des artefacts au hash identique à ceux de votre poste. Pour le vérifier :

# Sur votre poste
nix build .#default
nix path-info -r ./result | sort > local-paths.txt

# Comparer avec ce que la CI a produit (téléchargé depuis cachix)
nix store info --json < le-store-cachix > ci-paths.txt
diff local-paths.txt ci-paths.txt

Si le diff est vide, vos builds sont strictement reproductibles. Si non, l’une des deux machines a un input non-figé (un timestamp, une variable d’environnement leakée). C’est la garantie ultime que la CI ne triche pas — l’artefact qu’elle pousse est identique à celui de tout dev qui clone et build.

Erreurs fréquentes

Symptôme Cause Solution
error: experimental Nix feature 'flakes' is disabled en CI extra_nix_config oublié. Ajouter experimental-features = nix-command flakes dans install-nix-action.
cachix push: forbidden Token cachix invalide ou expiré. Régénérer le token sur cachix.org, mettre à jour le secret GitHub.
Build CI tourne 30+ minutes Pas de cache, recompilation de nixpkgs custom. Vérifier que cachix-action est bien avant les commandes nix build.
error: build of '/nix/store/...' failed: out of memory Runner GitHub manque de RAM pour compiler. Profiter du cache (cachix), ou passer à un runner self-hosted plus puissant.
Déploiement échoue avec Host key verification failed known_hosts du runner pas peuplé. Ajouter ssh-keyscan avant la commande.

Pourquoi cette pipeline bat docker build

Beaucoup de teams font tourner leur CI avec des Dockerfiles. Trois raisons de préférer Nix. Reproductibilité : un FROM node:22 peut donner deux images différentes à un mois d’écart à cause des patches de sécurité Debian sous-jacents ; un nix build avec le même flake.lock produit le même hash. Cache granulaire : Docker met en cache des couches entières ; Nix met en cache des dérivations individuelles, beaucoup plus fines. Aucune duplication : votre flake.nix de dev sert aussi pour la CI ; pas de Dockerfile à maintenir en parallèle.

Docker reste pertinent pour produire l’image finale qui sera déployée sur Kubernetes. Mais entre votre code source et cette image finale, Nix est un environnement de build supérieur en CI.

Patterns plus avancés à connaître

Magic Nix Cache de Determinate Systems remplace cachix avec un cache GitHub Actions natif (gratuit, sans compte tiers). nix-fast-build parallélise les checks plus efficacement que nix flake check. FlakeHub propose un registry hébergé pour vos flakes privés. Hercules CI est une CI dédiée Nix, plus optimisée pour le build distribué que GitHub Actions.

Pour démarrer, restez sur GitHub Actions + cachix : le combo couvre 90 % des besoins, et migrer vers une solution plus spécialisée se fait sans douleur quand le besoin se présente.

Suite logique

La série se termine avec Build d’un ISO NixOS et d’une AMI custom qui montre comment générer des images de serveur reproductibles à partir du même flake. Le guide principal NixOS est l’index général qui rassemble toute la matière.

Références officielles

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité