Le Blog Utux

HTTP 200 GET /

De Kubernetes à NixOS

Rédigé par uTux Aucun commentaire

Il y a un an et demi, j'annonçais avoir migré mon blog sur Kubernetes (K3s). Bien que je sois globalement satisfait du résultat et que cela m'a permis de beaucoup apprendre, je rencontre tout de même des désagréments :

  • Kubernetes, c'est lourd. Comptez 1 GB de RAM à vide. Pour être à l'aise, j'ai du prendre un VPS avec 4GB de RAM, là où 2 suffiraient largement sans Kubernetes.
  • Absence de support d'IPv6. En 2022 c'est franchement difficile à justifier.
  • La gestion des Ingress est complexe. J'utilise Traefik mais c'est compliqué, il m'a fallu quasiment 2 jours pour faire fonctionner les certificats ACME, et les montées de version ne se passent pas toujours très bien.
  • Comme prévu, les mises jour à demandent un peu plus d'efforts car les composants ne sont pas gérés par la distribution. Il faut donc:
    • Mettre K3s à jour régulièrement.
    • Reconstruire et livrer les images même si l'application n'a pas changé, juste pour être sûr de ne pas trimbaler de failles de sécurité dans les librairies.
    • Mettre à jour Traefik régulièrement.

Bref, même si je trouve que Kubernetes est une super solution qui a mis en valeur les containers et l'écosystème Linux, c'est clairement overkill pour moi et je souhaite me simplifier la vie. Et si au passage je peux me former à de nouvelles technos, c'est un plus.

La solution de facilité aurait été d'installer Debian et de coder quelques roles Ansible mais l'inconvénient est que je n'apprendrais rien de nouveau. Je suis donc parti sur NixOS. C'est une distribution où la configuration s'effectue de manière déclarative via le langage Nix, avec gestion des états et possibilité de rollback.

En effet lorsque vous gérez votre distribution Linux avec Ansible, Puppet ou Salt, vous pouvez déployer une configuration et des applications, en revanche le retour en arrière n'est pas géré. Par exemple si vous avez déployé Apache et que vous voulez changer pour Nginx, c'est à vous de coder la manière dont Ansible va désinstaller Apache, sinon il sera toujours présent. Avec NixOS, si vous retirez toute référence à httpd dans votre configuration, il ne sera plus du tout présent à la prochaine génération du système. C'est un fonctionnement atomic et stateful.

Pour l'installation, j'ai utilisé nixos-infect, un script à lancer sur la plupart des distributions Linux afin de les remplacer par NixOS. Associé à un cloud-init, il permet de faire le déploiement via Terraform de manière complètement automatique, ce qui est vraiment cool il faut le dire. Et pour les gens qui préfèrent une installation à la main, sachez que Hetzner proposer une ISO NixOS et un accès console distante même pour les VPS, c'est donc totalement possible :)

Pour la partie hébergement web, voici mon fichier de configuration /etc/nixos/web.nix :

{ config, lib, pkgs,  ...}:

let
  defaultVirtualHost = {
    documentRoot = "/var/www/html/blank";
    addSSL = true;
    forceSSL = false;
    sslServerKey = "/var/www/ssl/snakeoil.key";
    sslServerCert = "/var/www/ssl/snakeoil.pem";
    locations."/" = {
      index = "index.html";
    };
  };
  makeVirtualHost = webroot:
    { documentRoot = "${webroot}";
      forceSSL = true;
      enableACME = true;
      locations."/" = {
        index = "index.php";
      };
      extraConfig = ''
        <Directory "${webroot}">
          AllowOverride All
        </Directory>
      '';
    };
in {
  security = {
    acme = {
      email = "hostmaster@example.org";
      acceptTerms = true;
    };
  };
  services = {
    httpd = {
      enable = true;
      mpm = "prefork";
      adminAddr = "hostmaster@example.org";
      enablePHP = true;
      phpPackage = pkgs.php80;
      phpOptions = "display_errors = off";
      extraConfig = ''
        SetOutputFilter DEFLATE
        ServerSignature Off
        ServerTokens prod
        <FilesMatch ".(ico|pdf|jpg|jpeg|JPEG|png|gif|js|css)$">
          Header set Cache-Control "max-age=3600, public"
        </FilesMatch>
      '';
      extraModules = [
        "deflate"
      ];
      virtualHosts =
        {"_default_" = defaultVirtualHost;
         "utux.fr"   = (makeVirtualHost "/var/www/html/utux.fr");
        };
    };
  };
}

