2021-09-23 00:55:18 +00:00
|
|
|
|
## Prérequis
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez le télécharger
|
|
|
|
|
ici :\
|
2021-09-23 00:55:18 +00:00
|
|
|
|
<https://github.com/linuxkit/linuxkit/releases/latest>.
|
|
|
|
|
|
|
|
|
|
Notez qu'étant donné qu'il est écrit en Go, aucune dépendance n'est nécessaire
|
2022-11-15 21:34:03 +00:00
|
|
|
|
en plus du binaire[^lollibc]. Un simple `chmod +x` vous permettra de l'exécuter
|
|
|
|
|
depuis n'importe quel dossier
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
[^lollibc]: à condition tout de même que vous utilisiez une libc habituelle.
|
|
|
|
|
|
|
|
|
|
Vous aurez également besoin de QEMU pour tester vos créations.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Structure d'un fichier `linuxkit.yml`
|
|
|
|
|
|
|
|
|
|
Le fichier utilisé pour construire notre image se décompose en plusieurs
|
|
|
|
|
parties :
|
|
|
|
|
|
|
|
|
|
- `kernel` : il est attendu ici une image OCI contenant le nécessaire pour
|
2022-02-24 19:43:43 +00:00
|
|
|
|
pouvoir utiliser un noyau : l'image du noyau, ses modules et un initramfs ;
|
2021-09-23 00:55:18 +00:00
|
|
|
|
- `init` : l'ensemble des images OCI de cette liste seront fusionnés pour
|
2022-11-15 21:34:03 +00:00
|
|
|
|
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
|
2022-02-24 19:43:43 +00:00
|
|
|
|
moment ;
|
2021-09-23 00:55:18 +00:00
|
|
|
|
- `onboot`, `onshutdown` et `services` : il s'agit de conteneurs qui seront
|
2022-11-15 21:34:03 +00:00
|
|
|
|
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é.
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
2022-06-26 19:08:01 +00:00
|
|
|
|
Le format est documenté ici :
|
|
|
|
|
<https://github.com/linuxkit/linuxkit/blob/master/docs/yaml.md>
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
### Hello?
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
L'image la plus simple que l'on puisse réaliser pourrait être :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
kernel:
|
2022-11-15 21:34:03 +00:00
|
|
|
|
image: linuxkit/kernel:5.10.104
|
2021-09-23 00:55:18 +00:00
|
|
|
|
cmdline: "console=tty0 console=ttyS0"
|
|
|
|
|
init:
|
2022-11-15 21:34:03 +00:00
|
|
|
|
- linuxkit/init:8f1e6a0747acbbb4d7e24dc98f97faa8d1c6cec7
|
|
|
|
|
- linuxkit/runc:f01b88c7033180d50ae43562d72707c6881904e4
|
|
|
|
|
- linuxkit/containerd:de1b18eed76a266baa3092e5c154c84f595e56da
|
2021-09-23 00:55:18 +00:00
|
|
|
|
onboot:
|
|
|
|
|
- name: dhcpcd
|
2022-11-15 21:34:03 +00:00
|
|
|
|
image: linuxkit/dhcpcd:52d2c4df0311b182e99241cdc382ff726755c450
|
2021-09-23 00:55:18 +00:00
|
|
|
|
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
|
|
|
|
services:
|
|
|
|
|
- name: getty
|
2022-11-15 21:34:03 +00:00
|
|
|
|
image: linuxkit/getty:76951a596aa5e0867a38e28f0b94d620e948e3e8
|
2021-09-23 00:55:18 +00:00
|
|
|
|
env:
|
|
|
|
|
- INSECURE=true
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
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}
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
accès entièrement privilégier. Pour déboguer, il faut placer cette image dans
|
2022-05-12 00:46:31 +00:00
|
|
|
|
la partie `init`, elle sera alors lancée comme un équivalent de
|
2021-09-23 00:55:18 +00:00
|
|
|
|
`init=/bin/sh`.[^infogetty]
|
|
|
|
|
|
|
|
|
|
[^infogetty]: Plus d'infos à
|
|
|
|
|
<https://github.com/linuxkit/linuxkit/blob/master/pkg/getty/README.md#linuxkit-debug>
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
:::::
|
|
|
|
|
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
## `namespaces`
|
|
|
|
|
|
|
|
|
|
Chaque nouveau conteneur est donc lancé dans un espace distinct où il ne pourra
|
|
|
|
|
pas interagir avec les autres, ou déborder s'il s'avérait qu'il expose une
|
|
|
|
|
faille exploitable.
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
Néanmoins, contrairement à Docker qui, de base, va nous dissocier du maximum de
|
2021-09-23 00:55:18 +00:00
|
|
|
|
*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.
|
|
|
|
|
|
|
|
|
|
Il reste possible de se dissocier également de ces namespaces, en précisant :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- name: getty
|
2021-11-26 20:53:13 +00:00
|
|
|
|
image: linuxkit/getty:ed32c71531f5998aa510847bb07bd847492d4101
|
2021-09-23 00:55:18 +00:00
|
|
|
|
net: new
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Ou inversement, pour persister dans le namespace initial :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- name: getty
|
2021-11-26 20:53:13 +00:00
|
|
|
|
image: linuxkit/getty:ed32c71531f5998aa510847bb07bd847492d4101
|
2021-09-23 00:55:18 +00:00
|
|
|
|
pid: host
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Partage de `namespace`
|
|
|
|
|
|
|
|
|
|
Dans le cas où l'on souhaite que deux conteneurs partagent le même *namespace*,
|
|
|
|
|
il faut passer le chemin vers la structure du noyau correspondante.
|
|
|
|
|
|
|
|
|
|
On commence donc d'abord par créer le nouveau *namespace*, en prenant soin de
|
|
|
|
|
*bind mount* la structure du noyau à un emplacement connu :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- name: getty
|
2021-11-26 20:53:13 +00:00
|
|
|
|
image: linuxkit/getty:ed32c71531f5998aa510847bb07bd847492d4101
|
2021-09-23 00:55:18 +00:00
|
|
|
|
net: new
|
|
|
|
|
runtime:
|
|
|
|
|
bindNS: /run/netns/mynewnetns
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
À la création du *namespace* `net`, le lien vers la structure du noyau
|
|
|
|
|
correspondante sera *bind mount* sur `/run/netns/synchro`. On pourra alors
|
|
|
|
|
réutiliser plus tard ce chemin, en remplacement du mot clef `new` :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- name: xxxx
|
2021-11-19 23:00:30 +00:00
|
|
|
|
image: linuxkit/xxxx:v0.8
|
2021-09-23 00:55:18 +00:00
|
|
|
|
net: /run/netns/mynewnetns
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Construction et démarrage
|
|
|
|
|
|
|
|
|
|
Toute la puissance de `linuxkit` repose dans son système de construction et
|
|
|
|
|
surtout de lancement. En effet, il peut construire des images pour un grand
|
|
|
|
|
nombre de plate-forme, mais il est également possible d'utiliser les API de ces
|
2022-02-24 19:43:43 +00:00
|
|
|
|
plates-formes pour aller y lancer des instances de cette image !
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
Pour construire l'image faite précédemment :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```bash
|
|
|
|
|
linuxkit build hello.yml
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Cela va générer plusieurs fichiers dont un noyau (extrait de l'image de la
|
2022-02-24 19:43:43 +00:00
|
|
|
|
partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour
|
2021-09-23 00:55:18 +00:00
|
|
|
|
tester, n'attendons pas davantage pour lancer :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```bash
|
|
|
|
|
linuxkit run qemu -gui hello
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Ajouter un service
|
|
|
|
|
|
|
|
|
|
Maintenant que notre machine fonctionne, que nous pouvons interagir avec elle,
|
|
|
|
|
tentons de se passer de l'interface de QEMU (option `-gui`) en ajoutant un
|
|
|
|
|
serveur SSH aux `services` :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- name: sshd
|
2022-11-15 21:34:03 +00:00
|
|
|
|
image: linuxkit/sshd:4696ba61c3ec091328e1c14857d77e675802342f
|
|
|
|
|
binds.add:
|
|
|
|
|
- /root/.ssh:/root/.ssh
|
2021-09-23 00:55:18 +00:00
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
::::: {.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>
|
|
|
|
|
|
|
|
|
|
:::::
|
|
|
|
|
|
2022-05-12 00:46:31 +00:00
|
|
|
|
Comme nous n'avons défini aucun mot de passe, il va falloir utiliser une clef
|
2021-09-23 00:55:18 +00:00
|
|
|
|
SSH pour se connecter. Voilà un bon début d'utilisation de la section `files` :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- path: root/.ssh/authorized_keys
|
|
|
|
|
source: ~/.ssh/id_rsa.pub
|
|
|
|
|
mode: "0600"
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
2022-11-15 21:34:03 +00:00
|
|
|
|
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.
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Interface réseau virtuelle
|
|
|
|
|
|
|
|
|
|
Lorsque l'on souhaite se dissocier d'un *namespace* `net` afin de s'isoler,
|
|
|
|
|
mais que l'on veut tout de même pouvoir communiquer, il est nécessaire de créer
|
|
|
|
|
une interface `virtual ethernet` :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```yaml
|
|
|
|
|
- name: db
|
|
|
|
|
image: mariadb:latest
|
|
|
|
|
net: new
|
|
|
|
|
runtime:
|
|
|
|
|
bindNS:
|
|
|
|
|
net: /run/netns/db
|
|
|
|
|
interfaces:
|
|
|
|
|
- name: vethin-db
|
|
|
|
|
add: veth
|
|
|
|
|
peer: veth-db
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
2022-04-08 20:39:14 +00:00
|
|
|
|
::::: {.exercice}
|
2021-09-23 00:55:18 +00:00
|
|
|
|
|
|
|
|
|
Réalisez une recette `vault.yml` démarrant une instance du gestionnaire de
|
|
|
|
|
secrets [Hashicorp Vault](https://www.vaultproject.io/), utilisant une [base de
|
|
|
|
|
données au
|
|
|
|
|
choix](https://www.vaultproject.io/docs/configuration/storage/index.html)
|
|
|
|
|
(Consul, Etcd, MySQL, Cassandra, ...).
|
|
|
|
|
|
|
|
|
|
Au démarrage, Vault devra déjà être configuré pour parler à sa base de données,
|
|
|
|
|
qui devra se trouver dans un conteneur isolé et non accessible d'internet. Il
|
2022-02-24 19:43:43 +00:00
|
|
|
|
faudra donc établir un lien `virtual ethernet` entre les deux conteneurs ; et
|
2021-09-23 00:55:18 +00:00
|
|
|
|
ne pas oublier de le configurer (automatiquement au *runtime*, grâce à un
|
|
|
|
|
[`poststart`
|
|
|
|
|
*hook*](https://github.com/opencontainers/runtime-spec/blob/master/config.md#posix-platform-hooks)
|
|
|
|
|
ou bien à un conteneur issu du *package*
|
|
|
|
|
[`ip`](https://github.com/linuxkit/linuxkit/tree/master/pkg/ip)).
|
|
|
|
|
|
|
|
|
|
Les permissions étant généralement très strictes, vous aurez sans doute besoin
|
|
|
|
|
de les assouplir un peu en ajoutant des *capabilities* autorisées à vos
|
|
|
|
|
conteneurs, sans quoi vos conteneurs risquent d'être tués prématurément.
|
|
|
|
|
|
|
|
|
|
En bonus, vous pouvez gérer la [persistance des
|
|
|
|
|
données](https://github.com/linuxkit/linuxkit/blob/master/examples/swap.yml)
|
|
|
|
|
stockées dans Vault.
|
2022-04-08 20:39:14 +00:00
|
|
|
|
|
|
|
|
|
:::::
|