smolBSD : UNIX façon « Ikea »

Magazine
Marque
Linux Pratique
Numéro
141
Mois de parution
janvier 2024
Spécialité(s)


Résumé

Dans les séries américaines, on appelle ce genre d’histoire un crossover, les premières occurrences ont démarré dans Linux Pratique, puis une partie plus profonde sur l’amincissement d’un noyau NetBSD, pas nécessairement utile pour la finalité de notre produit, a fait son apparition dans GNU/Linux Magazine. Aujourd’hui, nous allons apprendre à construire un système BSD UNIX, NetBSD, From Scratch.


Body

Un petit rappel s’impose. L’objectif final de cette expérience est de créer des micro-services à la serverless, autrement dit des machines virtuelles qui démarrent en moins d’une seconde avec le service désiré (serveur web, mail, proxy IRC…) afin d’obtenir une isolation totale entre les différents services, modulo d’éventuels problèmes de sécurité impliquant l’hyperviseur.

Dans GNU/Linux Magazine 265 [1], nous avons appris comment charcut^Wmodifier un noyau NetBSD pour faire démarrer celui-ci en quelques centaines de millisecondes. Dans le cadre de cet article, nous utiliserons un outil tierce partie, confkerndev [2] qui réalise cette opération de façon simple et rapide.

1. Un disque plein de zéros

Tel l’artiste peintre nous allons nécessiter une toile vierge pour réaliser notre expérience ; cette dernière prend la forme d’un fichier qui aura la taille du disque virtuel que nous allons utiliser et sera rempli de zéros, littéralement. Le but de l’opération est de créer un périphérique de type « bloc », soit un disque dur logique, que le noyau considèrera comme tel, et de l’affubler de tous les éléments nécessaires au fonctionnement d’un système d’exploitation.

Une telle opération nécessite l’utilisation du programme dd(1), véritable couteau suisse de la manipulation de fichiers bruts, en voici la syntaxe :

$ mkdir ~/smol && cd ~/smol
$ dd if=/dev/zero of=./disque.img bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00628624 s, 1.7 GB/s

Explication : on utilise en entrée le périphérique /dev/zero qui renvoie uniquement des zéros et on envoie le résultat dans le fichier disque.img, avec une taille de bloc de 1 mégaoctet, 10 fois, ce qui créera un fichier rempli de zéros de 10 mégaoctets. On aurait parfaitement pu produire le même résultat en utilisant bs=10M count=1 ou encore bs=100K count=100.

Munis de cette matière brute, nous allons maintenant la « formater », ou plus précisément, ordonner ce disque pour que le système d’exploitation puisse y inscrire des données et le retrouver, l’organiser donc. Puisque nous menons notre expérience sous GNU/Linux, nous réalisons cette opération à l’aide de mke2fs, car en effet, même si le système cible est NetBSD, ce dernier est parfaitement capable de lire, et même démarrer, sur un système de fichiers ext2, propre au noyau Linux. Un bémol néanmoins, le noyau NetBSD ne supporte pas les dernières additions à ce format, comme par exemple la journalisation, il faut dont ajouter l’option -O none à la ligne de commandes pour formater notre image au format ext2 sans aucune fonctionnalité supplémentaire :

$ mke2fs -O none disque.img
mke2fs 1.46.5 (30-Dec-2021)
Discarding device blocks: done                            
Creating filesystem with 2560 4k blocks and 2560 inodes
 
Allocating group tables: done                            
Writing inode tables: done                            
Writing superblocks and filesystem accounting information: done

Maintenant que nous disposons d’un périphérique de type bloc formaté, nous pouvons le monter ! GNU/Linux implémente une fonctionnalité permettant d’« attacher » un fichier à un périphérique virtuel, le loopback device. Ce tour de passe-passe est effectué en coulisses par la commande mount lorsqu’elle est appelée avec l’option -o loop :

$ mkdir mnt
$ sudo mount -o loop disque.img mnt
$ ls mnt
lost+found

Un disque ma foi parfaitement normal.