Explications : j'ai d'autres vhosts non mentionnés ici, et à chaque fois leur configuration est identique. Pour éviter d'avoir à répéter du code, j'utilise let (permet de définir des variables et des fonctions) ainsi que in (pour les appliquer). Je ne connais pas de moyen plus propre de faire des loop pour le moment, car c'est le but. Étant donné que j'utilise PluXml, il ne faut pas oublier le AllowOverride All qui permet aux .htaccess de fonctionner, sinon les fichiers XML qui contiennent les data deviennent accessible, ce qui fait fuiter pas mal d'infos sensibles.

Pour le moment, ça marche plutôt bien. Le serveur consomme 119 Mo de RAM, soit quasiment 10x moins que Kubernetes :) Et en prime le support de l'IPv6 est revenu.

En conclusion, je suis content de pouvoir enfin tester NixOS en production. Bien que je ne sois pas encore familier avec le langage Nix, et que je le trouve bien trop compliqué par rapport à un bon vieux Ansible, j'estime que c'est l'avenir de Linux sur serveur. Les distributions devront être atomiques, et leur configuration centralisée, versionnée et reproductible. J'espère que ceci est le début d'une aventure positive.

Aperçu de NixOS en desktop

Rédigé par uTux 4 commentaires

Il y a un peu plus de 2 ans j'ai parlé de NixOS, distribution Linux atypique dans le sens où sa configuration se fait de manière déclarative à un unique emplacement.

NixOS logo

Mon ordinateur pro et ma machine gaming sont sous Windows, j'utilise donc très souvent des machines virtuelles Linux pour pouvoir travailler. Habituellement j'utilise Virtualbox + Debian + Mate, mais j'ai décidé d'expérimenter NixOS. Alors oui je sais qu'une machine virtuelle n'est pas représentative d'un cas d'usage réel, mais ça permet de se faire une première idée.

Installation

J'ai installé NixOS avec la configuration suivante:

# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  # Define on which hard drive you want to install Grub.
  boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only

  # Networking
  networking.hostName = "nixos"; # Define your hostname.
  networking.networkmanager.enable = true;

  # Select internationalisation properties.
  i18n = {
    consoleFont = "Lat2-Terminus16";
    consoleKeyMap = "fr";
    defaultLocale = "fr_FR.UTF-8";
  };

  # Set your time zone.
  time.timeZone = "Europe/Paris";

  # Repositories
  nixpkgs.config.allowUnfree = true;

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    ansible
    dnsutils
    firefox-bin
    gimp
    git
    htop
    keepassxc
    libreoffice
    networkmanagerapplet
    parcellite
    p7zip
    sudo
    syncthing
    syncthing-gtk
    thunderbird-bin
    tree
    unzip
    vim
    vscode
    xarchiver
  ];

  # Enable CUPS to print documents.
  services.printing.enable = true;

  # Enable sound.
  sound.enable = true;
  hardware.pulseaudio.enable = true;

  # Mate
  services.xserver = {
    enable = true;
    layout = "fr";
    xkbOptions = "eurosign:e";
    desktopManager = {
      default = "mate";
      xterm.enable = false;
      mate.enable = true;
    };
  };

  # Docker
  virtualisation.docker.enable = true;
  
  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.utux = {
    isNormalUser = true;
    extraGroups = [ "wheel" "networkmanager" "docker" ];
  };

  # Nix Garbage Collector
  nix.gc = {
    automatic = true;
    dates = "weekly";
    options = "--delete-older-than 30d";
  };

  # This value determines the NixOS release with which your system is to be
  # compatible, in order to avoid breaking some software such as database
  # servers. You should change this only after NixOS release notes say you
  # should.
  system.stateVersion = "19.09"; # Did you read the comment?
  system.autoUpgrade.enable = true;

}

Environnement desktop

NixOS Mate

La gestion centralisée de la configuration s'applique au système, mais pas au $HOME de l'utilisateur. Les raccourcis, les thèmes de bureau, les profils se gèrent "à la main", ce qui m'amène à penser que NixOS perd un peu d'intérêt en usage desktop. Cependant, ce point pourrait bientôt changer avec Home-manager.

Lors de la rédaction de cet article, la version de Mate est la 1.22.1 donc très récente, un bon point. Dans la liste des paquets installés, notez firefox-bin et thunderbird-bin. Couplés à l'activation du repo unfree, cela permet d'installer les versions à jour et upstream. Les paquets firefox et thunderbird sont des versions ESR dépourvues du branding de Mozilla, un peu comme Iceweasel et Icedove pour Debian il y a quelques années.

La version de Keepassx fournie par Nix (0.4.4) est trop vieille pour être utilisable avec le format .kdbx, j'ai donc du installer keepassxc à la place. Vscode est disponible lui aussi grâce au repo unfree.

