tuto5: add part on filesystems

This commit is contained in:
nemunaire 2022-11-15 22:34:03 +01:00
commit d02f573142
8 changed files with 547 additions and 45 deletions

View file

@ -1,6 +1,12 @@
include ../pandoc-opts.mk
SOURCES = tutorial.md oci.md registry.md runc.md linuxkit.md linuxkit-content.md rendu.md
SOURCES = tutorial.md \
registry.md \
../4/filesystem.md ../4/filesystem-ex.md ../4/filesystem-more.md \
oci.md \
runc.md \
linuxkit.md linuxkit-content.md \
rendu.md
all: tutorial.pdf

View file

@ -1,10 +1,12 @@
## Prérequis
Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez télécharger ici :\
Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez le télécharger
ici :\
<https://github.com/linuxkit/linuxkit/releases/latest>.
Notez qu'étant donné qu'il est écrit en Go, aucune dépendance n'est nécessaire
en plus du binaire[^lollibc] ;-)
en plus du binaire[^lollibc]. Un simple `chmod +x` vous permettra de l'exécuter
depuis n'importe quel dossier
[^lollibc]: à condition tout de même que vous utilisiez une libc habituelle.
@ -19,51 +21,77 @@ parties :
- `kernel` : il est attendu ici une image OCI contenant le nécessaire pour
pouvoir utiliser un noyau : l'image du noyau, ses modules et un initramfs ;
- `init` : l'ensemble des images OCI de cette liste seront fusionnés pour
donner naissance au *rootfs* de la machine. On n'y place normalement qu'un
gestionnaire de conteneur, qui sera chargé de lancer chaque conteneur au bon
donner naissance au *rootfs* de la machine. On y place normalement qu'un
gestionnaire de conteneurs, qui sera chargé de lancer chaque conteneur au bon
moment ;
- `onboot`, `onshutdown` et `services` : il s'agit de conteneurs qui seront
lancés par le système disponible dans l'`init`, au bon moment. Les conteneurs
indiqués dans `onboot` seront lancés **séquentiellement** au démarrage de la
machine, ceux dans `onshutdown` seront lancés lors de l'arrêt de la
machine. Les conteneurs dans `services` seront lancés simultanément une fois
que le dernier conteneur de `onboot` aura rendu la main ;
- `files` : des fichiers supplémentaires à placer dans le rootfs.
lancés par le gestionnaire disponible dans l'`init`, au moment désigné.\ Les
conteneurs indiqués dans `onboot` seront lancés **séquentiellement** au
démarrage de la machine, ceux dans `onshutdown` seront lancés lors de l'arrêt
de la machine. Les conteneurs dans `services` seront lancés simultanément une
fois que le dernier conteneur de `onboot` aura rendu la main ;
- `files` : des fichiers supplémentaires à placer dans le système de fichier à
l'emplacement déterminé.
Le format est documenté ici :
<https://github.com/linuxkit/linuxkit/blob/master/docs/yaml.md>
## Hello?
### Hello?
L'image la plus simple que l'on puisse réaliser pourrait être :
<div lang="en-US">
```yaml
kernel:
image: linuxkit/kernel:5.10.76
image: linuxkit/kernel:5.10.104
cmdline: "console=tty0 console=ttyS0"
init:
- linuxkit/init:eb597ef74d808b5320ad1060b1620a6ac31e7ced
- linuxkit/runc:21dbbda709ae138de0af6b0c7e4ae49525db5e88
- linuxkit/containerd:2f0907913dd54ab5186006034eb224a0da12443e
- linuxkit/init:8f1e6a0747acbbb4d7e24dc98f97faa8d1c6cec7
- linuxkit/runc:f01b88c7033180d50ae43562d72707c6881904e4
- linuxkit/containerd:de1b18eed76a266baa3092e5c154c84f595e56da
onboot:
- name: dhcpcd
image: linuxkit/dhcpcd:v0.8
image: linuxkit/dhcpcd:52d2c4df0311b182e99241cdc382ff726755c450
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
services:
- name: getty
image: linuxkit/getty:ed32c71531f5998aa510847bb07bd847492d4101
image: linuxkit/getty:76951a596aa5e0867a38e28f0b94d620e948e3e8
env:
- INSECURE=true
trust:
org:
- linuxkit
```
</div>
L'image `getty` est très pratique pour déboguer, car elle permet d'avoir un
shell sur la machine !
On retrouve nos différentes sections : `kernel` indique qu'il faut récupérer
l'image `linuxkit/kernel` depuis le registre Docker : il ne s'agit pas d'une
image qui sera lancé, elle est plutôt utilisée comme une archive de stockage
pour le noyau et ses modules. LinuxKit au moment de la construction de l'image
se chargera de placer les fichiers aux bons endroits.
Ensuite, nous avons une section `init` qui déclare 3 images Docker :
- `linuxkit/init` contient les fichiers de base et un binaire `/sbin/init` qui
servira de système d'initialisation ;
- `linuxkit/runc` nous donnera les outils pour lancer des conteneurs ;
- `linuxkit/containerd` apporte un daemon pour gérer les conteneurs pendant
leur durée de vie.
Ces trois images ne sont pas non plus des images Docker conventionnelles, dans
le sens où on ne peut pas les utiliser pour faire un `docker container
run`. Elles contiennent chacune une partie de l'arborescence du système de
fichiers, uniquement les fichiers nécessaire, en plus, au fonctionnement du
programme qu'elles ajoutent. Les images déclarées dans la section `init` seront
fusionnées ensemble et formeront le système de fichiers de base de notre image
LinuxKit.
Enfin les sections `onboot` et `services` sont plus conventionnelles : il
s'agit bien d'images Docker, les conteneurs seront lancés comme tel, à partir
d'une configuration `runc` qui sera générée au moment de la construction de
l'image LinuxKit.
L'image `getty` est notamment très pratique pour déboguer, car elle permet
d'avoir un shell sur la machine !
::::: {.more}
On notera cependant que, positionné dans `services`, le shell que nous
obtiendrons sera lui-même exécuté dans un conteneur, nous n'aurons donc pas un
@ -74,6 +102,8 @@ la partie `init`, elle sera alors lancée comme un équivalent de
[^infogetty]: Plus d'infos à
<https://github.com/linuxkit/linuxkit/blob/master/pkg/getty/README.md#linuxkit-debug>
:::::
## `namespaces`
@ -81,7 +111,7 @@ Chaque nouveau conteneur est donc lancé dans un espace distinct où il ne pourr
pas interagir avec les autres, ou déborder s'il s'avérait qu'il expose une
faille exploitable.
Néanmoins, contrairement à Docker qui va de base nous dissocier du maximum de
Néanmoins, contrairement à Docker qui, de base, va nous dissocier du maximum de
*namespaces*, `linuxkit` ne le fait pas pour les *namespaces* `net`, `ipc` et
`uts`. C'est-à-dire que, par défaut, la pile réseau est partagée entre tous les
conteneurs, tout comme les IPC et le nom de la machine.
@ -173,10 +203,29 @@ serveur SSH aux `services` :
<div lang="en-US">
```yaml
- name: sshd
image: linuxkit/sshd:add8c094a9a253870b0a596796628fd4ec220b70
image: linuxkit/sshd:4696ba61c3ec091328e1c14857d77e675802342f
binds.add:
- /root/.ssh:/root/.ssh
```
</div>
::::: {.question}
#### Que fait la ligne `binds.add` ? {-}
\
Avec l'instruction `binds.add`, LinuxKit va créer un *bind mount* selon le même
principe que les volumes des conteneurs Docker. Ici nous allons partager le
dossier `/root/.ssh` de notre image LinuxKit avec celui du conteneur `sshd`.
\
Un certain nombre de *bind mounts* sont effectués par défaut. Ceux-ci sont
déclarés dans les métadonnées des images. Pour avoir la liste, il convient de
regarder le fichier `build.yml` de chaque image :\
<https://github.com/linuxkit/linuxkit/blob/master/pkg/sshd/build.yml#L5>
:::::
Comme nous n'avons défini aucun mot de passe, il va falloir utiliser une clef
SSH pour se connecter. Voilà un bon début d'utilisation de la section `files` :
@ -188,12 +237,10 @@ SSH pour se connecter. Voilà un bon début d'utilisation de la section `files`
```
</div>
Ceci va aller chercher votre clef RSA publique sur votre machine, pour
la placer directement comme contenu du fichier `authorized_keys`.
Ceci va aller chercher votre clef RSA publique sur votre machine, pour la
placer directement comme contenu du fichier `authorized_keys`. À adapter en
fonction de votre situation.
Notons qu'il est inutile d'ajouter un *bind mount* du dossier `.ssh` ainsi
recopié, car le *package* `linuxkit/sshd` défini déjà cela :\
cf. <https://github.com/linuxkit/linuxkit/blob/master/pkg/sshd/build.yml#L5>
## Interface réseau virtuelle

View file

@ -7,6 +7,8 @@ Formée en juin 2015, l'Open Container Initiative (OCI) a pour but d'établir le
standard commun aux programmes de contenerisation, afin d'éviter une
fragmentation de l'écosystème.
## Spécifications
Trois spécifications ont été écrites :
- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définis les paramètres du démarrage d'un conteneur ;
@ -14,7 +16,7 @@ Trois spécifications ont été écrites :
- [`distribution-spec`](https://github.com/opencontainers/distribution-spec/blob/master/spec.md): définis la manière dont sont partagées et récupérées les images.
## `runtime-spec`
### `runtime-spec`
`runc` est l'implémentation de cette spécification ; elle a été extraite de
`docker`, puis donnée par Docker Inc. à l'OCI.
@ -38,7 +40,7 @@ plus de conteneur a proprement parlé, il fait seulement en sorte d'atteindre
l'état voulu par cette spécification, avant de passer la main à `runc`.
## `image-spec`
### `image-spec`
Une image OCI est composée d'un manifest, d'une suite de couches de systèmes de
fichiers, d'une configuration ainsi qu'un index d'image optionnel.
@ -68,14 +70,14 @@ là-dedans que finissent toutes les métadonnées que l'on inscrit dans nos
des couches du système de fichiers, ainsi que l'historique de l'image.
## `distribution-spec`
### `distribution-spec`
Dernière née de l'organisme, cette spécification fédère la notion de
*registre* : une API REST sur HTTP où l'on peut récupérer des images, mais
aussi en envoyer.
## Pour aller plus loin {-}
### Pour aller plus loin {-}
Si maintenant `docker` fait appel à un programme externe pour lancer
effectivement nos conteneurs, c'est que l'on peut changer cette

View file

@ -49,7 +49,7 @@ registre.
Avec `jq`, on peut l'extraire grâce à :
<div lang="en-US">
```bash
```
| jq -r .token
```
</div>
@ -149,7 +149,7 @@ tar xzf ${DL_LAYER} -C rootfs
Et voilà, nous avons extrait notre première image, nous devrions pouvoir :
<div lang="en-US">
```bash
```
42sh# chroot rootfs /hello
Hello from Docker!
[...]
@ -164,7 +164,7 @@ Hello from Docker!
Réalisez un script pour automatiser l'ensemble de ces étapes :
<div lang="en-US">
```bash
```
42sh$ cd $(mktemp -d)
42sh$ ./registry_play library/hello-world:latest