2. Aménagement

Nous avons créé le contenant, il est temps de s’occuper du contenu. NetBSD, fidèle héritier des systèmes BSD UNIX, est composé de deux sources d’outils, le système de base (base system) et les paquets tiers (pkgsrc). Au contraire de GNU/Linux, le système de base ne se présente pas sous forme de paquets de tel ou tel format, il s’agit simplement d’archives au format tar.gz qu’on appelle des sets. Ces sets contiennent les outils de base qui constituent un système d’exploitation NetBSD, pensez par exemple à ls, df, ps, du… mais également aux serveurs fondamentaux tels que postfix, bind ou encore sshd. Le contenu de ces sets est référencé dans le répertoire /etc/mtree, chaque set étant associé à un fichier set.<categorie>, dans ces derniers, on trouve le type, le mode, la taille et le hash sha256 du fichier concerné, par exemple pour set.base :

$ head -5 /etc/mtree/set.base
. type=dir uname=root gname=wheel mode=0755
./altroot type=dir uname=root gname=wheel mode=0755
./bin type=dir uname=root gname=wheel mode=0755
./bin/\133 type=file uname=root gname=wheel mode=0555 size=19984 sha256=c3cff33a7a09c62e2cf02c0399137e8ef3bda0ea0eb79e3b6cb2763dec23f225
./bin/cat type=file uname=root gname=wheel mode=0555 size=19840 sha256=4ee5b16ab6844dbc0d167c3763d0f83d0105b745cc49ab5753b9fb7074cab317

Ces archives se téléchargent simplement sur les divers miroirs du projet NetBSD, ou plus rapidement sur le CDN NetBSD [3], gracieusement proposé par Fastly.

Pour cet article, nous travaillerons avec la version 9.3 de NetBSD, aussi nous récupèrerons les sets à cette adresse https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/i386/binary/sets/.

Parmi tous ces sets, il en est un particulier : rescue.tgz. Ce set est peuplé avec les outils les plus communs destinés à réparer un système en mauvais état, ces outils sont liés statiquement afin d’en diminuer les dépendances sur des fichiers dispersés sur un disque potentiellement endommagé, et réduits à leur plus simple expression, c’est-à-dire qu’ils ne sont affublés d’aucune fonctionnalité superflue.