Python...

Globalement je retrouve donc mon environnement et mes applications favorites, mais je dois quand même parler de Python. Sur Debian, j'utilise généralement pip pour installer une version récente de Ansible et Molecule, mais sur NixOS je n'ai simplement pas compris comment ça marche :/ Il y a pourtant une documentation dédiée à Python mais elle a tendance à ne pas situer correctement les contextes ou ne pas donner assez d'exemples. Donc pas de pip pour le moment, j'ai utilisé le paquet NixOS de Ansible.

Performances

En ce qui me concerne, l'utilisation du bureau Mate dans Virtualbox sur NixOS n'est pas très fluide :/ que ce soit l'ouverture d'un onglet, le déplacement d'un fenêtre, le lancement d'un logiciel, tout accuse de saccades et de lags. Debian s'en sort mieux sur ce point, à configuration presque identique (2 vspus, 2Go de ram, vboxsvga, 32Mo vram), mais cette dernière utilise Mate 1.20.4 et pas 1.22.1.

Lorsque j'ai fait des tests sur une machine peu puissante, j'ai remarqué que nixos-rebuild arrive à mettre à genoux le système et les autres VMs, à cause des écritures sur le disque. Et à propos du disque, il faut parler de l'utilisation du stockage. Par nature, NixOS garde plusieurs versions de la configuration (overlays) et des paquets installés, pensez à des snapshots, donc on se doute que l'espace utilisé est important, très important. On peut facilement consommer 30 Go après quelques semaines, ce qui m'amène au point suivant.

Penser au nettoyage (garbage collector)

Heureusement il existe le Garbage collector qu'il faut régulièrement lancer en root:

[utux@nixos:~]$ sudo nix-collect-garbage -d
[...]
deleting '/nix/store/39s914agmm045fv7l3lz81zcvw86m3vb-xsltml_2.1.2.zip.drv'
deleting '/nix/store/5vy6k04dhrwn0951z7dnpkqyxp3r7ws0-jasper-2.0.16-bin'
deleting '/nix/store/p5c18w2cksfxw748d4f8l31rlfk8z1vg-font-adobe-100dpi-1.0.3'
deleting '/nix/store/mny4fywzpgb2yi54a0vz97f5kxlb8932-unit-systemd-modules-load.service.drv'
deleting '/nix/store/xbl8wj6293nfw3vziwqd5xmhrk5gdq6b-rand_hc-0.1.0.tar.gz.drv'
deleting '/nix/store/trash'
deleting unused links...
note: currently hard linking saves -0.00 MiB
8134 store paths deleted, 11574.19 MiB freed

Dans l'exemple ci-dessus, le système a nettoyé pas loin de 11,6 Go de paquets inutiles ! Il est possible d'automatiser ce nettoyage.

Documentation

NixOS a un manuel très détaillé et très instructif. On trouve aussi beaucoup d'informations sur des fils reddit et github. Il est tout de même fréquent de devoir aller lire le code pour savoir comment se configurer un logiciel pour NixOS, ce qui est intimidant au début mais on s'habitue.

Conclusion

Hé hé, un test ou un aperçu d'une distribution est un exercice que je n'ai pas fait depuis longtemps. Je vous encourage à tester NixOS, sur serveur ou en desktop. Cette distribution n'est pas comme toutes les autres que vous connaissez et elle vous plaira particulièrement si vous faites du devops et que vous cherchez une solution pour versionner les configurations de vos bécanes.

Je dois tout de même avouer que l'utilisation desktop est un peu laborieuse, surtout à cause des mauvaises performances dans Virtualbox (qui font que je reviens souvent à ma Debian) mais aussi à l'absence de gestion centralisée des $HOME (pour cela je testerai Home-manager.).

Utiliser NixOS met un peu de piment dans ma vie de Linuxien trop habitué à la Debian family et à la Red Hat family :)

Notes: NixOS / efi installation

Rédigé par uTux Aucun commentaire

Notes sur l'installation de NixOS / efi:

Après avoir booté l'iso:

passwd
systemctl start sshd
ip addr

Connexion ssh root@ip pour faire l'installation plus aisément:

gdisk /dev/vda
n 1 [entrée] +100M EF00
n 2 [entrée] +2G 8200
n 3 [entrée] [entrée] 8300
w y
mkfs.vfat -F32 /dev/vda1
mkswap /dev/vda2
swapon /dev/vda2
mkfs.xfs /dev/vda3
mount /dev/vda3 /mnt
mkdir /mnt/boot
mount /dev/vda1 /mnt/boot
nixos-generate-config --root /mnt/
[Editer mnt/etc/nixos/configuration.nix]
nixos-install
reboot

