Update tuto2
This commit is contained in:
parent
5f097b4221
commit
2c5317f4f9
35 changed files with 3588 additions and 472 deletions
243
tutorial/docker-internals/linuxkit-content.md
Normal file
243
tutorial/docker-internals/linuxkit-content.md
Normal file
|
@ -0,0 +1,243 @@
|
|||
## Prérequis
|
||||
|
||||
Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez 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] ;-)
|
||||
|
||||
[^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
|
||||
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
|
||||
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.
|
||||
|
||||
Le format est documenté
|
||||
[ici](https://github.com/linuxkit/linuxkit/blob/master/docs/yaml.md).
|
||||
|
||||
|
||||
## Hello?
|
||||
|
||||
L'image la plus simple que l'on puisse réaliser pourrait être :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
kernel:
|
||||
image: linuxkit/kernel:4.14.80
|
||||
cmdline: "console=tty0 console=ttyS0"
|
||||
init:
|
||||
- linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1
|
||||
- linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe
|
||||
- linuxkit/containerd:326b096cd5fbab0f864e52721d036cade67599d6
|
||||
onboot:
|
||||
- name: dhcpcd
|
||||
image: linuxkit/dhcpcd:v0.6
|
||||
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
||||
services:
|
||||
- name: getty
|
||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||
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 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
|
||||
la partie `init`, elle sera alors lancé comme un équivalent de
|
||||
`init=/bin/sh`.[^infogetty]
|
||||
|
||||
[^infogetty]: Plus d'infos à
|
||||
<https://github.com/linuxkit/linuxkit/blob/master/pkg/getty/README.md#linuxkit-debug>
|
||||
|
||||
|
||||
## `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.
|
||||
|
||||
Néanmoins, contrairement à Docker qui va de base 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.
|
||||
|
||||
Il reste possible de se dissocier également de ces namespaces, en précisant :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
- name: getty
|
||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||
net: new
|
||||
```
|
||||
</div>
|
||||
|
||||
Ou inversement, pour persister dans le namespace initial :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
- name: getty
|
||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||
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
|
||||
image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478
|
||||
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
|
||||
image: linuxkit/xxxx:v0.6
|
||||
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
|
||||
plates-formes pour aller y lancer des instances de cette image !
|
||||
|
||||
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
|
||||
partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour
|
||||
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
|
||||
image: linuxkit/sshd:c4bc89cf0d66733c923ab9cb46198b599eb99320
|
||||
```
|
||||
</div>
|
||||
|
||||
Comme nous n'avons définis 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` :
|
||||
|
||||
<div lang="en-US">
|
||||
```yaml
|
||||
- path: root/.ssh/authorized_keys
|
||||
source: ~/.ssh/id_rsa.pub
|
||||
mode: "0600"
|
||||
```
|
||||
</div>
|
||||
|
||||
Ceci va aller chercher votre clef RSA sur votre machine, pour la placer dans
|
||||
|
||||
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 :
|
||||
[pkg/sshd/build.yml#L5](https://github.com/linuxkit/linuxkit/blob/master/pkg/sshd/build.yml#L5).
|
||||
|
||||
|
||||
## 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>
|
||||
|
||||
|
||||
## Exercice {-}
|
||||
|
||||
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
|
||||
faudra donc établir un lien `virtual ethernet` entre les deux conteneurs ; et
|
||||
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.
|
Loading…
Add table
Add a link
Reference in a new issue