View file

@ -1,7 +1,5 @@
\newpage
`runc`
======
------
`runc` est le programme qui est responsable de la création effective du
conteneur : c'est lui qui va mettre en place toute la machinerie, les points de
@ -18,14 +16,14 @@ Pour appréhender l'utilisation de `runc` sans l'aide de Docker, nous allons
essayer de lancer un shell `alpine` avec un volume dans notre home.
## Prérequis
### Prérequis
Vous devriez avoir le binaire `runc` ou `docker-runc`. Si ce n'est pas le cas,
vous pouvez télécharger la dernière version :
<https://github.com/opencontainers/runc/releases>.
## Extraction du rootfs
### Extraction du rootfs
À l'aide du script d'extraction de registre déjà réalisé, extrayons le
*rootfs* d'alpine : `library/alpine` dans le registre Docker.
@ -40,7 +38,7 @@ docker image save alpine | tar xv -C rootfs
</div>
## Modèle de configuration
### Modèle de configuration
L'écriture complète d'un fichier `config.json` pour `runc` est plutôt
fastidieux et répétitif, nous allons donc gagner du temps et utiliser la
@ -57,7 +55,7 @@ Pour savoir à quoi correspondent tous ces éléments, vous pouvez consulter :\
Rassurez-vous, il n'y a que très peu de champs à modifier.
## Test brut
### Test brut
Voici comment nous pouvons tester le fonctionnement de notre *bundle* :
@ -87,7 +85,7 @@ virli1 12345 running /tmp/work/runctest 2012-12-12T12:12:12.123456789Z root
</div>
## Attacher notre `home`
### Attacher notre `home`
Dans le modèle de `config.json`, il y a déjà de nombreux systèmes de fichiers
qui sont montés. Nous pouvons les filtrer avec :