Après avoir booté la distribution:

sudo nix-channel --add https://nixos.org/channels/nixos-17.09-small nixos
sudo nixos-rebuild switch --upgrade

Utilisé en machine virtuelle Bhyve. Xfs pour le lolz.

Et bien sûr on oublie pas la documentation :)

NixOS : la distribution déclarative

Rédigé par uTux Aucun commentaire

Si vous êtes familier avec l'écosystème des distributions Linux, vous avez probablement levé un sourcil (comme Teal'c) en lisant ce titre car vous les connaissez toutes, vous avez touché à tous les gestionnaires de paquet, vous avez utilisé debian et gentoo, en bref vous avez fait le tour et plus rien ne nous surprend.

Et pourtant, bien que NixOS soit une distribution assez ancienne (2003) elle dispose de nombreux atouts inédits passés plutôt inaperçus jusqu'à présent.

NixOS logo

La configuration déclarative centralisée

Ce que je trouve le plus intéressant dans NixOS, c'est la configuration centralisée dans un unique fichier. En effet si vous avez déjà travaillé sur des routeurs ou diverses appliances, vous avez remarqué que l'on peut souvent importer et exporter la configuration sous forme de texte assez facilement, cela rend la maintenance très facile. Sous NixOS c'est le même principe, mais en plus puissant puisqu'on peut rollback voire booter sur une ancienne configuration depuis grub. Exemple de configuration d'un serveur MariaDB :

/etc/nixos/configuration.nix

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking = {
    hostName = "mariadb";
    nameservers = [ "192.168.0.31" ];
    defaultGateway = "192.168.0.254";
    interfaces.enp0s3.ip4 = [
      {
        address = "192.168.0.41";
        prefixLength = 24;
      }
    ];
  };

  # Select internationalisation properties.
  i18n = {
    consoleFont = "Lat2-Terminus16";
    consoleKeyMap = "fr";
    defaultLocale = "fr_FR.UTF-8";
  };

  # Set your time zone.
  time.timeZone = "Europe/Paris";

  # List packages installed in system profile. To search by name, run:
  # $ nix-env -qaP | grep wget
  environment.systemPackages = with pkgs; [
    git
    htop
    sudo
    tree
    vim
  ];

  # Services
  services = {
    openssh = {
      enable = true;
      permitRootLogin = "yes";
    };
    mysql = {
      enable = true;
      package = pkgs.mysql;
      extraOptions = ''bind-address=0.0.0.0'';
    };
  };

  # Open ports in the firewall.
  networking.firewall.allowedTCPPorts = [ 22 3306 ];
  # networking.firewall.allowedUDPPorts = [ ... ];

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.extraUsers = {
    utux = {
      isNormalUser = true;
      extraGroups = [ "wheel" ];
    };
  };

  # The NixOS release to be compatible with for stateful data such as databases.
  system.stateVersion = "17.03";

}

/etc/nixos/hardware-configuration.nix

# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:

{
  imports = [ ];

  boot.initrd.availableKernelModules = [ "virtio_pci" "ahci" "xhci_pci" "sr_mod" "virtio_blk" ];
  boot.kernelModules = [ ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/78634ba0-11d1-4f91-85ae-ac2ee247c387";
      fsType = "xfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/019A-1A05";
      fsType = "vfat";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/075a27eb-5656-4b57-b186-73a6d86e5e5c"; }
    ];

  nix.maxJobs = lib.mkDefault 1;
}

Comme vous le voyez, le fichier configuration.nix contient toute la configuration, incluant les services tiers tels que mariadb dans notre cas. Cela va donc encore plus loin que le /etc/rc.conf sur FreeBSD/NetBSD/OpenBSD qui centralise déjà pas mal de choses. Le fichier hardware-configuration.nix lui est généré automatiquement il n'y a pas besoin d'y toucher et il est plus ou moins unique par serveur.

Pour générer et appliquer la configuration :

nixos-rebuild switch

Pour mettre à jour le système :

nixos-rebuild switch --upgrade

Puis un petit mysql_secure_installation la première fois pour préparer notre SGBD.

Ce qu'il reste à faire en dehors du configuration.nix, c'est la définition des mots de passe, avec passwd et bien sûr la gestion des données persistantes (les bases de données pour mariadb par exemple).

Nix, gestionnaire de paquets fonctionnel

