docker-internals: tuto ready
This commit is contained in:
parent
5291bd365e
commit
de21be218a
@ -1,4 +1,4 @@
|
|||||||
SOURCES = tutorial.md clair.md oci.md manifest.md runc.md linuxkit.md vxlan.md rendu.md
|
SOURCES = tutorial.md clair.md oci.md registry.md runc.md linuxkit.md rendu.md
|
||||||
PANDOCOPTS = --latex-engine=xelatex \
|
PANDOCOPTS = --latex-engine=xelatex \
|
||||||
--standalone \
|
--standalone \
|
||||||
--normalize \
|
--normalize \
|
||||||
|
@ -3,10 +3,268 @@
|
|||||||
`linuxkit`
|
`linuxkit`
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Exemple avec une machine qui fait office de serveur DNS.
|
[`linuxkit`](https://github.com/linuxkit/linuxkit) est encore un autre projet
|
||||||
|
tirant parti des conteneurs. Il se positionne comme un système de construction
|
||||||
|
de machine. En effet, grâce à lui, nous allons pouvoir générer des systèmes
|
||||||
|
complets, *bootable* dans QEMU, VirtualBox, VMware ou même sur des machines
|
||||||
|
physiques, qu'il s'agisse de PC ou bien même de Raspberry Pi, ou même encore
|
||||||
|
des images pour les différents fournisseurs de cloud !
|
||||||
|
|
||||||
|
Bien entendu, au sein de ce système, tout est fait de conteneur ! Alors quand
|
||||||
|
il s'agit de donner une IP publique utilisable par l'ensemble des conteneurs,
|
||||||
|
il faut savoir jouer avec les *namespaces* pour arriver à ses fins !
|
||||||
|
|
||||||
|
Si vous vous rappelez du cours d'AdLin[^adlin] en début d'années, toutes les
|
||||||
|
VMs que vous avez utilisées reposaient entièrement sur `linuxkit`. En fait,
|
||||||
|
chaque conteneur représentait alors une machine différente : un conteneur
|
||||||
|
mattermost d'un côté, un conteneur `unbound` pour faire office de serveur DNS,
|
||||||
|
et les machines clientes étaient de simples conteneurs exécutant un client
|
||||||
|
dhcp.
|
||||||
|
|
||||||
|
[^adlin]: toutes les sources des machines sont dans ce dépôt :
|
||||||
|
<https://git.nemunai.re/?p=lectures/adlin.git;a=tree>
|
||||||
|
|
||||||
|
|
||||||
|
## 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">
|
||||||
|
```shell
|
||||||
|
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">
|
||||||
|
```shell
|
||||||
|
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>
|
||||||
|
|
||||||
Lien vers le fickit
|
|
||||||
|
|
||||||
## Exercice
|
## Exercice
|
||||||
|
|
||||||
Réaliser une recette `vault.yml` permettant de démarrer une instance.
|
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.
|
||||||
|
@ -73,3 +73,14 @@ des couches du système de fichiers, ainsi que l'historique de l'image.
|
|||||||
Dernière née de l'organisme, cette spécification fédère la notion de
|
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
|
*registre* : une API REST sur HTTP où l'on peut récupérer des images, mais
|
||||||
aussi en envoyer.
|
aussi en envoyer.
|
||||||
|
|
||||||
|
|
||||||
|
## 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 implémentation
|
||||||
|
? la réponse dans l'article :
|
||||||
|
<https://ops.tips/blog/run-docker-with-forked-runc/>
|
||||||
|
|
||||||
|
Et `containerd` dans l'histoire ?
|
||||||
|
<https://hackernoon.com/docker-containerd-standalone-runtimes-heres-what-you-should-know-b834ef155426>
|
||||||
|
@ -33,6 +33,8 @@ souhaite récupérer le contenu du dépôt[^quiddepot] `hello-world` :
|
|||||||
```shell
|
```shell
|
||||||
42sh$ curl "https://auth.docker.io/token"\
|
42sh$ curl "https://auth.docker.io/token"\
|
||||||
> "?service=registry.docker.io&scope=repository:library/hello-world:pull" | jq .
|
> "?service=registry.docker.io&scope=repository:library/hello-world:pull" | jq .
|
||||||
|
```
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"token": "lUWXBCZzg2TGNUdmMy...daVZxGTj0eh",
|
"token": "lUWXBCZzg2TGNUdmMy...daVZxGTj0eh",
|
||||||
"access_token": "eyJhbGciOiJSUzI1NiIsI...N5q469M3ZkL_HA",
|
"access_token": "eyJhbGciOiJSUzI1NiIsI...N5q469M3ZkL_HA",
|
||||||
@ -111,7 +113,8 @@ Enfin, armé du `digest` de notre couche, il ne nous reste plus qu'à la demande
|
|||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```shell
|
```shell
|
||||||
wget --header "Authorization: Bearer ${TOKEN}" "https://registry-1.docker.io/v2/library/hello-world/blobs/${LAYER_DIGEST}"
|
wget --header "Authorization: Bearer ${TOKEN}" \
|
||||||
|
"https://registry-1.docker.io/v2/library/hello-world/blobs/${LAYER_DIGEST}"
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -147,11 +150,14 @@ Réalisez un script pour automatiser l'ensemble de ces étapes :
|
|||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```shell
|
```shell
|
||||||
42sh$ cd $(mktemp)
|
42sh$ cd $(mktemp)
|
||||||
|
|
||||||
42sh$ ~/workspace/registry_play.sh library/hello
|
42sh$ ~/workspace/registry_play.sh library/hello
|
||||||
|
|
||||||
42sh$ find
|
42sh$ find
|
||||||
.
|
.
|
||||||
./rootfs
|
./rootfs
|
||||||
./rootfs/hello
|
./rootfs/hello
|
||||||
|
|
||||||
42sh# chroot rootfs /hello
|
42sh# chroot rootfs /hello
|
||||||
Hello from Docker!
|
Hello from Docker!
|
||||||
[...]
|
[...]
|
||||||
|
@ -31,14 +31,12 @@ cela dépendra de votre avancée dans le projet) :
|
|||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
login_x-TP5/
|
login_x-TP5/
|
||||||
|
login_x-TP5/docker-compose.yml
|
||||||
login_x-TP5/clair_config/config.yaml
|
login_x-TP5/clair_config/config.yaml
|
||||||
login_x-TP5/nginx:mainline.html
|
login_x-TP5/nginx:mainline.html
|
||||||
login_x-TP5/registry_play.sh
|
login_x-TP5/registry_play.sh
|
||||||
login_x-TP5/mydocker-export.sh
|
|
||||||
login_x-TP5/config.json
|
login_x-TP5/config.json
|
||||||
login_x-TP5/unboundkit.yml
|
|
||||||
login_x-TP5/vault.yml
|
login_x-TP5/vault.yml
|
||||||
|
login_x-TP5/pkg/...
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Utilisez la même tarball pour le rendu que pour la partie précédente.
|
|
||||||
|
@ -1,37 +1,131 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
https://ops.tips/blog/run-docker-with-forked-runc/
|
|
||||||
|
|
||||||
`runc`
|
`runc`
|
||||||
======
|
======
|
||||||
|
|
||||||
`runc` est le programme qui est responsable de la création effective du conteneur : c'est lui qui va mettre en place les *namespaces*, les *capabilities*, les points de montages ou volumes, ... Attention, son rôle reste limité à la mise en place de l'environnement conteneurisé, ce n'est pas lui qui télécharge l'image, ni fait l'assemblage des couches de système de fichiers, entre autres.
|
`runc` est le programme qui est responsable de la création effective du
|
||||||
|
conteneur : c'est lui qui va mettre en place les *namespaces*, les
|
||||||
|
*capabilities*, les points de montages ou volumes, ... Attention, son rôle
|
||||||
|
reste limité à la mise en place de l'environnement conteneurisé, ce n'est pas
|
||||||
|
lui qui télécharge l'image, ni fait l'assemblage des couches de système de
|
||||||
|
fichiers, entre autres.
|
||||||
|
|
||||||
Si vous n'avez pas eu le temps de terminer l'exercice précédent, vous pouvez utiliser `docker export | tar -C rootfs xv`.
|
Aujourd'hui, le lancement de conteneur est faite avec `runc`, mais il est
|
||||||
|
parfaitement possible d'utiliser n'importe quel autre programme à sa place, à
|
||||||
|
partir du moment où il expose la même interface à Docker et qu'il accepte les
|
||||||
|
*bundle* OCI.
|
||||||
|
|
||||||
On va essayer de lancer un shell `alpine` avec un volume dans notre home :)
|
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.
|
||||||
|
|
||||||
D'abord on extraie l'image avec le script précédent, puis on crée le fichier de conf qui va bien.
|
|
||||||
|
|
||||||
Aujourd'hui, la création de conteneur est faite avec `runc`, mais il est parfaitement possible d'utiliser n'importe quel autre programme, à la place de `runc`, à partir du moment où il expose la même interface à Docker et qu'il accepte les bundle OCI.
|
## Prérequis
|
||||||
|
|
||||||
https://github.com/opencontainers/runtime-spec/blob/master/config.md
|
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>. La 1.0.0-rc5 est Ok.
|
||||||
|
|
||||||
https://hackernoon.com/docker-containerd-standalone-runtimes-heres-what-you-should-know-b834ef155426
|
|
||||||
|
## Extraction du rootfs
|
||||||
|
|
||||||
|
À l'aide du script réalisé dans la partie précédentes, extrayons le rootfs
|
||||||
|
d'alpine : `library/alpine` dans le registre Docker.
|
||||||
|
|
||||||
|
Si vous n'avez pas eu le temps de terminer l'exercice précédent, vous pouvez
|
||||||
|
utiliser `docker image save alpine | tar xv -C rootfs`.
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
||||||
|
commande suivante, qui nous créera un modèle que nous adapterons un peu :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```shell
|
||||||
|
runc spec
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Pour savoir à quoi correspondent tous ces éléments, vous pouvez consulter :
|
||||||
|
<https://github.com/opencontainers/runtime-spec/blob/master/config.md>
|
||||||
|
|
||||||
|
|
||||||
|
## Test brut
|
||||||
|
|
||||||
|
Voici comment nous pouvons tester le fonctionnement de notre *bundle* :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```shell
|
||||||
|
42sh$ ls
|
||||||
|
rootfs/ config.json
|
||||||
|
|
||||||
|
42sh# runc run --bundle . virli1
|
||||||
|
/ # _
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Quelques informations sont disponibles, mais il ne faut pas s'attendre à
|
||||||
|
retrouver tout l'écosystème de `docker` ; ici il n'y a pas de gestion des
|
||||||
|
journaux, etc. :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```shell
|
||||||
|
42sh# runc list
|
||||||
|
ID PID STATUS BUNDLE CREATED OWNER
|
||||||
|
virli1 12345 running /tmp/work/runctest 2012-12-12T12:12:12.123456789Z root
|
||||||
|
|
||||||
|
42sh# runc state virli1
|
||||||
|
...
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## 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 :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```shell
|
||||||
|
42sh$ jq .mounts config.json
|
||||||
|
```
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"destination": "/proc",
|
||||||
|
"type": "proc",
|
||||||
|
"source": "proc"
|
||||||
|
},
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Pour avoir notre équivalent du `-v /home:/home` de `docker`, il va donc falloir
|
||||||
|
ajouter un élément à cette liste, demandant de *bind* :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"destination": "/home",
|
||||||
|
"type": "none",
|
||||||
|
"source": "/home",
|
||||||
|
"options": [
|
||||||
|
"bind",
|
||||||
|
"ro"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Exercice
|
## Exercice
|
||||||
|
|
||||||
Réaliser un `config.json` qui permette de lancer le conteneur `nemunaire/fic-admin`.
|
Serez-vous capable de continuer l'édition de votre `config.json` afin d'obtenir
|
||||||
|
les mêmes restrictions que votre projet de moulette ?
|
||||||
|
|
||||||
## Exercice
|
|
||||||
|
|
||||||
Serez-vous capable d'écrire un fichier `config.json` permettant d'obtenir le
|
|
||||||
même résultat que votre projet de moulette ?
|
|
||||||
|
|
||||||
* CGroups : 1GB RAM, 100 PID, ...
|
* CGroups : 1GB RAM, 100 PID, ...
|
||||||
* strict minimum de capabilities ;
|
* strict minimum de capabilities ;
|
||||||
* volume étudiant pour correction ;
|
* filtres `seccomp` ;
|
||||||
* carte réseau `veth` ;
|
* carte réseau `veth` ;
|
||||||
* ...
|
* ...
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
Mise en place
|
Mise en place
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
* `docker-compose`
|
||||||
|
* `venv` (Python3)
|
||||||
* `jq`
|
* `jq`
|
||||||
* `runc`
|
* `runc`
|
||||||
* `containerd`
|
* `containerd`
|
||||||
|
Loading…
Reference in New Issue
Block a user