Une autre particularité est que tous ces outils sont en réalité compilés en un seul binaire dont la fonctionnalité sera déterminée par argv[0], soit le nom du programme appelé, comme le réalise la trousse à outils busybox [4] sous GNU/Linux. En conséquence, le contenu de rescue.tgz se résume à une centaine d’outils qui sont tous des liens vers /bin/[ dont la taille est de… 7Mo :

$ tar ztvf sets/rescue.tgz |head -5
-r--r--r-- root/wheel   23015 2022-08-04 17:30 ./etc/mtree/set.rescue
-r-xr-xr-x root/wheel 7126064 2022-08-04 17:30 ./rescue/[
hr-xr-xr-x root/wheel       0 2022-08-04 17:30 ./rescue/atactl link to ./rescue/[
hr-xr-xr-x root/wheel       0 2022-08-04 17:30 ./rescue/badsect link to ./rescue/[
hr-xr-xr-x root/wheel       0 2022-08-04 17:30 ./rescue/brconfig link to ./rescue/[

Pour les plus curieux, l’outil utilisé pour générer cette trousse à outils se nomme crunchgen(1) et se trouve dans /usr/bin dans n’importe quel système NetBSD.

Peuplons donc notre disque vierge avec le contenu de ce set :

$ sudo tar zxvfp sets/rescue.tgz -C mnt/

Ceci va extraire le set dans le répertoire mnt/rescue.

L’objectif de cette expérience étant de faire démarrer un système sur ce disque virtuel, nous avons besoin d’un fichier /etc/rc, qui est exécuté par le premier processus démarré par le noyau, init. Le code source du noyau NetBSD en charge de l’appel à init [5] montre le tableau suivant :

static const char * const initpaths[] = {
    "/sbin/init",
    "/sbin/oinit",
    "/sbin/init.bak",
    "/rescue/init",
    NULL,
};

Tableau parcouru par la fonction start_init 10 lignes plus loin, qui exécutera la première occurrence existante de la liste. Comme on peut le voir, /rescue/init fait partie des possibilités, aussi, inutile de copier ce dernier dans /sbin.

On peut constater l’appel au fichier /etc/rc susnommé dans le code source d’init [6], nous allons créer ce fichier de démarrage avec un contenu basique :

#!/rescue/sh
 
export HOME=/
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/rescue
umask 022
 
mount -a
 
echo "OHAI!"
 
sh

Dans ce script :

  1. on s’assure que le chemin vers l’interpréteur est bien /rescue (mais on pourrait aussi bien créer un lien de /rescue/sh vers /bin/sh) ;
  2. on déclare la variable $HOME pour les programmes qui en auront besoin ;
  3. on s’assure d’ajouter /rescue au $PATH ;
  4. on crée un masque de création de fichiers classique, 022, soit u=rwx,g=rx,o=rx ;
  5. on mount tous les systèmes de fichiers ;
  6. on affiche un texte « témoin » ;
  7. on exécute sh, qui est dans le $PATH précédemment déclaré.

Le point 5 implique que nous devons créer un fichier /etc/fstab afin d’indiquer à mount quelles sont les partitions disponibles :

/dev/ld0a / ext2fs rw 1 1

Le disque que nous allons monter au démarrage de cette machine virtuelle est de type VirtIO [7], ces périphériques sont présentés avec le nom ld[0-9][a-z][0-9] est le numéro du disque et [a-z] la partition. Ici, nous montons la première partition du premier disque.

Mais ceci implique encore un ajout dans notre disque virtuel, au minimum la création du fichier de périphérique correspondant. Cette opération est réalisée avec le programme mknod(1) :

$ sudo mkdir mnt/dev
$ sudo mknod -m 640 mnt/dev/ld0a b 19 0

Quelques explications s’imposent. On invoque le programme mknod(1) dont le but est de créer des fichiers spéciaux, des fichiers de périphériques de type bloc (typiquement des disques ou équivalents) ou caractère (typiquement des périphériques dont on lit le contenu séquentiellement, comme par exemple un port série). Ici, on indique que le mode du fichier sera 640 (u=rw,g=r,o=), que son nom est ld0a, qu’il s’agit d’un périphérique de type bloc et que les identifiants major et minor du périphérique sont respectivement 19 et 0. Le premier chiffre, le major, indique le numéro affecté par le noyau au périphérique dont nous souhaitons créer l’interface. Ce chiffre, sous GNU/Linux, est indiqué par le fichier virtuel /proc/devices, sous NetBSD, c’est la commande sysctl kern.drivers qui indique quels sont les nombres liés au pilote, ici ld(4). Et j’ai bien dit les nombres, car les systèmes héritiers de BSD UNIX ont deux modes d’accès possibles pour manipuler un disque, le mode brut (raw), qui permet d’accéder au disque de façon directe, octet par octet, et le mode bloc, de plus haut niveau, dans lequel le disque est lu par blocs de taille fixe, à l’aide de fonctionnalités de plus haut niveau mises en place par le noyau.

La commande sysctl kern.drivers (sur un système NetBSD) nous indique que le pilote ld répond à deux majors :

$ doas sysctl kern.drivers|egrep -o '[0-9]+ [0-9]+ ld'
69 19 ld

Dans la plupart des systèmes BSD UNIX, on préfère aujourd’hui utiliser la commande doas au lieu de sudo, car plus simple et plus lisible. Le premier ne bénéficie cependant pas des innombrables capacités du dernier.

69 est le major du périphérique brut, et 19 celui du périphérique bloc, que l’on souhaite utiliser pour monter notre partition. Finalement, le minor est simplement le numéro du périphérique, ici 0 puisqu’il s’agit du premier disque sur ce système vierge.

Avant de lancer QEMU, il conviendra de démonter le disque virtuel afin que toutes les modifications apportées soient bien inscrites, cela se fera simplement avec la commande umount mnt.

3. Punch it Chewie!

Le noyau que nous utiliserons est un noyau NetBSD à qui on a fait subir une cure d’amaigrissement forcée, et dont le détail de la réalisation est expliqué dans GLMF 265 ; en deux mots, nous pouvons réduire son temps de chargement à un dixième de secondes en désactivant tous les pilotes de périphériques inutiles dans un environnement virtualisé.Pour cet article, nous nous contenterons d’utiliser confkerndev, œuvre d’un certain Denis Bodor, qui réalise cette tâche en quelques instants. La procédure est la suivante :

Télécharger un noyau NetBSD et le décompresser :

$ curl -L -o- https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.3/i386/binary/kernel/netbsd-GENERIC.gz|gzip -dc >netbsd-GENERIC

Comme nous l’avons expliqué dans l’article dédié à cette opération dans GNU/Linux Magazine 265, seuls les noyaux i386 supportent l’appel direct avec le paramètre -kernel de QEMU.

Préparer confkerndev puis lui passer en paramètre le noyau à opérer ainsi que les pilotes de périphériques à conserver :

$ git clone https://gitlab.com/0xDRRB/confkerndev.git
$ cd confkerndev && make i386; cd ..
$ cp -f netbsd-GENERIC netbsd-SMOL
$ confkerndev/confkerndevi386 -v -i netbsd-SMOL -K virtio.list -w

La liste des pilotes de périphériques est la suivante :

$ cat virtio.list
mainbus
cpu
acpicpu
ioapic
pci
isa
pcdisplay
wsdisplay
com
virtio
ld
vioif

Spartiate.

Bien ! Ces prérequis installés sur notre mini système, pouvons-nous le démarrer ?

La machine virtuelle sera prise en charge par l’inénarrable QEMU qu’on lancera avec l’option -enable-kvm afin de disposer de l’accélération matérielle pour la virtualisation grâce au module noyau kvm. Nous n’aurons pas besoin de plus de 256Mo. La console, l’élément basique et indispensable nécessaire à l’affichage, est passée en paramètre au noyau NetBSD, on déclare que cette dernière sera disponible sur le port série (com). On déclare également que le système de fichiers racine (root filesystem) sera disponible sur le périphérique ld0a. On indique à QEMU que le port série sera redirigé vers stdio (la sortie standard) en préfixant cette dernière par mon: de façon à gérer l’appui sur Control-C et ne pas quitter l’émulateur quand cette séquence est pressée. On indique à QEMU qu’il n’y aura pas de sortie vidéo avec l’option -display none et finalement le chemin et le mode d’accès du disque virtuel à utiliser :

$ qemu-system-x86_64 -enable-kvm -m 256 -kernel netbsd-SMOL -append "console=com root=ld0a" -serial mon:stdio -display none -drive file=disque.img,if=virtio

Résultat ?

[   1.0600703] exec /sbin/init: error 2       
[   1.0600703] init: trying /sbin/oinit
[   1.0600703] exec /sbin/oinit: error 2
[   1.0616794] init: trying /sbin/init.bak
[   1.0616794] exec /sbin/init.bak: error 2
[   1.0616794] init: trying /rescue/init
[   1.0822102] panic: init died (signal 0, exit 11)
[   1.0822102] cpu0: Begin traceback...
[   1.0929236] ?(c13f930c,cd8a5e7c,cd8a5f1c,c0d58c7d,c13f930c,0,b,0,c1d1a100,c1e22740) at c0dc17ae
[   1.0929236] ?(c13f930c,0,b,0,c1d1a100,c1e22740,c1d1a100,c1d1a100,c0d3ef3a,0) at c0dc1877
address 0xd4e45f3c is invalid
[...]
uvm_fault(0xc1eaa020, 0, 1) -> 0xe
[   1.1464837] fatal page fault in supervisor mode
[   1.1464837] trap type 6 code 0 eip 0xc0102064 cs 0x8 eflags 0x210246 cr2 0 ilevel 0 esp 0xc0ae488
7
[   1.1464837] curlwp 0xc1e22740 pid 1 lid 1 lowest kstack 0xcd8a32c0
kernel: supervisor trap page fault, code=0
Stopped in pid 1.1 (init) at    c0102064:       movl    0(%eax),%ebx

Bruit de Millenium Falcon qui rate son passage en vitesse lumière...

Ok, ok, premier test de décollage raté, MAIS plusieurs choses sont à noter, premièrement on visualise bien que c’est /rescue/init qui a été utilisé pour démarrer, ensuite, un indice clé, ce kernel panic est lié à la sortie du programme init, et plus particulièrement une sortie avec un code de retour 11. Or l’analyse du code source de init [8] nous montre le code suivant :

    if (access(_PATH_CONSOLE, F_OK) == 0)
        return 0;
    _exit(11);

Dans le header include/paths.h, on peut lire :

#define       _PATH_CONSOLE   "/dev/console"

Et effectivement, nous n’avons pas créé le périphérique console. Comme pour le périphérique disque, nous créons ce dernier à l’aide de mknod(1) :

$ sudo mount -o loop
$ sudo mknod -m 640 mnt/dev/console c 0 0
$ sudo umount mnt

Et cette fois :

[   1.0567866] exec /sbin/init: error 2
[   1.0567866] init: trying /sbin/oinit
[   1.0567866] exec /sbin/oinit: error 2
[   1.0567866] init: trying /sbin/init.bak
[   1.0567866] exec /sbin/init.bak: error 2
[   1.0567866] init: trying /rescue/init
# [   3.6437474] entropy: best effort
OHAI!
# date
Tue Oct 17 05:13:49 GMT 2023
# df -h
Filesystem         Size       Used      Avail %Cap Mounted on
/dev/ld0a          9.4M       6.9M       2.0M  77% /
#

Victoire, nous avons atterri sur le shell appelé depuis /etc/rc en moins d’une seconde, en consommant à peine 7Mo ! À partir d’ici, plus de limite, nous pouvons construire l’OS qui nous plaît, brindille par brindille.

4. MicroVM ?

Nous sommes en possession d’une base de travail assez solide et reproductible pour envisager son utilisation réelle, en effet, ce mini système d’exploitation met pratiquement le même temps à démarrer qu’un simple programme, le surcoût de faire s’exécuter le service de notre choix dans /etc/rc serait négligeable, et permettrait d’isoler chaque service non pas à l’aide de simples namespaces à l’instar de Docker, mais d’une machine virtuelle complète.

La technique n’est pas nouvelle, c’est à peu près de cette façon que les services « serverless » d’AWS Lambda fonctionnent, en démarrant en une fraction de seconde des micromachines virtuelles qui exécutent du code qui leur est fourni. La solution créée et utilisée par AWS, Firecracker [9], est par ailleurs libre, son code source est disponible sur un dépôt GitHub dédié [10].

Afin de rendre cette microVM totalement opérationnelle avec un logiciel classique, il nous manque encore plusieurs entrées dans le répertoire /dev, pensez par exemple à null, zero, random, mais aussi stdin, stdout, stderr… Heureusement pour nous, nous allons retrouver tous ces périphériques indispensables dans un fichier habituellement invoqué par l’installateur NetBSD, /dev/MAKEDEV, qui comme son nom l’indique, crée les devices. Ce fichier est un script shell dans lequel on trouve un case intéressant pour notre scénario minimaliste :

std)
     mkdev       console c 0  0   600
     mkdev       constty c 0  1   600
     mkdev       drum    c 4  0   640 $g_kmem
     mkdev       kmem    c 2  1   640 $g_kmem
     mkdev       mem     c 2  0   640 $g_kmem
     mkdev       null    c 2  2   666
     mkdev       full    c 2  11  666
     mkdev       zero    c 2  12  666
     mkdev       klog    c 7  0   600
     mkdev       ksyms   c 85 0   440 $g_kmem
     mkdev       random  c 46 0   444
     mkdev       urandom c 46 1   644
     if ! $fdesc_mounted; then
         mkdev   tty     c 1  0   666
         mkdev   stdin   c 22 0   666
         mkdev   stdout  c 22 1   666
         mkdev   stderr  c 22 2   666
     fi
     ;;

Le cas std crée en effet les périphériques « standards » dont un système d’exploitation UNIX classique a besoin.

Armés de ces informations et de notre précédente expérience, nous disposons de tout le nécessaire pour nous fendre d’un petit script shell qui servira à générer une image disque minimale. Nous allons ajouter quelques raffinements :

  • le script doit être portable, il peut fonctionner sous GNU/Linux ou NetBSD ;
  • pour d’éventuels futurs portages, il devra être POSIX [11] ;
  • on peut lui passer des informations en paramètre.

Les paramètres en question :

  • la taille de l’image ;
  • son nom ;
  • le ou les set(s) à utiliser ;
  • un nom de service, qui nous servira à personnaliser l’image créée.

La portabilité porte essentiellement les aspects suivants :

  • le contenu de la fstab ;
  • la syntaxe de dd ;
  • la gestion du loopback.

Voici le script en question :

#!/bin/sh
 
usage()
{
    cat 1>&2 << _USAGE_
Usage: ${0##*/} [-s service] [-m megabytes] [-n image] [-x set]
    Create a root image
    -s service service name, default "rescue"
    -m megabytes    image size in megabytes, default 10
    -i image    image name, default root.img
    -x sets     list of NetBSD sets, default rescue.tgz
    -k kernel   kernel to copy in the image
_USAGE_
    exit 1
}
 
options="s:m:i:x:k:h"
 
while getopts "$options" opt
do
    case $opt in
    s) svc="$OPTARG";;
    m) megs="$OPTARG";;
    i) img="$OPTARG";;
    x) sets="$OPTARG";;
    k) kernel="$OPTARG";;
    h) usage;;
    *) usage;;
    esac