Je vais être un peu plus prudent sur ce point, car étant encore en phase de découverte de NixOS, je ne connais pas encore très bien le gestionnaire de paquets Nix. Cependant, à la différence des gestionnaires classiques tels que apt, yum ou pacman, il ne se contente pas d'aller chercher des paquets pour les décompresser. Chaque version de chaque paquet est installé dans une arborescence /nix/store/{identifiant unique}, du coup plusieurs versions peuvent cohabiter ensemble et les mises à jour n'écrasent rien. Il est possible également pour les utilisateurs d'installer des paquets pour leur environnement (non-root) uniquement.

Mon avis

J'ai mis un serveur NixOS en test et il est trop tôt pour en tirer des conclusions. Mais j'aime l'idée de configuration centralisée déclarative, car la configuration classique des systèmes Linux n'est pas toujours simple à maintenir : Docker, Ansible, NixOS : le savoir (re)faire.

Si je dois citer deux inconvénients à NixOS : elle prend de la place (1,6GB à l'installation avec MariaDB) et elle nécessite au moins 1GB de RAM pour s'installer sous peine de voir oomkiller tuer nixos-install... elle peut cependant tourner avec 256MB par la suite.

NixOS nous montre qu'une distribution Linux ce n'est pas seulement un éinième fork de Ubuntu avec un wallpaper personalisé, ou encore une guerre de gestionnaire de paquets (dnf/apt), il existe encore de l'innovation et rien que pour cela elle mérite le coup d’œil.

Docker, Ansible, NixOS : le savoir (re)faire

Rédigé par uTux 4 commentaires

L'informatique, comme tous les métiers, demande un savoir-faire, celui-ci vient avec l'expérience et la pratique. Mais s'il y a un autre point qui est important et souvent négligé, c'est de savoir refaire. Je vais expliquer.

Imaginez-vous administrateur système dans une entreprise, on vous charge d'installer un serveur web pour afficher une simple page html. Vous allez alors installer Debian + Apache puis placer le fichier html à la racine, rien de difficile jusque là.

Imaginez ensuite qu'au bout de 2 mois ce fichier html soit remplacé par un fichier php un peu plus avancé, vous allez alors installer libapache2-mod-php5 là encore c'est facile. Par la suite le fichier évolue encore et vous oblige à installer des modules, par exemple php5-gd et php5-curl.

Puis le serveur vit sa vie et au bout de 2 ans on vous demande d'en mettre en place un deuxième avec exactement le même rôle. Et là ça se complique car 2 ans c'est long et vous avez probablement oublié tout ce que vous et vos collègues avez fait pour configurer ce serveur au fur et à mesure. S'il est facile d'identifier que apache2 et php5 sont présents, en revanche les modules sont beaucoup moins évidents, surtout si vous avez utilisé des gestionnaires tiers tels que pecl, cpan, pip.

L'une des grandes problématiques est donc de trouver un moyen pour garder une trace et refaire rapidement toutes les étapes qui ont accompagné la vie du serveur. Alors bien sûr le grand classique est d'utiliser un wiki, mais qui vous garanti que ce qu'y s'y trouve représente bien ce qui est en production ? Personne n'est à l'abri d'une modification "urgente" en prod non rapportée sur le wiki.

Une solution que l'on retrouve souvent et qui est appliquée dans Ansible, Docker et NixOS, c'est d'éliminer toutes les manipulations sur la prod. On y touche plus, à la place on travaille sur un fichier de recette, que l'on va ensuite deployer et jouer. Sur Ansible ce sont les playbook, sur docker les Dockerfile, et sur NixOS le fichier configuration.nix.

Cela parait beaucoup plus propre et ça l'est, c'est une rigueur pas forcément naturelle qui paye sur le long terme. Néanmoins ce n'est pas toujours évident, une manipulation rapide à faire sur un serveur peut se transformer en plusieurs minutes voire heures de devops dans Ansible. Let's Encrypt est un exemple, son automatisation n'est pas simple car vous allez devoir gérer deux cas différents selon la présence ou non d'un certificat. En effet certbot peut soit utiliser le mode standalone et donc couper Nginx (car nécessité du port 80) ou alors utiliser le mode webroot et justement passer par Nginx + vhost de votre site, or ce dernier a justement besoin du certificat pour démarrer. Et quid du cas de Docker où vous devez créer un nouveau container et le relier à l'existant juste pour renouveler vos certificats.

En conclusion le boulot de sysadmin, développeur ou devops n'est pas seulement de faire ou réparer les choses mais également de prévoir l'avenir, s'imposer une rigueur même si elle parait contre-productive sur le moment. J'aurai probablement l'occasion de parler de plus en détail de Docker et de NixOS dans de prochains articles, restez branchés.

Fil RSS des articles de ce mot clé