done
 
[ -z "$svc" ] && svc=rescue
[ -z "$megs" ] && megs=10
[ -z "$img" ] && img=rescue.img
[ -z "$sets" ] && sets=rescue.tgz
 
[ ! -f service/${svc}/etc/rc ] && \
    echo "no service/${svc}/etc/rc available" && exit 1
 
OS=$(uname -s)
 
[ "$OS" = "Linux" ] && is_linux=1
 
[ -n "$is_linux" ] && u=M || u=m
 
dd if=/dev/zero of=./${img} bs=1${u} count=${megs}
 
mkdir -p mnt
 
if [ -n "$is_linux" ]; then
    mke2fs -O none $img
    mount -o loop $img mnt
else
    vnd=$(vndconfig -l|grep -m1 'not'|cut -f1 -d:)
    vndconfig $vnd $img
    newfs /dev/${vnd}a
    mount /dev/${vnd}a mnt
fi
 
for s in ${sets}
do
    tar zxvfp sets/${s} -C mnt/
done
 
[ -n "$kernel" ] && cp -f $kernel mnt/
 
cd mnt
mkdir -p sbin bin dev etc/include
 
cp -f ../etc/fstab.${OS} etc/fstab
cp -f ../service/${svc}/etc/* etc/
cp -f ../service/common/* etc/include/
 
[ -d ../service/${svc}/postinst ] &&
    for x in ../service/${svc}/postinst/*.sh
    do
        sh $x
    done
 
if [ "$svc" = "rescue" ]; then
    for b in init mount_ext2fs
    do
        ln -s /rescue/$b sbin/
    done
    ln -s /rescue/sh bin/
fi
 
cd dev
 
mknod -m 600 console c 0  0
mknod -m 600 constty c 0  1
mknod -m 640 drum    c 4  0
mknod -m 640 kmem    c 2  1
mknod -m 640 mem     c 2  0
mknod -m 666 null    c 2  2
mknod -m 666 full    c 2  11
mknod -m 666 zero    c 2  12
mknod -m 600 klog    c 7  0
mknod -m 444 ksyms   c 85 0
mknod -m 444 random  c 46 0
mknod -m 644 urandom c 46 1
mknod -m 666 tty     c 1  0
mknod -m 666 stdin   c 22 0
mknod -m 666 stdout  c 22 1
mknod -m 666 stderr  c 22 2
mknod -m 640 ld0a    b 19 0
mknod -m 640 rld0a   c 69 0
mknod -m 640 ld1     b 19 11
mknod -m 640 ld1a    b 19 8
mknod -m 640 ld1d    b 19 11
mknod -m 640 rld1a   c 69 8
mknod -m 640 rld1d   c 69 11
 
cd ../..
 
umount mnt
 
[ -z "$is_linux" ] && vndconfig -u $vnd
 
exit 0

En regard de nos expériences durant cet article, les spécificités que nous avons énumérées prennent la forme suivante.

On crée sur la machine servant à générer l’image, au niveau du script, un répertoire etc qui contiendra un fichier fstab.<OS>, soit fstab.Linux ou fstab.NetBSD. Ceci permettra de différencier le système de fichiers à créer et à monter.

On crée également un répertoire service qui va contenir des personnalisations relatives à une image. Par exemple, on voudra certainement un fichier /etc/rc différent, et potentiellement des entrées dans /etc spécifiques. Mais comme on aura probablement besoin d’avoir des troncs communs, un répertoire service/common contiendra des scripts qui seront copiés dans /etc/include sur la cible et qu’on pourra inclure.

On se donne également la possibilité de réaliser des opérations post-installation, en exécutant tout script présent dans service/<nom du service>/postinst, par exemple :

$ cat service/base/postinst/dostuff.sh
#!/bin/sh
 
echo "iMil was here" > tmp/postinst.txt

Attention : Le script est lancé avec l’utilisateur root, ce qui signifie que les opérations post-installation également, prenez bien garde à utiliser des chemins relatifs et non absolus !

Une utilisation typique du script prendra la forme :

$ sudo ./mkimg.sh -i base.img -s base -m 300 -x "base.tgz etc.tgz"

Ce qui aura pour effet de générer une image base.img, utilisera les personnalisations créées dans service/base, générera un disque de 300Mo et y extraira le contenu des sets base et etc.

Ce script, et l’ensemble des prérequis sont disponibles dans le dépôt GitLab du projet mksmolnb [12] dont je suis l’auteur.

Conclusion

Notre preuve de concept fonctionne, mais nécessite maintenant un peu de travail pour la rendre exploitable en production, les étapes que nous avons suivies sont maintenant automatisées à l’aide d’un script, reste à trouver une manière élégante de déployer un service utile sur les microVM ainsi créées.

Nous utiliserons pour réaliser ces tâches les outils utilisés depuis la nuit des temps par les divers contributeurs des systèmes BSD à travers les âges, sh et make… mais ça, ce sera pour la prochaine fois ;)

Références

[1] iMil, « SmolBSD : un système UNIX de 7 mégaoctets qui démarre en moins d’une seconde », GNU/Linux Magazine n°265, septembre 2023 :
https://connect.ed-diamond.com/gnu-linux-magazine/glmf-265/smolbsd-un-systeme-unix-de-7-megaoctets-qui-demarre-en-moins-d-une-seconde

[2] https://gitlab.com/0xDRRB/confkerndev

[3] https://cdn.netbsd.org/

[4] https://www.busybox.net/

[5] https://github.com/NetBSD/src/blob/trunk/sys/kern/init_main.c#L948

[6] https://github.com/NetBSD/src/blob/trunk/sbin/init/init.c#L922

[7] https://wiki.libvirt.org/Virtio.html

[8] https://github.com/NetBSD/src/blob/trunk/sbin/init/init.c#L1742

[9] https://firecracker-microvm.github.io/

[10] https://github.com/firecracker-microvm/firecracker/

[11] https://en.wikipedia.org/wiki/POSIX

[12] https://gitlab.com/iMil/mksmolnb



Article rédigé par

Par le(s) même(s) auteur(s)

SmolBSD : un système UNIX de 7 mégaoctets qui démarre en moins d’une seconde

Magazine
Marque
GNU/Linux Magazine
Numéro
265
Mois de parution
septembre 2023
Spécialité(s)
Résumé

Que de racolage en si peu de mots. Et pourtant si, c’est bien la promesse de cet article, comment parvenir à construire un système d’exploitation fonctionnel en moins de… 10 mégabits. Quelle est cette sorcellerie ? En utilisant une fonctionnalité prévue, mais pas utilisée à cet escient par le noyau NetBSD, nous allons lui faire subir un régime drastique !

La grande migration, Épisode II

Magazine
Marque
Linux Pratique
Numéro
138
Mois de parution
juillet 2023
Spécialité(s)
Résumé

Dans l’épisode précédent [1], nous avons posé les premières briques d’une infrastructure d’auto-hébergement : vm-bhyve comme solution de virtualisation, sous FreeBSD donc, Wireguard comme gestionnaire de tunnel, une petite instance t4g.nano, 2 cœurs ARM64 et 512M de RAM chez AWS et un premier succès de déplacement de machine virtuelle hébergeant un simple serveur web d’un serveur dédié vers notre infrastructure personnelle. Nous allons voir maintenant comment migrer en douceur une machine virtuelle concentrant les services de base d’une architecture à l’autre.

Les derniers articles Premiums

Les derniers articles Premium

Sécurisez vos applications web : comment Symfony vous protège des menaces courantes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les frameworks tels que Symfony ont bouleversé le développement web en apportant une structure solide et des outils performants. Malgré ces qualités, nous pouvons découvrir d’innombrables vulnérabilités. Cet article met le doigt sur les failles de sécurité les plus fréquentes qui affectent même les environnements les plus robustes. De l’injection de requêtes à distance à l’exécution de scripts malveillants, découvrez comment ces failles peuvent mettre en péril vos applications et, surtout, comment vous en prémunir.

Bash des temps modernes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les scripts Shell, et Bash spécifiquement, demeurent un standard, de facto, de notre industrie. Ils forment un composant primordial de toute distribution Linux, mais c’est aussi un outil de prédilection pour implémenter de nombreuses tâches d’automatisation, en particulier dans le « Cloud », par eux-mêmes ou conjointement à des solutions telles que Ansible. Pour toutes ces raisons et bien d’autres encore, savoir les concevoir de manière robuste et idempotente est crucial.

Présentation de Kafka Connect

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Un cluster Apache Kafka est déjà, à lui seul, une puissante infrastructure pour faire de l’event streaming… Et si nous pouvions, d’un coup de baguette magique, lui permettre de consommer des informations issues de systèmes de données plus traditionnels, tels que les bases de données ? C’est là qu’intervient Kafka Connect, un autre composant de l’écosystème du projet.

Le combo gagnant de la virtualisation : QEMU et KVM

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

C’est un fait : la virtualisation est partout ! Que ce soit pour la flexibilité des systèmes ou bien leur sécurité, l’adoption de la virtualisation augmente dans toutes les organisations depuis des années. Dans cet article, nous allons nous focaliser sur deux technologies : QEMU et KVM. En combinant les deux, il est possible de créer des environnements de virtualisation très robustes.

Les listes de lecture

8 article(s) - ajoutée le 01/07/2020
Découvrez notre sélection d'articles pour faire vos premiers pas avec les conteneurs, apprendre à les configurer et les utiliser au quotidien.
11 article(s) - ajoutée le 02/07/2020
Si vous recherchez quels sont les outils du DevOps et comment les utiliser, cette liste est faite pour vous.
8 article(s) - ajoutée le 02/07/2020
Il est essentiel d'effectuer des sauvegardes régulières de son travail pour éviter de perdre toutes ses données bêtement. De nombreux outils sont disponibles pour nous assister dans cette tâche.
Voir les 60 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous