diff --git a/tutorial/1/Makefile b/tutorial/1/Makefile index 06088f9..099227c 100644 --- a/tutorial/1/Makefile +++ b/tutorial/1/Makefile @@ -3,7 +3,7 @@ include ../pandoc-opts.mk SOURCES = tutorial.md \ ../docker-basis/discover.md ../docker-basis/installation.md ../docker-basis/what.md ../docker-basis/first.md ../docker-basis/cleaning.md ../docker-basis/ex-flask.md \ ../docker-basis/volumes.md \ - ../docker-basis/linking.md \ + ../docker-basis/linking.md ../docker-basis/linking-ex-fic.md ../docker-basis/linking-ex-help.md \ ../docker-advanced/what.md ../docker-advanced/setup.md ../docker-advanced/manual.md ../docker-advanced/compose.md \ ../docker-advanced/security.md \ rendu.md diff --git a/tutorial/1/tutorial.md b/tutorial/1/tutorial.md index b17167d..3badd7b 100644 --- a/tutorial/1/tutorial.md +++ b/tutorial/1/tutorial.md @@ -6,7 +6,7 @@ institute: EPITA date: Jeudi 16 septembre 2021 abstract: | Durant ce premier TP, nous allons apprendre à utiliser Docker, puis - nous apprendrons à déployer un groupe de conteneurs ! + nous apprendrons à déployer un groupe de conteneurs ! \vspace{1em} diff --git a/tutorial/2/rendu.md b/tutorial/2/rendu.md index c500eec..b51b1a8 100644 --- a/tutorial/2/rendu.md +++ b/tutorial/2/rendu.md @@ -3,7 +3,7 @@ Rendu ===== -Est attendu d'ici le TP suivant : +Est attendu d'ici le TP suivant : - le rendu des exercice de ce TP ; - vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/12). @@ -41,7 +41,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (vous pourriez avoir des fichiers -supplémentaires) : +supplémentaires) :
``` diff --git a/tutorial/2/tutorial.md b/tutorial/2/tutorial.md index 438e848..8ac7b33 100644 --- a/tutorial/2/tutorial.md +++ b/tutorial/2/tutorial.md @@ -7,7 +7,7 @@ date: Jeudi 23 septembre 2021 abstract: | Durant ce deuxième TP, nous allons voir comment créer nos propres images, et comment s'assurer qu'elles n'ont pas de vulnérabilités - connues ! + connues ! \vspace{1em} diff --git a/tutorial/3/capabilities.md b/tutorial/3/capabilities.md index bad7084..a1846bc 100644 --- a/tutorial/3/capabilities.md +++ b/tutorial/3/capabilities.md @@ -35,7 +35,7 @@ On trouve par exemple : Pour émettre un ping, il est nécessaire d'envoyer des paquets ICMP. À la différence des datagrammes UDP ou des segments TCP, il n'est pas forcément simple d'envoyer des paquets ICMP lorsque l'on est simple utilisateur, car -l'usage du protocole ICMP dans une socket est restreint : il faut soit être +l'usage du protocole ICMP dans une soket est restreint : il faut soit être super-utilisateur, soit que le noyau ait été configuré pour autoriser certains utilisateurs à envoyer des `ECHO_REQUEST`. @@ -64,7 +64,7 @@ se mettent à fournir par défaut une configuration qui permette de se passer de *capabilities* pour lancer `ping`.\ Si vous vous rendez compte que votre binaire `ping` est dans ce cas, testez -depuis un conteneur, par exemple : +depuis un conteneur, par exemple :
``` @@ -83,7 +83,7 @@ depuis un conteneur, par exemple :
Dans le conteneur le binaire `ping` est *setuid root*, vous pouvez faire des -tests en retirant le *setuid* : +tests en retirant le *setuid* :
``` @@ -94,7 +94,7 @@ tests en retirant le *setuid* : ```
-Puis en ajoutant la *capability* : +Puis en ajoutant la *capability* :
``` diff --git a/tutorial/3/cgroups-influx.md b/tutorial/3/cgroups-influx.md index 7ad614f..f5e17bf 100644 --- a/tutorial/3/cgroups-influx.md +++ b/tutorial/3/cgroups-influx.md @@ -1,12 +1,12 @@ ### Exercice (obligatoire pour les SRS -- optionnel pour les GISTRE) Poursuivons [notre script de monitoring](#script-monitoring) afin d'envoyer nos -résultats vers InfluxDB : nous l'appellerons `./telegraf.sh` +résultats vers InfluxDB : nous l'appellerons `./telegraf.sh`. #### Rappel d'InfluxDB\ Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de -l'installer sur notre machine) : +l'installer sur notre machine) :
```bash @@ -16,7 +16,7 @@ docker container run --name mytsdb -d -p 8086:8086 influxdb:1.8 Il nous faut ensuite créer une base de données pour y stocker nos métriques. Voici comment on s'était débrouillé précédemment pour interagir avec -InfluxDB : +InfluxDB :
```bash @@ -33,7 +33,7 @@ Vérifiez que la base de données `metrics` a bien été créée. #### Monitoring vers InfluxDB\ Maintenant, envoyons nos données vers la base - : + :
```bash @@ -43,7 +43,7 @@ curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \
Pour vérifier que les données ont bien été ajoutées, nous pouvons effectuer la -requête suivante dans notre client `influx` : +requête suivante dans notre client `influx` :
```sql @@ -54,15 +54,15 @@ SELECT * from "$my_cgroup_name"; #### Monitorer davantage de données\ -Liste non exhaustive de données à monitorer : +Liste non exhaustive de données à monitorer : -* Nombre d'IOs effectué ; -* nombre d'octets lus/écrits sur les disques ; -* temps de calcul utilisé (`userspace`, `system`, tout confondu) ; +* Nombre d'IOs effectué ; +* nobre d'octets lus/écrits sur les disques ; +* temps de calcul utilisé (`userspace`, `system`, tout confondu) ; * ... Tous les cgroups existants dans le dernier noyau publié ont leur documentation -accessible ici : +accessible ici : - v1 : - v2 : diff --git a/tutorial/3/cgroups.md b/tutorial/3/cgroups.md index 43f3c2a..3bd49e7 100644 --- a/tutorial/3/cgroups.md +++ b/tutorial/3/cgroups.md @@ -4,40 +4,40 @@ Les *cgroup*s ------------- Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques -sur des **groupes de processus** (voire même, des threads !) et de leur +sur des **groupes de processus** (voire même, des threads !) et de leur attribuer des propriétés. Il est par exemple possible de leur imposer des -limites d'utilisation de ressources ou d'altérer leur comportement : quantité +limites d'utilisation de ressources ou d'altérer leur comportement : quantité de RAM, temps CPU, bande passante, ... Apparue dès [Linux 2.6.24](https://kernelnewbies.org/Linux_2_6_24#Task_Control_Groups) -(en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes +(en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes (*subsystem*), chacun étant responsable d'un type de ressources -spécifique : +spécifique : - [`blkio` (`io` dans la v2) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html) - limites et statistiques de bande passante sur les disques ; -- `cpu` : cycles CPU minimum garantis ; + limites et statistiques de bande passante sur les disques ; +- `cpu` : cycles CPU minimum garantis ; - [`cpuacct` (inclus dans `cpu` dans la v2) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpuacct.html) - statistiques du temps CPU utilisé ; + statistiques du temps CPU utilisé ; - [`cpuset` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpusets.html) associe des tâches à un/des CPU particuliers (par exemple pour dédier un cœur du CPU à un programme, qui ne pourra alors utiliser que ce CPU et pas les - autres) ; + autres) ; - [`devices` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html) - règles de contrôle de création (`mknod`) et d'accès aux périphériques ; + règles de contrôle de création (`mknod`) et d'accès aux périphériques ; - [`freezer` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html) - pour suspendre et reprendre l'exécution d'un groupe de tâches ; -- [`hugetlb` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/hugetlb.html) statistiques et limitation de l'usage de la fonctionnalité `HugeTLB` (permettant d'obtenir des pages mémoires plus grande que 4 kB) ; -- [`memory` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html) statistiques et limitation d'usage de la mémoire vive et de la *swap* ; -- [`net_cls` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_cls.html) applique un `classid` à tous les paquets émis par les tâches du *cgroup*, pour filtrage par le pare-feu en sortie ; -- [`net_prio` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_prio.html) surcharge la valeur de l'option de priorité `SO_PRIORITY`, ordonant la file d'attente des paquets sortants ; -- [`pids` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html) statistiques et limitation du nombre de processus ; + pour suspendre et reprendre l'exécution d'un groupe de tâches ; +- [`hugetlb` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/hugetlb.html) statistiques et limitation de l'usage de la fonctionnalité `HugeTLB` (permettant d'obtenir des pages mémoires plus grande que 4 kB) ; +- [`memory` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html) statistiques et limitation d'usage de la mémoire vive et de la *swap* ; +- [`net_cls` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_cls.html) applique un `classid` à tous les paquets émis par les tâches du *cgroup*, pour filtrage par le pare-feu en sortie ; +- [`net_prio` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_prio.html) surcharge la valeur de l'option de priorité `SO_PRIORITY`, ordonant la file d'attente des paquets sortants ; +- [`pids` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html) statistiques et limitation du nombre de processus ; - ... Nous allons commencer par faire quelques tests avec le *cgroup* *freezer*, qui @@ -48,19 +48,19 @@ lorsqu'on le décide. ### Montage du *freezer* En fonction de la configuration de votre système, vous allez vous trouver dans -l'une de ces trois situations : +l'une de ces trois situations : - Votre dossier `/sys/fs/cgroup` contient à la fois des fichiers `cgroup.*` et - éventuellement des dossiers : vous avez une distribution moderne qui utilise + éventuellement des dossiers : vous avez une distribution moderne qui utilise la nouvelle version des `cgroup`s. - Votre dossier `/sys/fs/cgroup` contient d'autres dossiers au nom des - sous-systèmes que l'on a listé ci-dessus : il s'agit des `cgroup`s v1. + sous-systèmes que l'on a listé ci-dessus : il s'agit des `cgroup`s v1. - Votre dossier `/sys/fs/cgroup` est vide ou inexistant, vous pouvez choisir - d'utiliser la version de votre choix : + d'utiliser la version de votre choix : - Pour utiliser la v1 : + Pour utiliser la v1 :
```bash @@ -70,7 +70,7 @@ l'une de ces trois situations :
- Pour utiliser la v2 : + Pour utiliser la v2 :
```bash @@ -103,7 +103,7 @@ La première étape dans l'utilisation d'un *cgroup* est donc de créer un group Pour ce faire, il suffit de créer un nouveau dossier dans un groupe existant, par exemple la racine. -On commence par se rendre à la racine : +On commence par se rendre à la racine :
```bash @@ -112,7 +112,7 @@ cd /sys/fs/cgroup/ # v2 ```
-Puis on crée notre groupe : +Puis on crée notre groupe :
```bash @@ -134,7 +134,7 @@ version, vous allez devoir activer le ou les contrôleurs dont vous avez besoin sous-système que l'on voulait). Pour activer le contrôleur *memory* dans notre groupe `virli`, nous utilisons -la commande suivante : +la commande suivante :
```bash @@ -163,9 +163,9 @@ le fichier `cgroup.procs` de notre groupe. Ce fichier contient la liste des processus rattachés à notre *cgroup*. Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son -PID : `echo $$`. +PID : `echo $$`. -Pour ajouter une tâche à ce groupe, cela se passe de cette manière : +Pour ajouter une tâche à ce groupe, cela se passe de cette manière :
```bash @@ -190,7 +190,7 @@ adaptés. En affichant le contenu du dossier `virli`, nous pouvions constater que celui-ci contenait déjà un certain nombre de fichiers. Certains d'entre-eux sont en lecture seule et permettent de lire des statistiques instantanées sur -le groupe ; tandis que d'autres sont des propriétés que nous pouvons modifier. +le groupe ; tandis que d'autres sont des propriétés que nous pouvons modifier. Nous pouvons consulter l'état de gel du groupe en affichant le contenu du fichier\ @@ -204,7 +204,7 @@ consultez ### Changement d'état Faisons exécuter à notre interpréteur une commande pour voir effectivement -l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez : +l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez :
```bash @@ -213,7 +213,7 @@ for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done
Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de -calcul à notre shell et ses fils : +calcul à notre shell et ses fils :
```bash @@ -223,7 +223,7 @@ echo 1 > /sys/fs/cgroup/virli/cgroup.freeze # v2
À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre -l'exécution : +l'exécution :
```bash @@ -233,7 +233,7 @@ echo 0 > /sys/fs/cgroup/virli/cgroup.freeze # v2
-### Exercice : script de monitoring {- #script-monitoring} +### Exercice : script de monitoring {- #script-monitoring} À nous maintenant de concevoir un script qui va enregistrer vers une base de données des statistiques issues des *cgroup*s, tel `telegraf`. @@ -267,7 +267,7 @@ doit cependant être possible d'y trouver des statistiques intéressantes, dont la quantité de mémoire utilisée. Ici nous affichons au début le PID du processus, ce qui peut simplifier le débogage du script.\ -Il s'utilise de la manière suivante : +Il s'utilise de la manière suivante :
```bash @@ -275,7 +275,7 @@ Il s'utilise de la manière suivante : ```
-Où : +Où : - `group_name` correspond au nom du/des *cgroup*(s) à créer/rejoindre. - `prog [args [...]]` est la commande que l'on souhaite monitorer, à exécuter @@ -297,7 +297,7 @@ quantité de ressources mises à disposition à un groupe de processus. Pour définir une limite, nous allons écrire la valeur dans le fichier correspondant à une valeur limite, comme par exemple `memory.max_usage_in_bytes`/`memory.max`, qui limite le nombre d'octets que -notre groupe de processus va pouvoir allouer au maximum : +notre groupe de processus va pouvoir allouer au maximum :
``` @@ -330,7 +330,7 @@ limiteurs, n'hésitez pas à consulter la documentation associée à chaque *cgroup*. Mettez à jour votre script de monitoring pour prendre en compte les -limites que vous avez définies : +limites que vous avez définies :
``` @@ -352,5 +352,5 @@ limites que vous avez définies : ### Pour aller plus loin {-} Pour tout connaître en détails, [la série d'articles de Neil Brown sur les -Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet +Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet article sur la version 2](https://lwn.net/Articles/679786/). diff --git a/tutorial/3/chroot.md b/tutorial/3/chroot.md index a00a3a8..3ec27b8 100644 --- a/tutorial/3/chroot.md +++ b/tutorial/3/chroot.md @@ -1,4 +1,4 @@ -L'isolation ... à 1 € ? +L'isolation ... à 1 € ? ----------------------- Depuis les premières versions d'Unix, il est possible de changer le répertoire @@ -83,7 +83,7 @@ pacstrap newroot/
Dans les deux cas, nous nous retrouvons avec un dossier `newroot` contenant une -distribution complète minimale, dans laquelle nous pouvons entrer : +distribution complète minimale, dans laquelle nous pouvons entrer :
```bash @@ -100,9 +100,10 @@ sous forme de tarball : #### Gentoo\ + +
```bash -wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20210630T214504Z.tar.xz tar xpf stage3-amd64-*.tar.xz -C newroot/ ```
@@ -113,7 +114,7 @@ environnement qui tient dans 200 MB. ::::: Comme pour les autres distributions vues précédemment, nous pouvons entrer dans -notre nouvelle racine comme ceci : +notre nouvelle racine comme ceci :
```bash @@ -124,15 +125,16 @@ chroot newroot/ bash #### Alpine\ + +
```bash -wget https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz tar xpf alpine-minirootfs-*.tar.xz -C newroot/ ```
Alpine se contentant de Busybox pour son système de base, nous n'avons pas -`bash`, mais on peut tout de même lancer `ash` : +`bash`, mais on peut tout de même lancer `ash` :
```bash diff --git a/tutorial/3/intro.md b/tutorial/3/intro.md index cfafb77..5c3d08c 100644 --- a/tutorial/3/intro.md +++ b/tutorial/3/intro.md @@ -8,5 +8,5 @@ allons tâcher d'apprendre comment il fonctionne en nous penchant sur un certain nombre de fonctionnalités de Linux. Dans un premier temps, nous allons aborder la manière dont le noyau Linux -permet de contrôler les processus : que ce soit en collectant des informations +permet de contrôler les processus : que ce soit en collectant des informations sur eux ou en imposant certaines restrictions. diff --git a/tutorial/3/oom.md b/tutorial/3/oom.md index 30ffe54..576be9d 100644 --- a/tutorial/3/oom.md +++ b/tutorial/3/oom.md @@ -3,7 +3,7 @@ Gestion de la mémoire ===================== -Linux a une gestion de la mémoire bien particulière[^vm-overcommit] : par +Linux a une gestion de la mémoire bien particulière[^vm-overcommit] : par défaut, `malloc(3)` ne retournera jamais `NULL`. En se basant sur l'euristique qu'un bloc mémoire demandé ne sera pas utilisé directement et que de nombreux process ne feront pas un usage total des blocks qu'ils ont alloués, le noyau @@ -22,7 +22,7 @@ est-ce `init` qui est en train de gérer le lancement d'un nouveau daemon). On dit alors que le noyau est *Out-Of-Memory*. Pour se sortir d'une telle situation, et après avoir tenté de vider les caches, -il lance son arme ultime, pour retrouver au plus vite de la mémoire : +il lance son arme ultime pour retrouver au plus vite de la mémoire : l'*Out-Of-Memory killer*. @@ -39,7 +39,7 @@ jusqu'à ce que le système retrouve sa sérénité. [^oom-algo]: -## Esquiver l'OOM killer ? +## Esquiver l'OOM killer ? Au sein d'un *cgroup* *memory*, les fichiers `memory.oom_control` (v1) ou `memory.events` (v2) peuvent être utilisé afin de recevoir une notification du @@ -58,4 +58,4 @@ ce sujet. Continuons l'exercice précédent où nous avions [fixé les limites](#Fixer-des-limites) de mémoire que pouvez réserver les processus de notre groupe. Que se passe-t-il alors si `memhog` dépasse la quantité de -mémoire autorisée dans le `cgroup` ? +mémoire autorisée dans le `cgroup` ? diff --git a/tutorial/3/project-body.md b/tutorial/3/project-body.md deleted file mode 120000 index faf28f7..0000000 --- a/tutorial/3/project-body.md +++ /dev/null @@ -1 +0,0 @@ -../../subject/2/project-part1.md \ No newline at end of file diff --git a/tutorial/3/project-body.md b/tutorial/3/project-body.md new file mode 100644 index 0000000..1fc69ba --- /dev/null +++ b/tutorial/3/project-body.md @@ -0,0 +1,115 @@ +## Palier 1 : Restreindre l'environnement (2 points) {-} + +Après avoir mis en place les bases de votre programme, commencez par créer les +différentes hiérarchies (si vous avez un noyau récent, vous pouvez utiliser les +cgroups-v2) dont vous allez avoir besoin pour limiter l'utilisation de +ressources. + +Puis, mettez en place ces limites : + +* pas plus d'1 GB de mémoire utilisée ; +* 1 seul CPU au maximum ; +* 100 PIDs ; +* ... + +En bonus, vous pouvez gérer les cas où le noyau sur lequel s'exécute votre +moulinette ne possède pas tous ces *CGroup*s, au lieu de planter, ne rien faire +n'est pas forcément une mauvaise solution. + + +## Palier 2 : Réduire les `capabilities` (2 points) {-} + +Réduisez au maximum les *capabilities*, de telle sorte qu'il ne soit pas +possible de faire un ping dans l'environnement restreint : + +
+``` +42sh# ping 9.9.9.9 +PING 9.9.9.9 (9.9.9.9) 56(84) bytes of data. +64 bytes from 9.9.9.9: icmp_seq=1 ttl=56 time=3.93 ms +64 bytes from 9.9.9.9: icmp_seq=2 ttl=56 time=3.97 ms +^C +--- 9.9.9.9 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1002ms +rtt min/avg/max/mdev = 3.931/3.954/3.978/0.067 ms + +42sh# ./mymoulette /bin/bash + bash# curl http://www.linuxcontainers.org/ | md5sum + c7d68d1cb4737125a84cd69f55add202 + + bash# ping 9.9.9.9 + ping: icmp open socket: Permission denied +``` +
+ +**Astuces\ :** `prctl(2)`, `capabilities(7)`, `capget(2)`, `capset(2)`, ... + +Aidez-vous du visualisateur de *capabilities* de la partie 1.3 du TP, pour voir +si vous êtes sur la bonne voie. + +Si votre distribution vous permet d'utiliser `ping` sans privilège, utilisez à +la place n'importe quel binaire ayant besoin de *capabilities* pour vos tests, +par exemple `arping` (qui nécessite `CAP_NET_RAW`) ou `halt` (qui nécessite +`CAP_SYS_BOOT`) : + +
+``` +42sh# ./mymoulette /bin/bash + bash# arping 192.168.0.1 + arping: socket: Permission denied + + bash# halt -f + halt: (null): Operation not permitted +``` +
+ + +## Palier bonus : Utilisable par un utilisateur (2 points) {-} + +Jouez avec les attributs étendus pour qu'un utilisateur non-privilégié puisse +exécuter votre moulinette. Ajoutez la/les commande(s) à votre `Makefile` ou +script d'installation. + + +## Création d'un environnement d'exécution minimal {-} + +Plutôt que d'utiliser votre système hôte au complet, avec tous ses programmes +et toutes ses bibliothèques, il faudrait utiliser un système contenant le +strict minimum. Recréez un environnement minimaliste, comme on a pu en voir +dans la partie sur les `chroot`. + +**Ne mettez pas cet environnement dans votre tarball de rendu, il vous + sera seulement utile pour faire des tests.** + + +## Palier 3 : Isolation du pauvre (1 point) {-} + +Nous n'avons pas encore vu de meilleure méthode pour mieux isoler +l'environnement que de faire un `chroot`, ajoutez à votre programme cette +isolation rudimentaire. Et rendez-vous au prochain cours pour avoir une +meilleure isolation ! + +
+``` +42sh$ which firefox +/usr/bin/firefox +42sh# ./mymoulette ./newrootfs/ /bin/bash + bash# which firefox + which: no firefox in (/usr/bin:/usr/local/bin:/bin:/opt/bin) +``` +
+ + +## Palier 4 : seccomp (2 points) {-} + +Filtrez les appels système de telle sorte qu'aucun programme exécuté dans +votre bac à sable ne puisse plus lancer les appels systèmes suivants : + +* `nfsservctl(2)` ; +* `personality(2)` ; +* `pivot_root(2)` ; +* ... + +N'hésitez pas à en utiliser d'autres pour vos tests ;) + +**Astuces\ :** `seccomp(2)`, `seccomp_init(3)`, `seccomp_load(3)`, ... diff --git a/tutorial/3/project-intro.md b/tutorial/3/project-intro.md index 1d46c98..ded052c 100644 --- a/tutorial/3/project-intro.md +++ b/tutorial/3/project-intro.md @@ -6,7 +6,7 @@ Projet et rendu ## Sujet Vous allez commencer aujourd'hui un projet qui s'étendra au prochain TP et qui -consistera à réaliser la partie d'isolation de la moulinette des ACUs ! +consistera à réaliser la partie d'isolation de la moulinette des ACUs ! Cette semaine, il faudra faire en sorte de restreindre un groupe de processus pour qu'il ne puisse pas faire de déni de service sur notre machine. @@ -14,11 +14,11 @@ pour qu'il ne puisse pas faire de déni de service sur notre machine. Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien utiliser du C, du C++, du Python, etc. -L'usage de bibliothèques **non relatives** au projet est autorisé : le but de +L'usage de bibliothèques **non relatives** au projet est autorisé : le but de ce sujet est d'évaluer votre compréhension et votre utilisation de la tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette -plomberie, n'hésitez pas à l'utiliser ! +plomberie, n'hésitez pas à l'utiliser ! Gardez en tête que ce projet sera à continuer au prochain TP, où il sera principalement question de faire des appels systèmes. diff --git a/tutorial/3/project-rendu.md b/tutorial/3/project-rendu.md index 175eab2..d59d3d4 100644 --- a/tutorial/3/project-rendu.md +++ b/tutorial/3/project-rendu.md @@ -3,7 +3,7 @@ Rendu ===== -Est attendu d'ici le TP suivant : +Est attendu d'ici le TP suivant : - le rendu des exercice de ce TP ; - vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/14). @@ -40,7 +40,7 @@ placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (adaptez les extensions et les éventuels fichiers supplémentaires associés au langage que vous aurez choisi -pour chaque exercice) : +pour chaque exercice) :
``` diff --git a/tutorial/3/pseudofs.md b/tutorial/3/pseudofs.md index b235fb0..4a4bf2b 100644 --- a/tutorial/3/pseudofs.md +++ b/tutorial/3/pseudofs.md @@ -41,13 +41,13 @@ apporter des modifications. Linux emploie de nombreux systèmes de fichiers virtuels : - `/proc` : contient, principalement, la liste des processus (`top` et ses - dérivés se contentent de lire les fichiers de ce point de montage) ; -- `/proc/sys` : contient la configuration du noyau ; + dérivés se contentent de lire les fichiers de ce point de montage) ; +- `/proc/sys` : contient la configuration du noyau ; - `/sys` : contient des informations à propos du matériel (utilisées notamment par `udev` pour peupler `/dev`) et des périphériques (taille des tampons, - clignottement des DELs, ...) ; + clignottement des DELs, ...) ; - `/sys/firmware/efi/efivars` : pour accéder et modifier les variables de - l'UEFI ; + l'UEFI ; - ... Tous ces systèmes de fichiers sont généralement exclusivement stockés en @@ -130,7 +130,7 @@ uts:[4026531838] Explorons le pseudo système de fichiers `/sys` pour écrire un script qui va, en fonction de ce que vous avez de disponible : -* afficher des statistiques sur notre batterie ; +* afficher des statistiques sur notre batterie ; * afficher des statistiques la fréquence du CPU. ##### `batinfo.sh`\ @@ -194,7 +194,7 @@ Maintenant que vous savez lire des informations dans `/sys`, tentons d'aller modifier le comportement de notre système. Au choix, réalisez l'un des scripts suivants, en fonction du matériel dont vous disposez : -* inverser l'état des diodes de notre clavier ; +* inverser l'état des diodes de notre clavier ; * mettre en veille votre machine, en ayant programmé une heure de réveil. ##### `rev_kdb_leds.sh`\ @@ -203,7 +203,7 @@ Si vous avez : * numlock On, * capslock Off, -* scrolllock Off ; +* scrolllock Off ; Après avoir exécuté le script, nous devrions avoir : @@ -242,7 +242,8 @@ Voici un exemple d'utilisation :
Vous aurez besoin de définir une alarme au niveau de votre RTC, via le -fichier : `/sys/class/rtc/rtcX/wakealarm`. +fichier :\ +`/sys/class/rtc/rtcX/wakealarm` ::::: {.warning} Attention au fuseau horaire utilisé par votre RTC, si votre système principal diff --git a/tutorial/3/seccomp.md b/tutorial/3/seccomp.md index dc56a0b..09661d7 100644 --- a/tutorial/3/seccomp.md +++ b/tutorial/3/seccomp.md @@ -12,13 +12,13 @@ particulier peut être renvoyé au programme. Depuis la version 3.17 du noyau, l'appel système `seccomp(2)` permet de faire entrer le processus courant dans ce mode. En effet, c'est le processus lui-même qui déclare au noyau qu'il peut désormais se contenter d'une liste réduite -d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou +d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou AppArmor, qui encapsulent les programmes pour toute la durée de leur exécution. *Seccomp* est particulièrement utile lorsqu'un processus a terminé son initialisation (ne dépendant en général pas de données sujettes à l'exploitation de vulnérabilité) et doit commencer à entrer dans des portions -de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de +de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de rendus des navigateurs Firefox et Chrome. @@ -39,7 +39,7 @@ des appels système `read(2)`, `write(2)` (sur les descripteurs de fichier déj ouvert), `_exit(2)` et `sigreturn(2)`. Historiquement, avant la création de l'appel système `seccomp(2)`, on activait -ce mode via : +ce mode via :
```c @@ -63,7 +63,7 @@ auquel est appliqué un filtre `seccomp`, héritent également de ce filtre. La construction de ce filtre est faite de manière programmatique, via des règles BPF (`Berkeley Packet Filter`). On passe ensuite ce filtre BPF en -argument de l'appel système : +argument de l'appel système :
```c @@ -79,7 +79,7 @@ seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog); ### Exercice {-} -Écrivez un programme filtrant un appel système, à l'aide de `seccomp` : +Écrivez un programme filtrant un appel système, à l'aide de `seccomp` :
``` diff --git a/tutorial/4/cmpns.md b/tutorial/4/cmpns.md index b7b7692..53b0734 100644 --- a/tutorial/4/cmpns.md +++ b/tutorial/4/cmpns.md @@ -1,6 +1,6 @@ \newpage -### Exercice : comparaison de *namespace* -- `cmpns.sh` +### Exercice : comparaison de *namespace* -- `cmpns.sh` Les *namespaces* d'un programme sont exposés sous forme de liens symboliques dans le répertoire `/proc//ns/`. @@ -46,9 +46,9 @@ que l'on cherche à comparer. Ici, `self` fait référence au processus actuellement exécuté (comme il existe un dossier `/proc/self/`, vous n'avez pas besoin de gérer de cas particulier -pour ça !). +pour ça !). -Et pourquoi pas : +Et pourquoi pas :
``` diff --git a/tutorial/4/docker-exec.md b/tutorial/4/docker-exec.md index 25a697a..c188e5a 100644 --- a/tutorial/4/docker-exec.md +++ b/tutorial/4/docker-exec.md @@ -1,19 +1,19 @@ \newpage -Exercice : `docker exec` +Exercice : `docker exec` ------------------------ Après voir lu la partie concernant les *namespaces*, vous avez dû comprendre qu'un `docker exec`, n'était donc rien de plus qu'un `nsenter(1)`. -Réécrivons, en quelques lignes, la commande `docker exec` ! +Réécrivons, en quelques lignes, la commande `docker exec` ! -Pour savoir si vous avez réussi, comparez les sorties des commandes : +Pour savoir si vous avez réussi, comparez les sorties des commandes : -- `ip address` ; -- `hostname` ; -- `mount` ; -- `pa -aux` ; +- `ip address` ; +- `hostname` ; +- `mount` ; +- `ps -aux` ; - ... @@ -27,11 +27,11 @@ d63ceae863956f8312aca60b7a57fbcc1fdf679ae4c90c5d9455405005d4980a 234269 42sh# ./mydocker_exec mywebserver ip address -1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group def link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever -13: eth0@if14: mtu 1500 qdisc noqueue state UP group default +13: eth0@if14: mtu 1500 state UP group def link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.1/16 scope global eth0 valid_lft forever preferred_lft forever diff --git a/tutorial/4/howto.md b/tutorial/4/howto.md index 2ce248c..f084d4a 100644 --- a/tutorial/4/howto.md +++ b/tutorial/4/howto.md @@ -33,7 +33,7 @@ En fonction des options qui lui sont passées, `unshare(1)` va créer le/les nouveaux *namespaces* et placer le processus dedans. Par exemple, nous pouvons modifier sans crainte le nom de notre machine, si -nous sommes passés dans un autre *namespace* `UTS` : +nous sommes passés dans un autre *namespace* `UTS` :
``` @@ -64,7 +64,7 @@ Ce *syscall*, propre à Linux, crée habituellement un nouveau processus (mais aussi des threads) enfant de notre processus courant, comme `fork(2)` (qui lui est un appel système POSIX) mais prend en plus de nombreux paramètres. L'isolement ou non du processus se fait en fonction des *flags* qui -sont passés : +sont passés : * `CLONE_NEWNS`, * `CLONE_NEWUTS`, @@ -83,7 +83,7 @@ que nous verrons plus tard. Pour créer un nouveau processus qui sera à la fois dans un nouvel espace de noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code C -semblable à : +semblable à :
```c @@ -118,7 +118,7 @@ dans un nouvel espace de noms. Dans ce cas, on utilisera l'appel système ::::: {.warning} Le comportement de `unshare(2)` (ou `unshare(3)`) avec les *namespace*s *PID* -et *Time* n'est pas celui que l'on peut attendre ! +et *Time* n'est pas celui que l'on peut attendre ! En effet, après avoir appelé `unshare`, le processus reste tout de même dans son *namespace* *Time* ou *PID* d'origine, seuls ses enfants (après un appel à diff --git a/tutorial/4/intro.md b/tutorial/4/intro.md index 06d23e6..a65ff61 100644 --- a/tutorial/4/intro.md +++ b/tutorial/4/intro.md @@ -22,12 +22,12 @@ Les espaces de noms du noyau, que l'on appelle *namespaces*, permettent de dupliquer certaines structures, habituellement considérées uniques pour le noyau, dans le but de les isoler d'un groupe de processus à un autre. -On en dénombre huit (le dernier ayant été ajouté dans Linux 5.6) : `cgroup`, +On en dénombre huit (le dernier ayant été ajouté dans Linux 5.6) : `cgroup`, `IPC`, `network`, `mount`, `PID`, `time`, `user` et `UTS`. La notion d'espace de noms est relativement nouvelle et a été intégrée progressivement au sein du noyau Linux. Aussi, toutes les structures ne sont -pas encore *containerisables* : le document fondateur[^NSDOC] parle ainsi +pas encore *containerisables* : le document fondateur[^NSDOC] parle ainsi d'isoler les journaux d'événements ou encore les modules de sécurité (LSM, tels que AppArmor, SELinux, Yama, ...). @@ -74,12 +74,12 @@ Cet espace de noms isole la liste des processus et virtualise leurs numéros. Une fois dans un espace, le processus ne voit que le sous-arbre de processus également attachés à son espace. Il s'agit d'un sous-ensemble de l'arbre global -de PID : les processus de tous les PID *namespaces* apparaissent donc dans +de PID : les processus de tous les PID *namespaces* apparaissent donc dans l'arbre initial. Pour chaque nouvel espace de noms de processus, une nouvelle numérotation est initiée. Ainsi, le premier processus de cet espace porte le numéro 1 et aura -les mêmes propriétés que le processus `init` usuel\ ; entre autres, si un +les mêmes propriétés que le processus `init` usuel\ ; entre autres, si un processus est rendu orphelin dans ce *namespace*, il devient un fils de ce processus, et non un fils de l'`init` de l'arbre global. @@ -89,7 +89,7 @@ processus, et non un fils de l'`init` de l'arbre global. Depuis Linux 2.6.29. Cet espace de noms fournit une isolation pour toutes les ressources associées -aux réseaux : les interfaces, les piles protocolaires IPv4 et IPv6, les tables +aux réseaux : les interfaces, les piles protocolaires IPv4 et IPv6, les tables de routage, règles pare-feu, ports numérotés, etc. Une interface réseau (`eth0`, `wlan0`, ...) ne peut se trouver que dans un seul @@ -126,7 +126,7 @@ correspond en fait à un sous-groupe de l'arborescence globale. Ainsi, un processus dans un *CGroup* *namespace* ne peut pas voir le contenu des sous-groupes parents (pouvant laisser fuiter des informations sur le reste du système). Cela peut également permettre de faciliter la migration de -processus (d'un système à un autre) : l'arborescence des *cgroups* n'a alors +processus (d'un système à un autre) : l'arborescence des *cgroups* n'a alors plus d'importance car le processus ne voit que son groupe. diff --git a/tutorial/4/lifetime.md b/tutorial/4/lifetime.md index 3726c92..b8fd50e 100644 --- a/tutorial/4/lifetime.md +++ b/tutorial/4/lifetime.md @@ -11,7 +11,7 @@ de processus qui l'utilisent. C'est-à-dire que, la plupart du temps, le termine. Lorsque l'on a besoin de référencer un *namespace* (par exemple pour le faire -persister après le dernier processus), on peut utiliser un `mount bind` : +persister après le dernier processus), on peut utiliser un `mount bind` :
```bash @@ -29,7 +29,7 @@ obtenir un descripteur de fichier valide vers le *namespace* (pour passer à ::::: {.question} -#### Faire persister un *namespace* ? {-} +#### Faire persister un *namespace* ? {-} \ Il n'est pas possible de faire persister un espace de noms d'un reboot à diff --git a/tutorial/4/mountns.md b/tutorial/4/mountns.md index 07e4c8e..e131b02 100644 --- a/tutorial/4/mountns.md +++ b/tutorial/4/mountns.md @@ -6,7 +6,7 @@ Le *namespace* `mount` L'espace de noms `mount` permet d'isoler la vision du système de fichiers qu'ont un processus et ses fils. -Peut-être que l'on peut trouver avec ça, un moyen de faire un `chroot` plus sûr ? +Peut-être que l'on peut trouver avec ça, un moyen de faire un `chroot` plus sûr ? ::::: {.warning} Attention il convient de prendre garde aux types de liaison existant entre vos @@ -33,7 +33,7 @@ Nous allons essayer de changer la racine de notre système de fichier. À la différence d'un `chroot(2)`, changer de racine est quelque chose d'un peu plus sportif car il s'agit de ne plus avoir aucune trace de l'ancienne racine. Au moins ici, il ne sera certainement pas possible de revenir en arrière dans -l'arborescence\ ! +l'arborescence ! Pour l'instant, votre système utilise sans doute la partition d'un disque physique comme racine de son système de fichier. Le changement de racine, va @@ -52,7 +52,7 @@ la racine d'un point de montage, comme l'explique `pivot_root(2)`. En effet, il serait encore possible hypothétiquement de remonter dans l'arborescence si l'on ne se trouvait pas à la racine d'une partition au moment du basculement. -Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` : +Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` :
```bash @@ -61,32 +61,31 @@ Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` ```
-Placez ensuite dans cette nouvelle racine le système de votre choix (cf. le TP -précédent pour les différentes méthodes et liens). +Placez ensuite dans cette nouvelle racine le système de votre choix. -### Exercice : Changer de racine -- `myswitch_root.sh` +### Exercice : Changer de racine -- `myswitch_root.sh` -Voici les grandes étapes du changement de racine : +Voici les grandes étapes du changement de racine : -1. S'isoler dans les *namespaces* adéquats ; +1. S'isoler dans les *namespaces* adéquats ; 2. Démonter ou déplacer toutes les partitions de l'ancienne racine vers la - nouvelle racine ; -3. `pivot_root` ! + nouvelle racine ; +3. `pivot_root` ! #### S'isoler\ Notre but étant de démonter toutes les partitions superflues, nous allons -devoir nous isoler sur : +devoir nous isoler sur : -* les points de montages, ça semble évident ; -* les PIDs : car on ne pourra pas démonter une partition en cours +* les points de montages, ça semble évident ; +* les PIDs : car on ne pourra pas démonter une partition en cours d'utilisation. S'il n'y a pas de processus, il n'y a personne pour nous - empêcher de démonter une partition ! + empêcher de démonter une partition ! * les autres *namespaces* ne sont pas forcément nécessaires. -Isolons-nous : +Isolons-nous :
```bash @@ -97,12 +96,12 @@ Isolons-nous : #### Dissocier la propagation des démontages\ -Attention ! avant de pouvoir commencer à démonter les partitions, il faut +Attention ! avant de pouvoir commencer à démonter les partitions, il faut s'assurer que les démontages ne se propagent pas via une politique de *shared mount*. Commençons donc par étiqueter tous nos points de montage (de ce *namespace*), -comme esclaves : +comme esclaves :
```bash @@ -111,15 +110,15 @@ comme esclaves :
-#### Démonter tout !\ +#### Démonter tout !\ À vous maintenant de démonter vos points d'attache. Il ne devrait vous rester -après cette étape que : `/`, `/dev`, `/sys`, `/proc`, `/run` et leurs fils. +après cette étape que : `/`, `/dev`, `/sys`, `/proc`, `/run` et leurs fils. -#### Switch !\ +#### Switch !\ -À ce stade, dans votre console, vous avez plusieurs solutions : utiliser +À ce stade, dans votre console, vous avez plusieurs solutions : utiliser `switch_root(8)` ou `pivot_root(8)`. La première abstrait plus de choses que la seconde. @@ -136,7 +135,7 @@ Cette commande, plus proche du fonctionnement de l'appel système `pivot_root(2)`, requiert de notre part que nous ayons préalablement déplacé les partitions systèmes à leur place dans la nouvelle racine. -L'appel de la commande sert à intervertir les deux racines ; elle prend en argument : +L'appel de la commande sert à intervertir les deux racines ; elle prend en argument : * le chemin de la nouvelle racine, * le chemin dans la nouvelle racine où placer l'ancienne. @@ -144,7 +143,7 @@ L'appel de la commande sert à intervertir les deux racines ; elle prend en argu Une fois le pivot effectué, on peut démonter l'ancienne racine. Pour lancer la première commande dans la nouvelle racine, on passe généralement -par : +par :
```bash diff --git a/tutorial/4/namespaces_more.md b/tutorial/4/namespaces_more.md index 93817a2..bc52f51 100644 --- a/tutorial/4/namespaces_more.md +++ b/tutorial/4/namespaces_more.md @@ -4,7 +4,7 @@ Je vous recommande la lecture du *man* `namespaces(7)` introduisant et énumérant les *namespaces*. Pour tout connaître en détails, [la série d'articles de Michael Kerrisk sur les -*namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il faut +*namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il faut ajouter [l'article sur le plus récent `cgroup` *namespace*](https://lwn.net/Articles/621006/) et [le petit dernier sur le *namespace* `time`](https://lwn.net/Articles/766089/). diff --git a/tutorial/4/networkns.md b/tutorial/4/networkns.md index 59871c7..1a20578 100644 --- a/tutorial/4/networkns.md +++ b/tutorial/4/networkns.md @@ -6,11 +6,11 @@ Le *namespace* `network` {#net-ns} ### Introduction L'espace de noms `network`, comme son nom l'indique permet de virtualiser tout -ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les +ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les règles de filtrage, etc. En entrant dans un nouvel espace de noms `network`, on se retrouve dans un -environnement qui n'a plus qu'une interface de *loopback* : +environnement qui n'a plus qu'une interface de *loopback* :
``` @@ -25,7 +25,7 @@ environnement principal, il s'agit bien de deux interfaces isolées l'une de l'autre. Qui dit nouvelle pile réseau, dit également que les ports qui sont assignés -dans l'espace principal, ne le sont plus dans le conteneur : il est donc +dans l'espace principal, ne le sont plus dans le conteneur : il est donc possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un autre espace de noms. @@ -33,9 +33,9 @@ autre espace de noms. ### Premiers pas avec `ip netns` La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le -*namespace* `network` : `ip netns`. +*namespace* `network` : `ip netns`. -Nous pouvons tout d'abord créer un nouvel espace de noms : +Nous pouvons tout d'abord créer un nouvel espace de noms :
```bash @@ -45,17 +45,17 @@ Nous pouvons tout d'abord créer un nouvel espace de noms : La technique utilisée ici pour avoir des *namespaces* nommés est la même que celle que nous avons vue dans -[la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind` +[la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind` dans le dossier `/var/run/netns/`. Cela permet de faire persister le namespace malgré le fait que plus aucun processus ne s'y exécute. Maintenant que notre *namespace* est créé, nous pouvons regarder s'il contient -des interfaces : +des interfaces :
``` 42sh# ip netns exec virli ip link -1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1 +1: lo: mut 65536 qdisc noop state DOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 ```
@@ -64,7 +64,7 @@ Cette commande ne nous montre que l'interface de *loopback*, car nous n'avons pour l'instant pas encore attaché la moindre interface. D'ailleurs, cette interface est rapportée comme étant désactivée, activons-là -via la commande : +via la commande :
```bash @@ -92,7 +92,7 @@ interface physique par conteneur, d'autant plus si l'on a plusieurs centaines de conteneurs à gérer. Une technique couramment employée consiste à créer une interface virtuelle de -type `veth` : +type `veth` :
``` @@ -100,16 +100,16 @@ type `veth` : ```
-Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui +Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui entre d'un côté sort de l'autre et inversement. La commande précédente a donc -créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont +créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont donc reçus par `veth1` et les paquets envoyés à `veth1` sont reçus par `veth0`. Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si l'on place l'une des deux extrémités dans un autre *namespace* `network`, il devient alors possible de réaliser un échange de paquets entre les deux. -Pour déplacer `veth1` dans notre *namespace* `virli` : +Pour déplacer `veth1` dans notre *namespace* `virli` :
```bash @@ -117,7 +117,7 @@ Pour déplacer `veth1` dans notre *namespace* `virli` : ```
-Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces : +Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
```bash @@ -126,7 +126,7 @@ Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces : ```
-Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité : +Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité : [^linkdown]: Il peut être nécessaire d'activer chaque lien, via `ip link set vethX up`. @@ -140,7 +140,7 @@ Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
Il ne reste donc pas grand chose à faire pour fournir Internet à notre -conteneur : via un peu de NAT ou grâce à un pont Ethernet. +conteneur : via un peu de NAT ou grâce à un pont Ethernet. ### Les autres types d'interfaces @@ -171,9 +171,9 @@ derrière notre machine. Lorsque l'on n'a pas assez de carte ethernet et que le switch ne supporte pas -les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le +les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le MACVLAN. S'il est activé dans votre noyau, vous allez avoir le choix entre l'un -des quatre modes : *private*, VEPA, *bridge* ou *passthru*. +des quatre modes : *private*, VEPA, *bridge* ou *passthru*. Quel que soit le mode choisi, les paquets en provenance d'autres machines et à destination d'un MAC seront délivrés à l'interface possédant la MAC. Les @@ -189,7 +189,7 @@ la machine, c'est à l'équipement réseau derrière la machine de rerouter le paquet vers la machine émettrice (par exemple un switch [802.1Qbg](http://www.ieee802.org/1/pages/802.1bg.html)). -Pour construire une nouvelle interface de ce type : +Pour construire une nouvelle interface de ce type :
``` @@ -217,11 +217,11 @@ conteneur de la même machine. ##### *Bridge* À l'inverse des modes *VEPA* et *private*, les paquets sont routés selon leur -adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à -l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est +adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à +l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est envoyé sur l'interface de sortie. -Pour construire une nouvelle interface de ce type : +Pour construire une nouvelle interface de ce type :
``` @@ -233,9 +233,9 @@ Pour construire une nouvelle interface de ce type : ### Aller plus loin {-} Pour approfondir les différentes techniques de routage, je vous -recommande cet article : +recommande cet article : [Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking). -Appliqué à Docker, vous apprécierez cet article : [Understanding Docker +Appliqué à Docker, vous apprécierez cet article : [Understanding Docker Networking Drivers and their use cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/). diff --git a/tutorial/4/pidns.md b/tutorial/4/pidns.md index 8210bce..ffad3f0 100644 --- a/tutorial/4/pidns.md +++ b/tutorial/4/pidns.md @@ -18,9 +18,9 @@ pas de PID en cours de route, puisqu'il dépend du *namespace* dans lequel il se trouve. -### Isolons ! +### Isolons ! -Première étape s'isoler : +Première étape s'isoler :
```bash @@ -45,9 +45,9 @@ notre système initial. Pour s'en sortir, il est nécessaire de s'isoler dans un *namespace* `mount` séparé. -#### Double isolation : ajout du *namespace* `mount`\ +#### Double isolation : ajout du *namespace* `mount`\ -Voici la nouvelle ligne de commande que l'on va utiliser : +Voici la nouvelle ligne de commande que l'on va utiliser :
```bash @@ -65,11 +65,11 @@ Cette fois, `top` et `ps` nous rapportent bien que l'on est seul dans notre ### Arborescence à l'extérieur du *namespace* Lors de notre première tentative de `top`, lorsque `/proc` était encore monté -sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans +sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans son nouveau *namespace*) était présent dans l'arborescence de l'espace initial -avec un PID dans la continuité des autres processus, étonnant ! +avec un PID dans la continuité des autres processus, étonnant ! -En fait, l'isolation consiste en une virtualisation des numéros du processus : +En fait, l'isolation consiste en une virtualisation des numéros du processus : la plupart des processus du système initial ne sont pas accessibles, et ceux qui font partie de l'espace de noms créé disposent d'une nouvelle numérotation. Et c'est cette nouvelle numérotation qui est montrée au processus. @@ -85,12 +85,12 @@ Au sein d'un *namespace*, le processus au PID 1 est considéré comme le programme `init`, les mêmes propriétés s'appliquent donc. Si un processus est orphelin, il est donc affiché comme étant fils du PID 1 -dans son *namespace*[^PR_SET_CHILD_SUBREAPER] ; il n'est pas sorti de l'espace +dans son *namespace*[^PR_SET_CHILD_SUBREAPER] ; il n'est pas sorti de l'espace de noms. [^PR_SET_CHILD_SUBREAPER]: en réalité, ce comportement est lié à la propriété `PR_SET_CHILD_SUBREAPER`, qui peut être définie pour n'importe quel processus - de l'arborescence. Le processus au PID 1 hérite forcément de cette propriété\ ; + de l'arborescence. Le processus au PID 1 hérite forcément de cette propriété\ ; il va donc récupérer tous les orphelins, si aucun de leurs parents n'ont la propriété définie. @@ -104,4 +104,4 @@ l'intérieur pour conserver un comportement cohérent. ### Aller plus loin {-} N'hésitez pas à jeter un œil à la page de manuel consacrée à cet espace de -noms : `pid_namespaces(7)`. +noms : `pid_namespaces(7)`. diff --git a/tutorial/4/project-intro.md b/tutorial/4/project-intro.md index e4a3175..91105a3 100644 --- a/tutorial/4/project-intro.md +++ b/tutorial/4/project-intro.md @@ -9,7 +9,7 @@ Projet et rendu notation de ce cours.** Vous allez continuer aujourd'hui le projet qui s'étendra depuis le TP précédent -et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs ! +et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs ! Cette semaine, il faudra faire en sorte de restreindre un groupe de processus pour qu'il s'exécute indépendemment de votre système. @@ -17,8 +17,8 @@ pour qu'il s'exécute indépendemment de votre système. Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien utiliser du C, du C++, du Python, du shell, etc. -L'usage de bibliothèques **non relatives** au projet est autorisé : le but de +L'usage de bibliothèques **non relatives** au projet est autorisé : le but de ce sujet est d'évaluer votre compréhension et votre utilisation de la tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette -plomberie, n'hésitez pas à l'utiliser ! +plomberie, n'hésitez pas à l'utiliser ! diff --git a/tutorial/4/rendu.md b/tutorial/4/rendu.md index ea3286f..1f8f270 100644 --- a/tutorial/4/rendu.md +++ b/tutorial/4/rendu.md @@ -3,9 +3,9 @@ Projet et rendu =============== -Est attendu d'ici le TP suivant : +Est attendu d'ici le TP suivant : -- le rendu des exercice de ce TP ; +- le rendu des exercice de ce TP ; - vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/15). Pour les GISTRE (et en bonus pour les SRS), [un @@ -40,7 +40,7 @@ RAR, ...). Voici une arborescence type (adaptez les extensions et les éventuels fichiers supplémentaires associés au langage que vous aurez choisi -pour chaque exercice) : +pour chaque exercice) :
``` diff --git a/tutorial/4/setns-samples.md b/tutorial/4/setns-samples.md index 9d1e061..f3dbf76 100644 --- a/tutorial/4/setns-samples.md +++ b/tutorial/4/setns-samples.md @@ -1,6 +1,6 @@ #### Exemple C\ -Voici un exemple de code C utilisant `setns(2)` : +Voici un exemple de code C utilisant `setns(2)` :
```c @@ -38,7 +38,7 @@ main(int argc, char *argv[]) #### Exemple shell\ -Dans un shell, on utilisera la commande `nsenter(1)` : +Dans un shell, on utilisera la commande `nsenter(1)` :
```bash diff --git a/tutorial/4/setns.md b/tutorial/4/setns.md index c936259..46ec337 100644 --- a/tutorial/4/setns.md +++ b/tutorial/4/setns.md @@ -23,7 +23,7 @@ l'autre, d'une version du noyau à l'autre, il est normal d'avoir une liste de aurons les mêmes. Ces fichiers sont en fait des liens symboliques un peu particuliers, car ils ne -pointent pas vers une destination valide : +pointent pas vers une destination valide :
```bash @@ -52,7 +52,7 @@ On ne peut pas afficher tel quel les structures, mais on peut l'ouvrir avec `setns(2)`. Pour les commandes *shell*, il convient de donner en argument le chemin vers le -lien symbolique : la commande se chargera d'`open(2)` le fichier. +lien symbolique : la commande se chargera d'`open(2)` le fichier. #### `*_for_children`\ diff --git a/tutorial/4/setup.md b/tutorial/4/setup.md index c62c9a9..3bdc569 100644 --- a/tutorial/4/setup.md +++ b/tutorial/4/setup.md @@ -5,7 +5,7 @@ Pour pouvoir suivre les exercices ci-après, vous devez disposez d'un noyau Linux, idéalement dans sa version 5.6 ou mieux. Il doit de plus être compilé -avec les options suivantes (lorsqu'elles sont disponibles pour votre version) : +avec les options suivantes (lorsqu'elles sont disponibles pour votre version) :
``` @@ -28,7 +28,7 @@ Device Drivers ---> ```
-Les variables de configuration correspondantes sont : +Les variables de configuration correspondantes sont :
``` @@ -62,13 +62,13 @@ Nous allons utiliser des programmes issus des [`procps-ng`](https://gitlab.com/procps-ng/procps) ainsi que ceux de la [`libcap`](https://sites.google.com/site/fullycapable/). -Sous Debian et ses dérivés, ces paquets sont respectivement : +Sous Debian et ses dérivés, ces paquets sont respectivement : * `util-linux` * `procps` * `libcap2-bin` -Sous ArchLinux et ses dérivés, ces paquets sont respectivement : +Sous ArchLinux et ses dérivés, ces paquets sont respectivement : * `util-linux` * `procps-ng` @@ -79,17 +79,17 @@ Sous ArchLinux et ses dérivés, ces paquets sont respectivement : La sécurité du *namespace* `user` a souvent été remise en cause par le passé, on lui attribue de nombreuses vulnérabilités. Vous devriez notamment consulter -à ce sujet : +à ce sujet : -* [Security Implications of User Namespaces](https://blog.araj.me/security-implications-of-user-namespaces/) ; -* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ; -* ; +* [Security Implications of User Namespaces](https://blog.araj.me/security-implications-of-user-namespaces/) ; +* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ; +*  ; * . De nombreux projets ont choisi de ne pas autoriser l'utilisation de cet espace de noms sans disposer de certaines *capabilities*[^userns-caps]. -[^userns-caps]: Sont nécessaires, conjointement : `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`. +[^userns-caps]: Sont nécessaires, conjointement : `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`. De nombreuses distributions ont choisi d'utiliser un paramètre du noyau pour adapter le comportement. @@ -99,7 +99,7 @@ adapter le comportement. ##### Debian et ses dérivées {.unnumbered} Si vous utilisez Debian ou l'un de ses dérivés, vous devrez autoriser -explicitement cette utilisation non-privilégiée : +explicitement cette utilisation non-privilégiée :
```bash diff --git a/tutorial/4/userns.md b/tutorial/4/userns.md index 7a2a76e..a842433 100644 --- a/tutorial/4/userns.md +++ b/tutorial/4/userns.md @@ -23,7 +23,7 @@ utilisateur, on obtient les privilèges requis pour créer tous les autres types de *namespaces*. Grâce à cette technique, il est possible de lancer des conteneurs en tant que -simple utilisateur ; le projet [Singularity](https://sylabs.io/) repose +simple utilisateur ; le projet [Singularity](https://sylabs.io/) repose en grande partie sur cela. @@ -34,11 +34,11 @@ garder dans le nouvel espace, que les utilisateurs et les groupes utiles au processus, en les renumérotant au passage si besoin. -#### L'utilisateur -2 : *nobody*\ +#### L'utilisateur -2 : *nobody*\ Lorsque l'on arrive dans un nouvel espace, aucun utilisateur ni groupe n'est défini. Dans cette situation, tous les identifiants d'utilisateur et de groupe, -renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à +renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à l'utilisateur *nobody* et au groupe *nogroup*. -1 étant réservé pour indiquer une erreur dans le retour d'une commande, ou la @@ -53,7 +53,7 @@ Pour établir la correspondance, une fois que l'on a créé le nouveau ##### `uid_map`\ -Sur chaque ligne, on doit indiquer : +Sur chaque ligne, on doit indiquer : - L'identifiant marquant le début de la plage d'utilisateurs, pour le processus en question. @@ -62,7 +62,7 @@ Sur chaque ligne, on doit indiquer : - La taille de la plage. -Par exemple, le *namespace* `user` initial défini la correspondance suivante : +Par exemple, le *namespace* `user` initial défini la correspondance suivante :
``` @@ -75,7 +75,7 @@ Cela signifie que les utilisateurs dont l'identifiant court de 0 à `MAX_INT - 2` inclus, dans cet espace de noms, correspondent aux utilisateurs allant de 0 à `MAX_INT - 1` inclus, pour le processus affichant ce fichier. -Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut : +Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut :
``` @@ -99,18 +99,18 @@ des groupes au lieu des utilisateurs.
```bash -42sh$ unshare --mount --pid --mount-proc --fork --net --user --map-root-user /bin/bash +42sh$ unshare --mount --pid --mount-proc --fork --net --user --map-root-user bash ```
Un `capsh --print` nous montre que l'on est bien `root` et que l'on possède toutes les *capabilities*. Cependant, cela ne signifie pas que l'on a tous les -droits sur le système ; il y a plusieurs niveaux de validation qui entrent en +droits sur le système ; il y a plusieurs niveaux de validation qui entrent en jeu. L'idée étant que l'on a été désigné root dans son conteneur, on devrait pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors. ### Aller plus loin {-} -N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* : +N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* : `user_namespaces(7)`. diff --git a/tutorial/5/Makefile b/tutorial/5/Makefile index 5b54858..8269e42 100644 --- a/tutorial/5/Makefile +++ b/tutorial/5/Makefile @@ -2,7 +2,9 @@ include ../pandoc-opts.mk SOURCES_SRS = tutorial-srs.md \ ../devops/devops.md \ - ../devops/what.md \ + ../devops/what-srs.md \ + ../devops/what-ansible.md \ + ../devops/what-hosts.md \ ../devops/tools.md \ ../devops/tools-gitea.md \ ../devops/tools-gitea-ansible.md \ @@ -12,6 +14,7 @@ SOURCES_SRS = tutorial-srs.md \ ../devops/tools-drone-oauth.md \ ../devops/tools-drone-runner.md \ ../devops/tools-drone-runner-ansible.md \ + ../devops/tools-drone-runner-end.md \ ../devops/tools-end.md \ ../devops/ci.md \ ../devops/publish-docker.md \ @@ -19,6 +22,8 @@ SOURCES_SRS = tutorial-srs.md \ SOURCES_GISTRE = tutorial-gistre.md \ ../devops/what-gistre.md \ + ../devops/what-cmd.md \ + ../devops/what-hosts.md \ ../devops/what-gistre-see-srs.md \ ../devops/tools.md \ ../devops/tools-gitea.md \ @@ -29,6 +34,7 @@ SOURCES_GISTRE = tutorial-gistre.md \ ../devops/tools-drone-oauth.md \ ../devops/tools-drone-runner.md \ ../devops/tools-drone-runner-cmd.md \ + ../devops/tools-drone-runner-end.md \ ../devops/tools-end.md \ ../devops/ci-gistre.md \ ../devops/run-gistre.md \ diff --git a/tutorial/5/rendu-gistre.md b/tutorial/5/rendu-gistre.md index a9d75de..4544fb4 100644 --- a/tutorial/5/rendu-gistre.md +++ b/tutorial/5/rendu-gistre.md @@ -34,7 +34,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (vous pourriez avoir des fichiers -supplémentaires) : +supplémentaires) :
``` diff --git a/tutorial/5/rendu-srs.md b/tutorial/5/rendu-srs.md index 0409591..140bee8 100644 --- a/tutorial/5/rendu-srs.md +++ b/tutorial/5/rendu-srs.md @@ -34,7 +34,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (vous pourriez avoir des fichiers -supplémentaires) : +supplémentaires) :
``` diff --git a/tutorial/5/rendu.md b/tutorial/5/rendu.md index e11ac4d..ab04cb5 100644 --- a/tutorial/5/rendu.md +++ b/tutorial/5/rendu.md @@ -29,7 +29,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (vous pourriez avoir des fichiers -supplémentaires) : +supplémentaires) :
``` diff --git a/tutorial/5/tutorial-gistre.md b/tutorial/5/tutorial-gistre.md index 97e01ac..73ab0a2 100644 --- a/tutorial/5/tutorial-gistre.md +++ b/tutorial/5/tutorial-gistre.md @@ -1,13 +1,13 @@ --- title: Virtualisation légère -- TP n^o^ 5 -subtitle: "Application des conteneurs : tests et intégration continue" +subtitle: "Application des conteneurs : tests et intégration continue" author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps} institute: EPITA date: Jeudi 4 novembre 2021 abstract: | Durant ce nouveau TP, appréhenderons l'intégration continue et nous plongerons dans l'IoT pour trouver une solution innovante à des problèmes de - déploiement ! + déploiement ! \vspace{1em} diff --git a/tutorial/5/tutorial-srs.md b/tutorial/5/tutorial-srs.md index 80e0bce..fff7ea4 100644 --- a/tutorial/5/tutorial-srs.md +++ b/tutorial/5/tutorial-srs.md @@ -6,7 +6,7 @@ institute: EPITA date: Jeudi 4 novembre 2021 abstract: | Durant ce nouveau TP, nous allons jouer les DevOps et déployer - automatiquement des services ! + automatiquement des services ! \vspace{1em} diff --git a/tutorial/5/tutorial.md b/tutorial/5/tutorial.md index 5ed84df..9b7f000 100644 --- a/tutorial/5/tutorial.md +++ b/tutorial/5/tutorial.md @@ -6,7 +6,7 @@ institute: EPITA date: Jeudi 4 novembre 2021 abstract: | Durant ce nouveau TP, nous allons jouer les DevOps et déployer - automatiquement des services ! + automatiquement des services ! \vspace{1em} diff --git a/tutorial/colored-blocks.lua b/tutorial/colored-blocks.lua index f943420..bb60f07 100644 --- a/tutorial/colored-blocks.lua +++ b/tutorial/colored-blocks.lua @@ -4,7 +4,7 @@ function Div(el) -- insert element in front table.insert( el.content, 1, - pandoc.RawBlock("latex", "\\begin{alertbox}")) + pandoc.RawBlock("latex", "\\noindent\\begin{alertbox}")) -- insert element at the back table.insert( el.content, @@ -15,7 +15,7 @@ function Div(el) -- insert element in front table.insert( el.content, 1, - pandoc.RawBlock("latex", "\\begin{codebox}")) + pandoc.RawBlock("latex", "\\noindent\\begin{codebox}")) -- insert element at the back table.insert( el.content, @@ -26,7 +26,7 @@ function Div(el) -- insert element in front table.insert( el.content, 1, - pandoc.RawBlock("latex", "\\begin{questionbox}")) + pandoc.RawBlock("latex", "\\noindent\\begin{questionbox}")) -- insert element at the back table.insert( el.content, diff --git a/tutorial/devops/cd.md b/tutorial/devops/cd.md index 0a73e0a..88f6597 100644 --- a/tutorial/devops/cd.md +++ b/tutorial/devops/cd.md @@ -3,4 +3,4 @@ Déploiement =========== -TODO il faudrait pouvoir cliquer sur le bouton pour mettre à jour l'image docker qui tourne localement ? en passant par Ansible ? +TODO il faudrait pouvoir cliquer sur le bouton pour mettre à jour l'image docker qui tourne localement ? en passant par Ansible ? diff --git a/tutorial/devops/ci-gistre.md b/tutorial/devops/ci-gistre.md index c762d68..0f1130c 100644 --- a/tutorial/devops/ci-gistre.md +++ b/tutorial/devops/ci-gistre.md @@ -21,11 +21,11 @@ configuration des dépôts. ::::: Une fois Gitea et Drone installés et configurés, nous allons pouvoir rentrer -dans le vif du sujet : faire de l'intégration continue sur notre premier projet ! +dans le vif du sujet : faire de l'intégration continue sur notre premier projet ! ### Créez un dépôt pour `linky2influx` -Après avoir créé (ou migré pour les plus malins !) le dépôt +Après avoir créé (ou migré pour les plus malins !) le dépôt [`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) dans Drone, synchronisez les dépôts, puis activez la surveillance de `linky2influx`. @@ -57,33 +57,33 @@ Committons puis poussons notre travail. Dès qu'il sera reçu par Gitea, nous devrions voir l'interface de Drone lancer les étapes décrites dans le fichier. ::::: {.warning} -**IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez +**IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez réutilisé le fichier présent sur le dépôt au lieu de partir de l'exemple donné dans la documentation, **commencez en partant de l'exemple de la -documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans -votre situation ! +documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans +votre situation ! ::::: ![Drone en action](../devops/drone-run-linky.png){height=7.5cm} -Lorsqu'apparaît enfin la ligne `git.nemunai.re/linky2influx`, le projet est compilé ! +Lorsqu'apparaît enfin la ligne `git.nemunai.re/linky2influx`, le projet est compilé ! ### Publier le binaire correspondant aux tags/jalons Nous savons maintenant que notre projet compile bien dans un environnement -différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès +différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès lors que la compilation est terminée, car nous n'en faisons rien. Ajoutons donc une nouvelle règle à notre `.droneci.yml` pour placer le binaire au sein de la liste des fichiers téléchargeable aux côtés des tags. -Vous aurez sans doute besoin de : +Vous aurez sans doute besoin de : - - -Attention à ne pas stocker votre clef d'API dans le fichier YAML ! +Attention à ne pas stocker votre clef d'API dans le fichier YAML ! ![Binaire publié automatiquement sur Gitea](../devops/tag-released.png){height=8cm} @@ -95,16 +95,16 @@ l'interface de Drone. ::::: -### Publier pour plusieurs architectures ? +### Publier pour plusieurs architectures ? Le compilateur Go est fourni avec l'ensemble des backends des différentes architectures matérielles qu'il supporte, nous pouvons donc aisément faire de la compilation croisée pour d'autres architectures. Essayons maintenant de compiler `linky2influx` pour plusieurs architectures afin de -vérifier que cela fonctionne bien ! +vérifier que cela fonctionne bien ! -Un exemple est donné tout en haut de cette page : +Un exemple est donné tout en haut de cette page : . En faisant varier `$GOARCH` en `mips`, `powerpc`, ... nous pouvons générer les diff --git a/tutorial/devops/ci.md b/tutorial/devops/ci.md index 60ecf42..355ea91 100644 --- a/tutorial/devops/ci.md +++ b/tutorial/devops/ci.md @@ -3,24 +3,26 @@ ## Intégration continue Une fois Gitea et Drone installés et configurés, nous allons pouvoir rentrer -dans le vif du sujet : faire de l'intégration continue sur notre premier projet ! +dans le vif du sujet : faire de l'intégration continue sur notre premier projet ! ### Créez un dépôt pour `youp0m` -Reprenez les travaux réalisés au TP précédent. Nous allons notamment avoir -besoin du `Dockerfile` dans la section suivante. +Reprenez les travaux déjà réalisés : nous allons notamment avoir besoin du +`Dockerfile` que nous avons réalisé pour ce projet `youp0m`. -Après avoir créé (ou migré pour les plus malins !) le dépôt -[`youp0m`](https://git.nemunai.re/nemunaire/youp0m) dans Drone, -synchronisez les dépôts, puis activez la surveillance de `youp0m`. +Après avoir créé (ou migré pour les plus malins !) le dépôt +`youp0m`[^urlyoup0m] dans gitea, synchronisez les dépôts dans Drone, puis +activez la surveillance de `youp0m`. -Nous allons devoir rédiger un fichier `.drone.yml`, que l'on placera à la racine +[^urlyoup0m]: + +Nous allons devoir rédiger un fichier `drone.yml`, que l'on placera à la racine du dépôt. C'est ce fichier qui sera traité par DroneCI pour savoir comment compiler et tester le projet. ::::: {.warning} -Un fichier `.drone.yml` existe déjà à la racine du dépôt. Celui-ci pourra vous -servir d'inspiration, mais il ne fonctionnera pas directement sur votre +Un fichier `drone.yml` existe déjà à la racine du dépôt. Celui-ci pourra vous +servir d'inspiration, mais il ne fonctionnera pas directement dans votre installation. **Vous rencontrerez des problèmes inattendus si vous utilisez le fichier @@ -32,11 +34,11 @@ documentation pour obtenir un `.drone.yml` fonctionnel. ### Définir les étapes d'intégration Toutes les informations nécessaires à l'écriture du fichier `.drone.yml` se -trouvent dans [l'excellente documentation du -projet](https://docs.drone.io/pipeline/docker/examples/languages/golang/). +trouvent dans l'excellente documentation du projet :\ +. Les étapes sont sensiblement les mêmes que dans le `Dockerfile` que nous avons -écrit lors du TP précédent. +écrit précédemment. Committons puis poussons notre travail. Dès qu'il sera reçu par Gitea, nous devrions voir l'interface de Drone lancer les étapes décrites dans le fichier. @@ -44,23 +46,22 @@ devrions voir l'interface de Drone lancer les étapes décrites dans le fichier. ![Drone en action](../devops/drone-run.png){height=6cm} ::::: {.warning} -**IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez +**IMPORTANT :** si vous avez l'impression que ça ne marche pas et que vous avez réutilisé le fichier présent sur le dépôt au lieu de partir de l'exemple donné dans la documentation, **commencez en partant de l'exemple de la -documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans -votre situation ! +documentation** ! Le fichier présent sur le dépôt **ne fonctionnera pas** dans +votre situation ! ::::: -Lorsqu'apparaît enfin la ligne `git.nemunai.re/youp0m`, le projet est compilé ! +Lorsqu'apparaît enfin la ligne `git.nemunai.re/youp0m`, le projet est compilé ! ### Inspection qualité Nous n'avons pas encore de test à proprement parler. Nous allons utiliser -[Sonarqube](https://www.sonarqube.org/) pour faire une revue qualité du code ! +[Sonarqube](https://www.sonarqube.org/) pour faire une revue qualité du code ! -Tout d'abord, il faut lancer le conteneur Sonarqube (SRS, pensez à l'ajouter à -votre playbook !) : +Tout d'abord, il faut lancer le conteneur Sonarqube :
```bash @@ -72,7 +73,7 @@ Le service met un bon moment avant de démarrer, dès qu'il se sera initialisé, nous pourrons accéder à l'interface sur . En attendant qu'il démarre, nous pouvons commencer à ajouter le nécessaire à -notre `.drone.yml` : . +notre `.drone.yml` : . Après s'être connecté à Sonarqube (`admin:admin`), nous pouvons aller générer un token, tel que décrit dans la [documentation du plugin @@ -86,18 +87,18 @@ qui en fera une analyse minutieuse. Rendez-vous sur ### Publier le binaire correspondant aux tags/jalons Nous savons maintenant que notre projet compile bien dans un environnement -différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès +différent de celui du développeur ! Néanmoins, le binaire produit est perdu dès lors que la compilation est terminée, car nous n'en faisons rien. Ajoutons donc une nouvelle règle à notre `.droneci.yml` pour placer le binaire au sein de la liste des fichiers téléchargeables aux côtés des tags. -Vous aurez sans doute besoin de : +Vous aurez sans doute besoin de : - - -Attention à ne pas stocker votre clef d'API dans le fichier YAML ! +Attention à ne pas stocker votre clef d'API dans le fichier YAML ! ![Binaire publié automatiquement sur Gitea](../devops/tag-released.png){height=8cm} diff --git a/tutorial/devops/devops.md b/tutorial/devops/devops.md index e61e27b..bd9b1c2 100644 --- a/tutorial/devops/devops.md +++ b/tutorial/devops/devops.md @@ -4,13 +4,13 @@ Le mouvement DevOps =================== Jusqu'à récemment, et encore dans de nombreuses entreprises, les développeurs -et les administrateurs système faisaient partie de deux équipes différentes : +et les administrateurs système faisaient partie de deux équipes différentes : les uns développant sur leurs machines avec les dernières bibliothèques, utilisant les derniers frameworks à la mode, sans se préoccuper de la sécurité -(ils travaillent en `root` ou avec `sudo` ;)), tandis que les autres tentaient +(ils travaillent en `root` ou avec `sudo` ;)), tandis que les autres tentaient tant bien que mal de déployer ces services avec les contraintes opérationnelles en tête.\ -Ces contraintes : tant liées à la **sécurité** (il faut s'assurer +Ces contraintes : tant liées à la **sécurité** (il faut s'assurer qu'un service n'utilise pas une bibliothèque vulnérable par exemple, donc soit utilisé sur un système à jour, et qu'il ne tourne pas en `root`), qu'à la **disponibilité** (si le service est mal codé est contient beaucoup de fuites @@ -19,13 +19,13 @@ pâtissent). Une guerre faisait donc rage entre les développeurs qui ne comprenaient pas que les administrateurs système ne pouvaient pas maintenir autant de versions d'une -bibliothèque qu'il y avait de services : par exemple dans le cas de plusieurs +bibliothèque qu'il y avait de services : par exemple dans le cas de plusieurs services en PHP, on pouvait leur demander de déployer des applications utilisant la version 5.6, et la 7.2 pour d'autres, ... lorsqu'il y avait des incompatibilités mineures et plus personne pour s'occuper de la maintenance d'un vieux service toujours utilisé. -Le même principe est aussi valable pour Python, Ruby, ... : les développeurs +Le même principe est aussi valable pour Python, Ruby, ... : les développeurs ont toujours eu tendance à vouloir utiliser les dernières améliorations d'un langage, mais les administrateurs système n'ont alors pas de paquets stables dans la distribution. En effet, les distributions stables telles que Debian, @@ -64,10 +64,10 @@ charges, les pannes, ... ::::: {.warning} Attention par contre aux entreprises qui recrutent un profil DevOps, car cela a -autant de sens que recruter un développeur Scrum ou un développeur cycle en V : +autant de sens que recruter un développeur Scrum ou un développeur cycle en V : DevOps est une méthodologie. Les entreprises qui recrutent un DevOps recherchent généralement quelqu'un qui fera à la fois du développement logiciel -d'un côté et de l'administration système de l'autre : une situation +d'un côté et de l'administration système de l'autre : une situation généralement assez difficile à vivre. Alors qu'au contraire, la mouvance DevOps doit être prise au sérieux par l'ensemble des développeurs. Lors d'un entretien d'embauche pour ce genre de poste, assurez-vous bien de ne pas être le seul à @@ -77,14 +77,14 @@ faire du DevOps. ## Intégration continue -L'**intégration continue** est la première brique à mettre en place : le but +L'**intégration continue** est la première brique à mettre en place : le but est de compiler automatiquement chaque commit dans un environnement proche de celui de production, puis de lancer les suites de tests du logiciel. Cela permet de détecter les problèmes au plus tôt dans le cycle de développement, mais cela permet également d'améliorer la qualité du code sur le long terme, car on peut y ajouter facilement des outils qui vont se charger -automatiquement de réaliser des analyses : cela peut aller de la couverture des +automatiquement de réaliser des analyses : cela peut aller de la couverture des tests, à de l'analyse statique ou dynamique de binaire, en passant par la recherche de vulnérabilités ou de mauvaises pratiques de programmation. @@ -101,7 +101,7 @@ les développeurs considéreront avoir atteint un jalon, une version stable. ## Déploiement continu Une fois tous les tests passés et les objets produits (on parle d'*artifact* ou -d'*assets*), il est possible de déclencher un déploiement : il s'agit de rendre +d'*assets*), il est possible de déclencher un déploiement : il s'agit de rendre accessible aux utilisateurs finaux le service ou les objets. Dans le cas d'un programme à télécharger @@ -113,15 +113,15 @@ vers la dernière version (pour que les utilisateurs aient la notifications). Ou bien dans le cas d'un service en ligne (GitHub, Netflix, GMail, ...), il s'agira de mettre à jour le service. -Parfois les deux seront à faire : à la fois publier un paquet ou un -conteneur et mettre à jour un service en ligne : par exemple, [le +Parfois les deux seront à faire : à la fois publier un paquet ou un +conteneur et mettre à jour un service en ligne : par exemple, [le serveur Synapse](https://buildkite.com/matrix-dot-org/synapse) du protocole de messagerie Matrix ou encore [Gitlab](https://gitlab.com/gitlab-org/gitlab/-/pipelines), tous deux publient des paquets à destination de leurs communautés, et mettent à jour leur service en ligne.\ -Il existe pour cela de très nombreuses stratégies : lorsque l'on n'a pas +Il existe pour cela de très nombreuses stratégies : lorsque l'on n'a pas beaucoup de trafic ni beaucoup de machines, on peut simplement éteindre l'ancien service et démarrer le nouveau, si ça prend quelques millisecondes en étant automatisé, cela peut être suffisant compte tenu du faible @@ -133,11 +133,11 @@ de tout rallumer. Déjà parce que trop de visiteurs vont se retrouver avec des pages d'erreur, et aussi parce qu'en cas de bug logiciel qui n'aurait pas été vu malgré les étapes précédentes, cela pourrait créer une situation catastrophique (imaginez qu'on ne puisse plus valider une commande sur Amazon à -cause d'une ligne commentée par erreur !).\ +cause d'une ligne commentée par erreur !).\ On va donc privilégier un déploiement progressif de la nouvelle version (que l'on va étendre sur plusieurs minutes, heures ou mêmes jours), en éteignant tour à tour les instances, et en veillant à ce que les métriques (voir la -section suivante !) soient constantes. +section suivante !) soient constantes. ## Monitoring et supervision @@ -145,16 +145,16 @@ section suivante !) soient constantes. Une fois déployé, le service peut avoir des ratés, alors il convient de le surveiller afin d'être le plus proactif possible dans la résolution des problèmes. La pire situation est celle dans laquelle c'est un utilisateur qui -nous informe d'un problème... (sur Twitter !?) +nous informe d'un problème... (sur Twitter !?) Nous avons réalisé précédemment une partie collecte de métriques, avec nos conteneurs TICK. Nous n'allons donc pas nous en occuper aujourd'hui. \ Notez tout de même qu'il y a deux grandes catégories de logiciels de -supervision : +supervision : -**Basée sur des états** comme Nagios, Zabbix, ... : ces logiciels vont +**Basée sur des états** comme Nagios, Zabbix, ... : ces logiciels vont simplement réaliser des séries de tests définis, à intervalles réguliers et contacter l'administrateur d'astreinte dès qu'un test ne passe plus de manière persistante. @@ -163,8 +163,8 @@ Il y a rarement beaucoup d'intelligence ou d'anticipation automatique dans ces outils. \ -**Basée sur les métriques** comme ELK, Prometheus, InfluxDB, ... : dans la -stack TICK que nous avons mis en place au précédent TP, nous avions placé un +**Basée sur les métriques** comme ELK, Prometheus, InfluxDB, ... : dans la +stack TICK que nous avons mis en place précédemment, nous avions placé un agent sur la machine que nous souhaitions analyser. Outre les graphiques présenté dans Chronograf, le dernier outil que l'on n'avait pas configuré était Kapacitor, qui permet après avoir analysé les données, d'alerter en fonction @@ -196,4 +196,4 @@ des pannes, des latences, ... à n'importe quel niveau du produit, afin d'en tester (brulatement certes) sa résilience. Cela oblige les développeurs, les opérationnels et les architectes à concevoir des services hautement tolérant aux pannes, ce qui fait que le jour où une véritable panne survient, elle n'a -aucun impact sur la production (enfin on espère !). +aucun impact sur la production (enfin on espère !). diff --git a/tutorial/devops/publish-docker.md b/tutorial/devops/publish-docker.md index c825ae4..d3ef438 100644 --- a/tutorial/devops/publish-docker.md +++ b/tutorial/devops/publish-docker.md @@ -7,13 +7,12 @@ Toutes les tâches de publication peuvent s'assimiler à des tâches de déploiement continu. C'est en particulier le cas lorsque le produit de compilation sera simplement publié et qu'il n'y a pas de service à mettre à jour ensuite (par exemple, dans le cas de Firefox ou de LibreOffice, une fois -testés, les paquets sont envoyés sur le serveur d'où ils seront distribués ; il +testés, les paquets sont envoyés sur le serveur d'où ils seront distribués ; il n'y a pas de service/docker à relancer). -À l'inverse, `youp0m` ou `linky2influx` sont à la fois des programmes que l'on -peut télécharger et des services qu'il faut déployer pour les mettre à -jour. Pour simplifier le déploiement, nous utilisons des images Docker. Il faut -cependant les générer ... +À l'inverse, `youp0m` est à la fois un programme que l'on peut télécharger et +un service qu'il faut déployer pour le mettre à jour. Pour simplifier le +déploiement, nous utilisons une image Docker. Il faut cependant la générer ... ## Mise en place du registre @@ -25,7 +24,7 @@ Docker intégré. Si vous utilisez Gitea, continuez cette section. Afin de disposer de notre propre registre Docker sur lequel publier nos images, nous allons utiliser l'image de registre fournie par Docker. Elle se lance -comme suit : +comme suit :
```bash @@ -37,7 +36,7 @@ Vous trouverez davantage d'informations pour le déploiement [ici](https://docs.docker.com/registry/deploying/). Nous pouvons tester le bon fonctionnement de notre registre avec la commande -suivante : +suivante :
```bash @@ -50,7 +49,7 @@ suivante : ## Publication de l'image Une fois le registre démarré, il ne nous reste plus qu'à ajouter une étape de -publication de l'image Docker. Cela se fait au moyen du plugin suivant : +publication de l'image Docker. Cela se fait au moyen du plugin suivant :\ . Sans plus de configuration, le registre que nous avons démarré @@ -62,7 +61,7 @@ pour utiliser `https`, il est nécessaire de définir l'option ## Test de l'image Sur l'hôte, nous pouvons tester que l'image a bien été publiée grâce à la -commande suivante : +commande suivante :
```bash @@ -92,8 +91,8 @@ une machine virtuelle avec une connexion SSH. N'hésitez pas à l'ajouter à vot `.droneci.yml`. -## Profitons ! +## Profitons ! Sonarqube a repéré quelques erreurs dans le code de `youp0m`, essayez de les corriger, et publiez une nouvelle version, pour observer toute la chaîne en -action ! +action ! diff --git a/tutorial/devops/run-gistre.md b/tutorial/devops/run-gistre.md index 016612c..c0d0419 100644 --- a/tutorial/devops/run-gistre.md +++ b/tutorial/devops/run-gistre.md @@ -6,7 +6,7 @@ Mettons de côté le déploiement continu, pour nous concentrer sur la manière dont nous allons pouvoir exécuter notre module de relevé de compteur Linky. \ -Le binaire de notre module se lance de la manière suivante : +Le binaire de notre module se lance de la manière suivante :
```shell @@ -35,7 +35,7 @@ retient votre attention. Vous êtes tenu de retenir au minimum 2 solutions distinctes (on considère que les technologies listées sur la même lignes sont similaires). -La liste de technologies proposées est à la suivante : +La liste de technologies proposées est à la suivante : - conteneur Docker ou podman, - conteneur LXC (avec base alpine ou nu), @@ -83,7 +83,7 @@ login_x-TP5/lxc/run.sh
En complément, vous pouvez inclure au dépôt de `linky2influx` le modèle -permettant de créer le conteneur LXC, ainsi qu'un exemple de configuration : +permettant de créer le conteneur LXC, ainsi qu'un exemple de configuration :
``` @@ -107,7 +107,7 @@ vous pourriez écrire le script `systemd` et profiter de l'utiliser dans votre recette `bitbake`. Un service basé sur `nspawn` peut par contre être potentiellement intéressant, -il pourra être intégré au dépôt : +il pourra être intégré au dépôt :
``` @@ -121,7 +121,7 @@ login_x-TP5/linky2influx/systemd/linky2influx.nspawn Vous pourriez vouloir écrire une recette Bitbake pour créer et déployer le module via un paquet `.ipk` ou similaire en fonction de votre configuration. -Écrivez la recette au sein de `meta-electropcool` : +Écrivez la recette au sein de `meta-electropcool` :
``` @@ -146,7 +146,7 @@ utiliser le package Nix ensuite. ### Snap, Flatpack, AppImage -Intégrez au dépôt le fichier de description, par exemple : +Intégrez au dépôt le fichier de description, par exemple :
``` @@ -155,7 +155,7 @@ login_x-TP5/linky2influx/snapcraft.yaml
Il faudra également préciser avec un fichier `run.sh` la manière dont lancer -votre conteneur : +votre conteneur :
``` @@ -168,7 +168,7 @@ login_x-TP5/{snap,flatpack}/run.sh ### k3s Nous en apprendrons davantage sur Kubernetes au prochain TP, mais si vous -connaissez déjà, vous pourriez vouloir écrire un *Chart* Helm : +connaissez déjà, vous pourriez vouloir écrire un *Chart* Helm :
``` @@ -176,7 +176,7 @@ login_x-TP5/k3s/linky2influx.yaml ```
-Inutile de vous casser la tête avec ça si vous ne connaissez pas ! +Inutile de vous casser la tête avec ça si vous ne connaissez pas ! ### Votre solution @@ -191,4 +191,4 @@ login_x-TP5/k3s/linky2influx.yaml
\ -À vous de jouer ! +À vous de jouer ! diff --git a/tutorial/devops/tools-drone-ansible.md b/tutorial/devops/tools-drone-ansible.md index a34e1d4..4edcc3b 100644 --- a/tutorial/devops/tools-drone-ansible.md +++ b/tutorial/devops/tools-drone-ansible.md @@ -1,5 +1,5 @@ Voici à quoi pourrait ressembler le playbook Ansible démarrant notre conteneur -Drone : +Drone :
```yaml diff --git a/tutorial/devops/tools-drone-cmd.md b/tutorial/devops/tools-drone-cmd.md index 26d6188..256d21d 100644 --- a/tutorial/devops/tools-drone-cmd.md +++ b/tutorial/devops/tools-drone-cmd.md @@ -1,26 +1,36 @@ -Voici à quoi pourrait ressembler la ligne de commande démarrant notre conteneur -Drone : +Tout comme Gitea, Drone tire un certain nombre de paramètres depuis son +environnement. Nous allons donc commencer par indiquer l'identifiant et le +secret de l'application que l'on a créé précédemment dans Gitea :
```shell export DRONE_GITEA_CLIENT_ID=#FIXME export DRONE_GITEA_CLIENT_SECRET=#FIXME -export DRONE_RPC_SECRET=$(openssl rand -base64 30) - -docker container run --name droneci -d \ - -v /var/lib/drone:/data \ - --network gitea -p 80:80 \ - -e DRONE_GITEA_CLIENT_ID -e DRONE_GITEA_CLIENT_SECRET -e DRONE_GITEA_SERVER=http://gitea:3000 \ - -e DRONE_RPC_SECRET -e DRONE_SERVER_HOST=droneci -e DRONE_SERVER_PROTO=http \ - drone/drone:1 - -docker network connect drone droneci ```
-La dernière commande permet à notre conteneur Drone d'être à la fois présent -dans le réseau `gitea` et `drone`, ce qui permet de garder les deux réseaux -distincts. +Puis, tout comme pour Gitea, nous allons générer un secret. Ce secret est +utilisé par les différents *worker*s pour s'authentifier : + +
+```shell +export DRONE_RPC_SECRET=$(openssl rand -base64 30) +``` +
+ +Lançons enfin Drone avec les deux commandes suivantes : + +
+```shell +docker volume create drone_data + +docker container run --name droneci -d -v drone_data:/data --network my_ci_net + -p 80:80 -e DRONE_GITEA_CLIENT_ID -e DRONE_GITEA_CLIENT_SECRET \ + -e DRONE_GITEA_SERVER=http://gitea:3000 -e DRONE_SERVER_PROTO=http \ + -e DRONE_RPC_SECRET -e DRONE_SERVER_HOST=droneci \ + drone/drone:2 +``` +
Gardez la variable d'environnement `DRONE_RPC_SECRET` dans un coin, nous en aurons encore besoin juste après. diff --git a/tutorial/devops/tools-drone-oauth.md b/tutorial/devops/tools-drone-oauth.md index ad4f366..945bb2c 100644 --- a/tutorial/devops/tools-drone-oauth.md +++ b/tutorial/devops/tools-drone-oauth.md @@ -1,15 +1,7 @@ -::::: {.question} - -La version 2 de Drone, encore plus pratique et sympathique est disponible en -test. Vous pouvez tout à fait l'utiliser pour la suite du TP. Cela ne change -pas la version des *runners* à utiliser. - -::::: - -Une fois lancé, rendez-vous sur l'interface de DroneCI : +Une fois lancé, rendez-vous sur l'interface de DroneCI : Vous serez automatiquement redirigé vers la page d'authentification de Gitea, puis vers l'autorisation OAuth d'accès de Drone à Gitea. Il faut bien évidemment valider cette demande, afin que Drone ait accès à nos dépôts. -![OAuth Drone](../devops/oauth-drone.png){width=9cm} +![OAuth Drone](../devops/oauth-drone.png){width=9cm} diff --git a/tutorial/devops/tools-drone-runner-ansible.md b/tutorial/devops/tools-drone-runner-ansible.md index 647b1c1..dd1d239 100644 --- a/tutorial/devops/tools-drone-runner-ansible.md +++ b/tutorial/devops/tools-drone-runner-ansible.md @@ -1,4 +1,4 @@ -Voici à quoi pourrait ressembler le playbook Ansible démarrant notre agent Drone : +Voici à quoi pourrait ressembler le playbook Ansible démarrant notre agent Drone :
```yaml diff --git a/tutorial/devops/tools-drone-runner-cmd.md b/tutorial/devops/tools-drone-runner-cmd.md index fff43aa..7e9426e 100644 --- a/tutorial/devops/tools-drone-runner-cmd.md +++ b/tutorial/devops/tools-drone-runner-cmd.md @@ -1,11 +1,13 @@ -Voici à quoi pourrait ressembler la ligne de commande démarrant notre agent Drone : +\ + +Voici La ligne de commande permettant de démarrer notre agent :
```shell -docker container run --name droneci-runner -d \ - -v /var/run/docker.sock:/var/run/docker.sock --network drone \ - -e DRONE_RPC_PROTO=http -e DRONE_RPC_HOST=droneci -e DRONE_RPC_SECRET \ - -e DRONE_RUNNER_CAPACITY=2 -e DRONE_RUNNER_NAME=my-runner -e DRONE_RUNNER_NETWORKS=drone,gitea \ +docker container run --name droneci-runner -d --network my_ci_net \ + -v /var/run/docker.sock:/var/run/docker.sock -e DRONE_RPC_PROTO=http + -e DRONE_RPC_HOST=droneci -e DRONE_RPC_SECRET -e DRONE_RUNNER_CAPACITY=2 \ + -e DRONE_RUNNER_NAME=my-runner -e DRONE_RUNNER_NETWORKS=my_ci_net \ drone/drone-runner-docker:1 ```
diff --git a/tutorial/devops/tools-drone-runner-end.md b/tutorial/devops/tools-drone-runner-end.md new file mode 100644 index 0000000..c19602b --- /dev/null +++ b/tutorial/devops/tools-drone-runner-end.md @@ -0,0 +1,9 @@ +::::: {.more} + +On remarquera que l'on partage notre socket Docker : l'exécution de code +arbitraire n'aura pas lieu directement dans le conteneur, en fait il s'agit +d'un petit orchetrateur qui lancera d'autres conteneurs en fonction des tâches +qu'on lui demandera. Le code arbitraire sera donc toujours exécuté dans un +conteneur moins privilégié. + +::::: diff --git a/tutorial/devops/tools-drone-runner.md b/tutorial/devops/tools-drone-runner.md index b4d8427..745f014 100644 --- a/tutorial/devops/tools-drone-runner.md +++ b/tutorial/devops/tools-drone-runner.md @@ -2,14 +2,13 @@ Notre conteneur `droneci` est uniquement une interface graphique qui va centraliser d'un côté les nouveaux commits à traiter, et de l'autre les -résultats retournés par les agents chargés d'exécuter le code. +résultats retournés par les agents chargés d'exécuter les tâches. Il serait impensable d'exécuter arbitrairement du code en parallèle d'une application privilégiée (ici, notre conteneur `droneci` a accès aux dépôts potentiellement privés de Gitea). Les agents qui sont amenés à traiter du code -arbitraire s'exécutent à part et peuvent être de différents types. Dans le -vocabulaire de Drone, on les appelle des ~~blade~~*runners*. +arbitraire s'exécutent à part et peuvent être de différents types. -Nous allons lancer un *runner* Docker : il s'agit d'un type d'agent qui va +Nous allons lancer un *runner* Docker : il s'agit d'un type d'agent qui va exécuter nos étapes de compilation dans des conteneurs Docker (oui, quand on -disait que Drone était conçu autour de Docker, c'était pas pour rire !) +disait que Drone était conçu autour de Docker, c'était pas pour rire !) diff --git a/tutorial/devops/tools-drone.md b/tutorial/devops/tools-drone.md index b3d8731..df0be10 100644 --- a/tutorial/devops/tools-drone.md +++ b/tutorial/devops/tools-drone.md @@ -8,6 +8,10 @@ Mais nous allons déployer notre propre solution, en utilisant [Drone CI](https://drone.io/). C'est une solution d'intégration continue libre et moderne, conçue tout autour de Docker. Idéale pour nous ! +Deux conteneurs sont à lancer : nous aurons d'un côté l'interface de contrôle +et de l'autre un agent (*runner* dans le vocabulaire de Drone) chargé +d'exécuter les tests. Dans un environnement de production, on aura généralement +plusieurs agents, et ceux-ci seront situé sur des machines distinctes. ### Interface de contrôle et de dispatch des tâches @@ -19,6 +23,8 @@ Drone va avoir besoin d'authentifier les utilisateurs afin d'accéder aux dépô privés (avec l'autorisation des utilisateurs). Pour cela, comme l'indique la documentation de Drone, on va utiliser OAuth2 : dans Gitea, il va falloir créer une *application OAuth2*. Le formulaire de création se trouve dans la -configuration du compte utilisateur, sous l'onglet *Applications*. Drone aura -également besoin d'une URL de redirection. Dans notre cas, ce sera : +configuration du compte utilisateur, sous l'onglet *Applications*. + +Drone aura également besoin d'une URL de redirection. Dans notre cas, +ce sera :\ `http://droneci/login`. diff --git a/tutorial/devops/tools-end.md b/tutorial/devops/tools-end.md index 6c4e617..d870359 100644 --- a/tutorial/devops/tools-end.md +++ b/tutorial/devops/tools-end.md @@ -1 +1 @@ -L'environnement étant prêt, il ne reste plus qu'à nous lancer dans nos projets ! +L'environnement étant prêt, il ne reste plus qu'à nous lancer dans nos projets ! diff --git a/tutorial/devops/tools-gitea-ansible.md b/tutorial/devops/tools-gitea-ansible.md index a72b6db..1d33700 100644 --- a/tutorial/devops/tools-gitea-ansible.md +++ b/tutorial/devops/tools-gitea-ansible.md @@ -1,13 +1,17 @@ -Votre playbook ressemblera à quelque chose comme ça : +Votre playbook ressemblera à quelque chose comme ça :
```yaml -- name: Launch gitea container +- name: Create a volume for storing repositories + docker_volume: + name: gitea-data + +- name: launch gitea container docker_container: name: gitea image: "gitea/gitea:{{ version }}" volumes: - - /var/lib/gitea:/data + - gitea-data:/data - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro state: started @@ -27,3 +31,5 @@ Votre playbook ressemblera à quelque chose comme ça : SECRET_KEY: "{{ secret_key }}" ```
+ +Plus d'infos sur cette page : . diff --git a/tutorial/devops/tools-gitea-cmd.md b/tutorial/devops/tools-gitea-cmd.md index d522ecc..41b8161 100644 --- a/tutorial/devops/tools-gitea-cmd.md +++ b/tutorial/devops/tools-gitea-cmd.md @@ -1,13 +1,33 @@ -La ligne de commande pour lancer Gitea ressemblera à quelque chose comme ça : +Commençons par créer un nouveau volume `gitea-data`, celui-ci contiendra +les données de `gitea` (nos dépôts Git, mais également la configuration propre +à `gitea`) : + +
+```shell +docker volume create gitea-data +``` +
+ +Afin de simplifier l'installation de notre conteneur, nous allons utiliser un +maximum de paramètres par défaut. Il faudra toutefois générer une clef secrète +propre à l'installation. Puisque c'est temporaire, on peut se contenter de ne +pas la stocker (elle sera perdue si on ferme notre terminal) :
```shell export SECRET_KEY=$(openssl rand -base64 30) +``` +
-docker container run --name gitea -d \ - -v /var/lib/gitea:/data -v /etc/timezone:/etc/timezone:ro -v /etc/localtime:/etc/localtime:ro \ - --network gitea -p 2222:22 -p 3000:3000 \ - -e RUN_MODE=prod -e DOMAIN=gitea -e SSH_DOMAIN=gitea -e INSTALL_LOCK=true -e SECRET_KEY \ +Pour finir, lançons notre conteneur `gitea` : + +
+```shell +docker container run --name gitea --network my_ci_net -p 2222:22 -p 3000:3000 \ + -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro \ + -v gitea-data:/data \ + -e RUN_MODE=prod -e DOMAIN=gitea -e SSH_DOMAIN=gitea -e INSTALL_LOCK=true \ + -e SECRET_KEY -d \ gitea/gitea:1 ```
diff --git a/tutorial/devops/tools-gitea-end.md b/tutorial/devops/tools-gitea-end.md index 145979b..e49e266 100644 --- a/tutorial/devops/tools-gitea-end.md +++ b/tutorial/devops/tools-gitea-end.md @@ -1,15 +1,15 @@ -Plus d'infos sur cette page : . +Une fois le conteneur lancé, vous pouvez accéder à l'interface de votre +gestionnaire de versions sur le port 3000 de votre machine (à moins que vous +n'ayez opté pour un autre port). +\ -Une fois le conteneur lancé, vous pouvez accéder à l'interface de gitea sur le -port 3000 de votre machine (à moins que vous n'ayez opté pour un autre port). - -Vous pouvez ajouter un nouvel administrateur avec la commande suivante : +Vous pouvez ajouter un nouvel administrateur avec la commande suivante :
```bash -docker exec gitea gitea admin user create --username "${USER}" --random-password \ - --must-change-password=false --admin --email "${USER}@epita.fr" +docker exec gitea gitea admin user create --username "${USER}" --admin \ + --must-change-password=false --random-password --email "${USER}@example.com" ```
-Notez le mot de passe généré pour [vous y connecter](http://localhost:3000/user/login). +Notez le mot de passe généré pour ensuite vous y connecter. diff --git a/tutorial/devops/tools-gitea.md b/tutorial/devops/tools-gitea.md index 0875f82..1bbd35a 100644 --- a/tutorial/devops/tools-gitea.md +++ b/tutorial/devops/tools-gitea.md @@ -21,7 +21,7 @@ que l'on peut lier avec ses dépôts. Une fonctionnalité que GitLab propose En effet, la problématique du stockage des produits de compilation est vaste. Si au début on peut se satisfaire d'un simple serveur web/FTP/SSH pour les récupérer manuellement, on a vite envie de pouvoir utiliser les outils -standards directement : `docker pull ...`, `npm install ...`, ... +standards directement : `docker pull ...`, `npm install ...`, ... Des programmes et services se sont spécialisés là-dedans, citons notamment [Artifactory](https://jfrog.com/artifactory/) ou [Nexus @@ -33,11 +33,11 @@ Dans un premier temps, nous allons nous contenter de publier un binaire associé ### Installation et configuration -Allez c'est parti ! première chose à faire : installer et configurer +Allez c'est parti ! première chose à faire : installer et configurer [Gitea](https://gitea.io/) (ceux qui le souhaitent peuvent choisir [gitlab](https://gitlab.org/) ou une autre plate-forme, mais la suite sera moins guidée). -Nous allons utiliser l'image : +Nous allons utiliser l'image : [`gitea/gitea`](https://hub.docker.com/r/gitea/gitea) (ou [`gitlab/gitlab-ce`](https://hub.docker.com/r/gitlab/gitlab-ce)). diff --git a/tutorial/devops/what-ansible.md b/tutorial/devops/what-ansible.md new file mode 100644 index 0000000..9d95222 --- /dev/null +++ b/tutorial/devops/what-ansible.md @@ -0,0 +1,16 @@ +## Préparer le terrain + +Tous les déploiements sont à faire sur votre machine en utilisant des +conteneurs Docker, qui seront regroupés au sein de réseaux +Docker. Cela vous permettra d’utiliser la résolution de noms entre vos +conteneurs. + +Dans votre playbook Ansible, vous pourrez procéder ainsi : + +
+```yaml +- name: Create virli network + docker_network: + name: virli3 +``` +
diff --git a/tutorial/devops/what-cmd.md b/tutorial/devops/what-cmd.md new file mode 100644 index 0000000..7575395 --- /dev/null +++ b/tutorial/devops/what-cmd.md @@ -0,0 +1,15 @@ +## Préparer le terrain + +Tous les déploiements sont à faire sur votre machine ; la plate-forme de CI +utilisera massivement les conteneurs Docker, qui seront regroupés au sein de +réseaux Docker : cela nous permettra de profiter de la résolution de noms entre +les conteneurs. + +Dès à présent, nous pouvons commencer par créer un réseau, dans lequel nous +placerons tous nos conteneurs de CI/CD : + +
+```shell +docker network create my_ci_net +``` +
diff --git a/tutorial/devops/what-gistre.md b/tutorial/devops/what-gistre.md index 2969908..6c1a992 100644 --- a/tutorial/devops/what-gistre.md +++ b/tutorial/devops/what-gistre.md @@ -3,7 +3,7 @@ Électropcool ============ -Bienvenue dans la société Électropcool ! +Bienvenue dans la société Électropcool ! Électropcool est une société française spécialisée dans l'[immotique](https://fr.wikipedia.org/wiki/Immotique), elle vend des @@ -20,14 +20,14 @@ en combustible (liés à la météo)[^HOMEASSISTANT]. [^HOMEASSISTANT]: Si ça vous met l'eau à la bouche, jettez un œil du côté du projet qui fait un peu moins de - *bullshit*, mais est bien réel ! + *bullshit*, mais est bien réel ! La principale difficulté que rencontre Électropcool est qu'aucun bâtiment ne dispose des mêmes références de pièces et qu'en dehors des nouveaux bâtiments pour lesquels la société peut imposer des équipements électroniques spécifiquement supportés et compatibles avec la plate-forme qu'elle vend, il lui est bien souvent nécessaire de faire des développements spécifiques pour -s'interfacer avec de l'électronique existant : c'est notamment le cas pour les +s'interfacer avec de l'électronique existant : c'est notamment le cas pour les chaudières et les [VMC](https://fr.wikipedia.org/wiki/Ventilation_m%C3%A9canique_contr%C3%B4l%C3%A9e), qui, compte tenu de leur coût de remplacement prohibitif, nécessitent souvent @@ -74,7 +74,7 @@ retiendrez.) \ Le projet qui vous servira de base pour vos tests sera -[`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) : à partir d'un +[`linky2influx`](https://git.nemunai.re/nemunaire/linky2influx) : à partir d'un compteur [Linky](https://fr.wikipedia.org/wiki/Linky), branché sur les bornes de [téléinformation client du compteur](https://hallard.me/demystifier-la-teleinfo/) et [lisant le @@ -92,36 +92,3 @@ gestionnaire de versions. Nous testerons enfin différentes solution pour déployer notre binaire, afin d'établir quelle est la solution adéquate. - - -## Préparer le terrain - -Tous les déploiements sont à faire sur votre machine et la plate-forme de CI -utilisera massivement les conteneurs Docker, qui seront regroupés au sein de -réseaux Docker. Cela vous permettra d'utiliser la résolution de noms entre vos -conteneurs. - -Vous devriez dès maintenant créer les deux réseaux suivants sur votre machines : - -
-```shell -docker network create gitea -docker network create drone -``` -
- - -Étant donné que votre machine ne dispose pas de domaine sur Internet et que -l'on va essayer de simplifier au maximum l'installation, vous devriez ajouter -cette ligne à votre fichier `/etc/hosts` (ou -`\Windows\System32\drivers\etc\hosts`) : - -
-```conf -127.0.0.1 gitea droneci -``` -
- -Cette ligne va vous permettre de résoudre les noms des conteneurs. Cela -permettra aux requêtes OAuth de se faire de manière transparente pour vous -lorsque vous serez dans votre navigateur. diff --git a/tutorial/devops/what-hosts.md b/tutorial/devops/what-hosts.md new file mode 100644 index 0000000..53dc91f --- /dev/null +++ b/tutorial/devops/what-hosts.md @@ -0,0 +1,14 @@ +Étant donné que votre machine ne dispose pas de domaine sur Internet et que +l'on va essayer de simplifier au maximum l'installation, vous devriez ajouter +cette ligne à votre fichier `/etc/hosts` (ou +`\Windows\System32\drivers\etc\hosts`) : + +
+```conf +127.0.0.1 gitea droneci +``` +
+ +Cette ligne va vous permettre de résoudre les noms des conteneurs. Cela +permettra aux requêtes OAuth de se faire de manière transparente pour vous +lorsque vous serez dans votre navigateur. diff --git a/tutorial/devops/what-srs.md b/tutorial/devops/what-srs.md new file mode 100644 index 0000000..aa2a3db --- /dev/null +++ b/tutorial/devops/what-srs.md @@ -0,0 +1,32 @@ +\newpage + +But du TP +========= + +Nous allons nous mettre aujourd’hui dans la peau d’une équipe DevOps et +réaliser une solution complète d’intégration/déploiement continu (le fameux +CI/CD, pour *Continuous Integration* et *Continuous Delivery*). + +Le résultat attendu d’ici la fin de cette partie sera de mettre en place toutes +les briques décrites dans la section précédente. +\ + +Nous allons commencer par automatiser le projet `youp0m`, plus simple, ~~puis +la plate-forme du FIC dans son ensemble, ce qui représente un petit challenge~~ +(merci Nabih !). + +Il est également attendu que vous rendiez un playbook Ansible, permettant de +retrouver un environnement similaire. Car on pourra s’en resservir par la +suite. +\ + +Dans un premier temps, on voudra juste compiler notre projet, pour s’assurer +que chaque commit poussé ne contient pas d’erreur de compilation, dans +l’environnement défini comme étant celui de production. Ensuite, on ajoutera +quelques tests automatiques. Puis nous publierons automatiquement le binaire +`youp0m` comme fichier associé à un tag au sein de l’interface web du +gestionnaire de versions. + +Enfin, nous mettrons en place un registre Docker qui nous permettra de publier +automatiquement l’image Docker associée. C’est à partir de cette image Docker +que l’on va commencer à déployer automatiquement... diff --git a/tutorial/devops/what.md b/tutorial/devops/what.md index 550bc66..2b8cb33 100644 --- a/tutorial/devops/what.md +++ b/tutorial/devops/what.md @@ -1,64 +1,25 @@ \newpage -But du TP -========= +La journée DevOps +================= -Nous allons nous mettre aujourd'hui dans la peau d'une équipe DevOps et +Nous allons maintenant nous mettre dans la peau d'une équipe DevOps et réaliser une solution complète d'intégration/déploiement continu (le fameux CI/CD, pour *Continuous Integration* et *Continuous Delivery*). Le résultat attendu d'ici la fin de cette partie sera de mettre en place toutes -les briques décrites dans la section précédente. -\ - -Nous allons commencer par automatiser le projet `youp0m`, plus simple, ~~puis -la plate-forme du FIC dans son ensemble, ce qui représente un petit challenge~~ -(merci Nabih !). - -Il est également attendu que vous rendiez un playbook Ansible, permettant de -retrouver un environnement similaire. Car on pourra s'en resservir par la suite. +les briques décrites au chapitre précédent. Nous allons pour cela automatiser +le projet `youp0m`, que l'on connaît déjà bien. \ Dans un premier temps, on voudra juste compiler notre projet, pour s'assurer -que chaque commit poussé ne contient pas d'erreur de compilation, dans -l'environnement défini comme étant celui de production. Ensuite, on ajoutera -quelques tests automatiques. Puis nous publierons automatiquement le binaire -`youp0m` comme fichier associé à un tag au sein de l'interface web du -gestionnaire de versions. +que chaque *commmit* poussé ne contient pas d'erreur de compilation (dans +l'environnement défini comme étant celui de production, donc avec une version +précise des outils de compilation). Ensuite, nous ajouterons quelques tests +automatiques, puis nous publierons automatiquement le binaire `youp0m` comme +fichier associé à un tag au sein de l'interface web d'un gestionnaire de +versions. Enfin, nous mettrons en place un registre Docker qui nous permettra de publier automatiquement l'image Docker associée. C'est à partir de cette image Docker que l'on va commencer à déployer automatiquement... - - -## Préparer le terrain - -Tous les déploiements sont à faire sur votre machine en utilisant des -conteneurs Docker, qui seront regroupés au sein de réseaux Docker. Cela vous -permettra d'utiliser la résolution de noms entre vos conteneurs. - -Dans votre playbook Ansible, vous pourrez procéder ainsi : - -
-```yaml -- name: Create virli network - docker_network: - name: virli3 -``` -
- - -Étant donné que votre machine ne dispose pas de domaine sur Internet et que -l'on va essayer de simplifier au maximum l'installation, vous devriez ajouter -cette ligne à votre fichier `/etc/hosts` (ou -`\Windows\System32\drivers\etc\hosts`) : - -
-```conf -127.0.0.1 gitea droneci -``` -
- -Cette ligne va vous permettre de résoudre les noms des conteneurs. Cela -permettra aux requêtes OAuth de se faire de manière transparente pour vous -lorsque vous serez dans votre navigateur. diff --git a/tutorial/docker-advanced/compose.md b/tutorial/docker-advanced/compose.md index 07978d1..864af3d 100644 --- a/tutorial/docker-advanced/compose.md +++ b/tutorial/docker-advanced/compose.md @@ -57,7 +57,7 @@ run`. Cette section est le pendant de la commandes `docker volume`. On déclare les volumes simplement en leur donnant un nom et un driver comme -suit : +suit :
```yaml @@ -68,7 +68,7 @@ volumes:
Pour les utiliser avec un conteneur, on référence le nom ainsi que -l'emplacement à partager : +l'emplacement à partager :
```yaml @@ -87,10 +87,10 @@ Cette section est le pendant de la commandes `docker network`. Par défaut, Docker relie tous les conteneurs sur un bridge et fait du NAT pour que les conteneurs puissent accéder à l'Internet. Mais ce n'est pas le seul -mode possible ! +mode possible ! De la même manière que pour les `volumes`, cette section déclare les réseaux -qui pourront être utilisés par les `services`. On pourrait donc avoir : +qui pourront être utilisés par les `services`. On pourrait donc avoir :
```yaml @@ -133,12 +133,14 @@ lié, même après que l'on ait démarré. La résolution se fera dynamiquement. #### Utiliser le `docker-compose.yml` -Consultez -[la documentation](https://docs.docker.com/compose/compose-file/) pour -une liste exhaustive des options que nous pouvons utiliser. +Consultez la documentation[^COMPOSEDOC] pour une liste exhaustive des options +que nous pouvons utiliser. + +[^COMPOSEDOC]: La documentation des `docker-compose.yml` : + Une fois que notre `docker-compose.yml` est prêt, nous pouvons lancer -la commande suivante et admirer le résultat : +la commande suivante et admirer le résultat :
```bash diff --git a/tutorial/docker-advanced/manual.md b/tutorial/docker-advanced/manual.md index 771c665..b5db30c 100644 --- a/tutorial/docker-advanced/manual.md +++ b/tutorial/docker-advanced/manual.md @@ -6,9 +6,8 @@ Lier des conteneurs Avant de voir des méthodes plus automatiques pour déployer toute notre pile logicielle TICK, nous allons commencer par mettre en place et lier les conteneurs manuellement, de la même manière que nous avons pu le faire avec -l'interface d'administration du FIC et MySQL. Cela nous permettra de voir les -subtilités de chaque image, ce qui nous fera gagner du temps pour ensuite -en faire la description. +MySQL. Cela nous permettra de voir les subtilités de chaque image, ce qui nous +fera gagner du temps pour ensuite en faire la description. ### Conteneur central : la base de données @@ -58,7 +57,8 @@ le client officiel (le binaire s'appelle `influx`) :
``` -42sh$ docker container run --rm -it --link mytsdb:influxdb influxdb:1.8 influx -host influxdb +42sh$ docker container run --rm -it --link mytsdb:influxdb influxdb:1.8 \ + influx -host influxdb Connected to http://influxdb:8086 version 1.8.9 InfluxDB shell version: 1.8.9 > show databases @@ -69,10 +69,10 @@ _internal ```
-Si vous aussi vous voyez la table `_internal`, bravo ! vous pouvez passer à la +Si vous aussi vous voyez la table `_internal`, bravo ! vous pouvez passer à la suite. -#### Mais quelle était cette commande magique ? {-} +#### Mais quelle était cette commande magique ? {-} Oui, prenons quelques minutes pour l'analyser ... @@ -132,7 +132,9 @@ système. Pour cela, on commence par télécharger *Telegraf* :
```bash -curl https://dl.influxdata.com/telegraf/releases/telegraf-1.19.2_linux_amd64.tar.gz | \ +V=1.19.2 +P=telegraf-${V}_linux_$(uname -m) +curl https://dl.influxdata.com/telegraf/releases/${P}.tar.gz | \ tar xzv -C /tmp ```
@@ -157,7 +159,8 @@ Et observons ensuite :
```bash -42sh$ docker container run --rm -it --link mytsdb:zelda influxdb:1.8 influx -host zelda +42sh$ docker container run --rm -it --link mytsdb:zelda influxdb:1.8 \ + influx -host zelda InfluxDB shell version: 1.8.9 > show databases name: databases @@ -205,6 +208,6 @@ si besoin. la page d'accueil est vide au démarrage, pour savoir si vous avez réussi, rendez-vous sous l'onglet *Hosts*, le nom de votre machine devrait y apparaître. En cliquant dessus, vous obtiendrez des graphiques similaires à -ceux ci-dessous : +ceux ci-après : ![Résultat obtenu](chronograf_latest.png) diff --git a/tutorial/docker-advanced/rendu.md b/tutorial/docker-advanced/rendu.md index da25c27..f41d796 100644 --- a/tutorial/docker-advanced/rendu.md +++ b/tutorial/docker-advanced/rendu.md @@ -7,7 +7,7 @@ Projet ------ Réalisez le `docker-compose.yml` permettant de lancer toute notre stack de -monitoring, d'un simple : +monitoring, d'un simple :
``` @@ -49,10 +49,10 @@ Tarball ------- Tous les fichiers identifiés comme étant à rendre pour ce TP sont à -placer dans une tarball (pas d'archive ZIP, RAR, ...). +placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (vous pourriez avoir des fichiers supplémentaires, -cela dépendra de votre avancée dans le projet) : +cela dépendra de votre avancée dans le projet) :
``` @@ -66,7 +66,7 @@ login_x-TP1/... ## Signature du rendu -Deux méthodes sont utilisables pour signer votre rendu : +Deux méthodes sont utilisables pour signer votre rendu : * signature du courriel ; * signature de la tarball. @@ -93,7 +93,7 @@ signature. #### No public key -Si vous recevez un rapport avec l'erreur suivante : +Si vous recevez un rapport avec l'erreur suivante :
``` @@ -116,7 +116,7 @@ rendu. #### Not explicit username -Si vous recevez un rapport avec l'erreur suivante : +Si vous recevez un rapport avec l'erreur suivante :
``` @@ -131,7 +131,7 @@ données. #### I've decided to skip your e-mail -Si vous recevez un rapport concluant ainsi : +Si vous recevez un rapport concluant ainsi :
``` diff --git a/tutorial/docker-advanced/security.md b/tutorial/docker-advanced/security.md index 0f7326a..31cecfe 100644 --- a/tutorial/docker-advanced/security.md +++ b/tutorial/docker-advanced/security.md @@ -5,7 +5,7 @@ Contenir les applications pour éviter les fuites Lorsque l'on gère un environnement de production, on souhaite bien évidemment éviter tout déni de service. Ou parfois, contenir un -programme métier avec une fuite mémoire, dans certaines limites : il +programme métier avec une fuite mémoire, dans certaines limites : il vaut parfois mieux le tuer et le relancer automatiquement, plutôt que d'attendre que potentiellement un autre processus se fasse tuer à sa place. @@ -44,7 +44,7 @@ l'ordonnanceur privilégiant alors les autres processus du système. Par défaut, le taux maximal (1024 = 100%) d'utilisation CPU est donné aux nouveaux conteneurs, on peut le réduire en utilisant l'option -`-c`/`--cpu-shares` : 512 = 50%, par exemple. +`-c`/`--cpu-shares` : 512 = 50%, par exemple. ## Sécuriser l'exécution @@ -76,14 +76,14 @@ du noyau, seccomp est un filtre que l'on peut définir pour chaque appel système. Liste blanche, liste noire, tout est possible. Docker filtre notamment tous les appels systèmes qui pourraient -déborder à l'extérieur du conteneur : il n'est par exemple pas +déborder à l'extérieur du conteneur : il n'est par exemple pas possible de changer l'heure dans un conteneur, car il n'y a aujourd'hui aucun mécanisme pour isoler les visions des dates d'un conteneur à l'autre. Voici par exemple un fichier de profil seccomp, interdisant l'utilisation de l'appel système `nanosleep(2)` (utilisé notamment par -`sleep(1)`) : +`sleep(1)`) :
```js @@ -105,11 +105,11 @@ l'utilisation de l'appel système `nanosleep(2)` (utilisé notamment par ```
-On peut ensuite l'appliquer à un conteneur Docker : +On peut ensuite l'appliquer à un conteneur Docker :
``` -42sh$ docker container run -it --security-opt seccomp=nanosleep.json ubuntu /bin/bash +42sh$ docker run -it --security-opt seccomp=nanosleep.json ubuntu /bin/bash (cntnr)$ sleep 42 sleep: cannot read realtime clock: Operation not permitted ``` diff --git a/tutorial/docker-advanced/setup.md b/tutorial/docker-advanced/setup.md index 188f46c..b70aa5a 100644 --- a/tutorial/docker-advanced/setup.md +++ b/tutorial/docker-advanced/setup.md @@ -3,11 +3,10 @@ Mise en place ------------- -Dans la première partie du TP, nous avons installé l'environnement Docker -principal, qui inclut le client, le daemon et toute sa machinerie. Mais le -projet Docker propose de nombreuses autres ressources, souvent directement -trouvées dans les usages de la communauté, et parfois même appropriées par -Docker. +Jusqu'ici, nous avons utilisé l'environnement Docker principal, qui inclut le +client, le daemon et toute sa machinerie. Mais le projet Docker propose de +nombreuses extensions, souvent directement trouvées dans les usages de la +communauté, et parfois même appropriées par Docker. ### `docker-compose` @@ -16,8 +15,8 @@ Dans cette partie, nous allons avoir besoin de `docker-compose`. Ce projet ne bénéficie pas d'une intégration au sein du projet Docker et doit être téléchargé séparément, car originellement, le projet était développé par -une équipe indépendante. Il constitue aujourd'hui une brique de l'écosystème -Docker, presque indispensable ! +une équipe indépendante (et en Python). Il constitue aujourd'hui une brique de +l'écosystème Docker, presque indispensable ! #### Par le gestionnaire de paquets @@ -26,28 +25,17 @@ fonctionnera avec la version de Docker qu'ils fournissent. #### Par la distribution binaire -L'équipe en charge de Docker compose met à disposition un exécutable contenant -tous les scripts. Nous pouvons l'installer en suivant la procédure suivante : +L'équipe en charge du projet met à disposition un exécutable que nous pouvons +téléchargeant depuis . -
-```bash -curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64 \ - > /usr/bin/docker-compose -chmod +x /usr/bin/docker-compose -``` -
- -#### `pip` - -Le projet étant écrit en Python, il est également disponible via `pip`, si vous -préférez cette méthode. N'oubliez pas de préciser une version compatible avec -votre version de Docker. +Ajoutez l'exécutable dans le dossier des plugins : `$HOME/.docker/cli-plugins` +(sans oublier de `chmod +x` !). #### Vérification du fonctionnement Comme avec Docker, nous pouvons vérifier le bon fonctionnement de -`docker-compose` en exécutant la commande : +`docker-compose` en exécutant la commande :
``` @@ -56,13 +44,13 @@ docker-compose version: 1.29.2 ```
-Si vous obtenez une réponse similaire, c'est que vous êtes prêt à commencer le -TP ! Alors n'attendons pas, partons à l'aventure ! +Si vous obtenez une réponse similaire, c'est que vous êtes prêt à continuer ! +Alors n'attendons pas, partons à l'aventure ! ### Play With Docker Tout comme pour la partie précédente, si vous avez des difficultés pour -réaliser les exercices sur vos machines, vous pouvez utiliser le projet [Play +réaliser les exercices sur votre machine, vous pouvez utiliser le projet [Play With Docker](https://play-with-docker.com/) qui vous donnera accès à un bac à -sable avec lequel vous pourrez réaliser tous les exercices de ce TP. +sable avec lequel vous pourrez réaliser tous les exercices. diff --git a/tutorial/docker-advanced/tutorial.md b/tutorial/docker-advanced/tutorial.md index 9ae5026..4e49a12 100644 --- a/tutorial/docker-advanced/tutorial.md +++ b/tutorial/docker-advanced/tutorial.md @@ -6,7 +6,7 @@ institute: EPITA date: Mercredi 2 octobre 2019 abstract: | Dans cette deuxième partie du TP, nous allons apprendre à déployer - un groupe de conteneurs ! + un groupe de conteneurs ! \vspace{1em} diff --git a/tutorial/docker-advanced/what.md b/tutorial/docker-advanced/what.md index 380051d..c577fd0 100644 --- a/tutorial/docker-advanced/what.md +++ b/tutorial/docker-advanced/what.md @@ -6,9 +6,9 @@ Orchestrer un groupe de conteneurs Maintenant que nous savons démarrer individuellement des conteneurs et les lier entre-eux, nous allons voir une première manière d'automatiser cela. -Plutôt que de lancer les commandes `docker` comme nous l'avons fait jusque là : +Plutôt que de lancer les commandes `docker` comme nous l'avons fait jusque là : soit directement dans un terminal, soit via un script, nous allons décrire -l'état que nous souhaitons atteindre : quels images lancer, quels volumes +l'état que nous souhaitons atteindre : quels images lancer, quels volumes créer, quels réseaux, etc. Cette description peut s'utiliser pour lancer un conteneur seul, mais elle prend tout son sens lorsqu'il faut démarrer tout un groupe de conteneurs qui fonctionnent de concert, parfois avec des dépendances @@ -16,7 +16,7 @@ groupe de conteneurs qui fonctionnent de concert, parfois avec des dépendances démarrer). On parle d'orchestration, car nous allons utiliser Docker comme un chef -d'orchestre : il va ordonner les créations des différents objets (volumes, +d'orchestre : il va ordonner les créations des différents objets (volumes, réseaux, conteneurs, ...) afin d'arriver au résultat attendu, puis il va faire en sorte de maintenir ce résultat selon les événements qui pourront survenir. diff --git a/tutorial/docker-basis/Makefile b/tutorial/docker-basis/Makefile index 9f71daa..8e23792 100644 --- a/tutorial/docker-basis/Makefile +++ b/tutorial/docker-basis/Makefile @@ -1,6 +1,6 @@ include ../pandoc-opts.mk -SOURCES = tutorial.md installation.md what.md first.md cleaning.md ex-flask.md volumes.md linking.md +SOURCES = tutorial.md installation.md what.md first.md cleaning.md ex-flask.md volumes.md linking.md linking-ex-fic.md linking-ex-help.md all: tutorial.pdf diff --git a/tutorial/docker-basis/cleaning.md b/tutorial/docker-basis/cleaning.md index fb4d76f..ae6c2c2 100644 --- a/tutorial/docker-basis/cleaning.md +++ b/tutorial/docker-basis/cleaning.md @@ -17,19 +17,19 @@ l'option `--rm`. ### Conteneurs Nous pouvons afficher l'ensemble des conteneurs, quel que soit leur état (en -cours d'exécution, arrêtés,\ ...) avec la commande suivante : +cours d'exécution, arrêtés, ...) avec la commande suivante :
``` 42sh$ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES -552d71619723 hello-world "/hello" 4 days ago Exited (0) 4 days ago dreamy_gates -0e8bbff6d500 debian "/bin/bash" 2 weeks ago Exited (0) 2 weeks ago cranky_jones +552d71619723 hello-world "/hello" 4 days ago Exited (0) 4 days ago dreamy_g +0e8bbff6d500 debian "/bin/bash" 2 weeks ago Exited (0) 2 weeks ago cranky_j ```
Il y a de fortes chances pour que vous n'ayez plus besoin de ces vieux -conteneurs. Pour les supprimer, utilisez la commande : +conteneurs. Pour les supprimer, utilisez la commande :
```bash @@ -37,7 +37,7 @@ docker container rm 0e8bbff6d500 552d71619723 ```
-ou encore : +ou encore :
```bash @@ -57,7 +57,7 @@ de la même manière que les conteneurs, avec les sous-commandes `docker image`. ### `prune` Dans la plupart des menus permettant de gérer les objets Docker, vous trouverez -une commande `prune` qui supprimera les objets inutilisés : +une commande `prune` qui supprimera les objets inutilisés :
```bash @@ -65,7 +65,7 @@ docker container prune ```
-On aura tendance à vouloir supprimer tous les objets inutiles d'un seul coup, via : +On aura tendance à vouloir supprimer tous les objets inutiles d'un seul coup, via :
```bash diff --git a/tutorial/docker-basis/discover.md b/tutorial/docker-basis/discover.md index d779590..69494bd 100644 --- a/tutorial/docker-basis/discover.md +++ b/tutorial/docker-basis/discover.md @@ -2,3 +2,15 @@ Découvrons Docker ================= + +Entrons sans plus attendre dans le vif du sujet : Docker. + +Ce projet, dont les sources ont été rendues libres en 2013, a tout de +suite remporté un engouement indéniable. Le projet a énormément grossi +depuis, et il s'est aussi bien stabilisé. Aujourd'hui de nombreuses +entreprises n'hésitent plus à l'utiliser en production. + +Dans ce chapitre, nous allons partir à la découverte de cet outil : +après l'avoir installé, nous apprendrons d'abord les concepts clefs puis +nous lancerons notre premier conteneur et nous irons jusqu'à déployer +un premier service web avec lequel nous pourrons interagir. diff --git a/tutorial/docker-basis/ex-flask.md b/tutorial/docker-basis/ex-flask.md index 8e80950..da34f12 100644 --- a/tutorial/docker-basis/ex-flask.md +++ b/tutorial/docker-basis/ex-flask.md @@ -3,13 +3,13 @@ Mon premier webservice ---------------------- -C'est parti, nous allons déployer notre premier service ! +C'est parti, nous allons déployer notre premier service ! Il s'agit d'un service montrant une image aléatoire à chaque chargement de -page : . +page : . -Nous pouvons télécharger et lancer le service grâce à : +Nous pouvons télécharger et lancer le service grâce à :
```bash @@ -17,22 +17,22 @@ docker container run -i nemunaire/youp0m ```
-Cette fois-ci, ce n'est pas un shell que nous obtenons[^defaultcmd] : il semblerait que le -service soit lancé et écoute sur le port 8080. Est-ce le cas ? +Cette fois-ci, ce n'est pas un shell que nous obtenons[^defaultcmd] : il semblerait que le +service soit lancé et écoute sur le port 8080. Est-ce le cas ? -[^defaultcmd]: Chaque conteneur dispose d'une commande par défaut : les images +[^defaultcmd]: Chaque conteneur dispose d'une commande par défaut : les images de base telles que les distributions vont lancer un shell, tandis que les conteneurs de service vont lancer leur service directement. -Non ! Car le service est contenerisé ! Il s'exécute dans son coin, sans +Non ! Car le service est contenerisé ! Il s'exécute dans son coin, sans interférer avec son hôte. ### Redirection de ports -Nous pouvons rediriger le port avec l'argument `-p dst_host:src_cntr` : +Nous pouvons rediriger le port avec l'argument `-p dst_host:src_cntr` :
```bash @@ -43,7 +43,7 @@ docker container run -i -p 8080:8080 nemunaire/youp0m Cette fois, nous pouvons accéder au service. Pour le moment, le service ne dispose d'aucune image à afficher, vous pouvez -utiliser cette syntaxe pour ajouter une image : +utiliser cette syntaxe pour ajouter une image :
```bash @@ -51,7 +51,7 @@ base64 monimage.jpg | curl --data @- http://localhost:8080/api/images/monimage ```
-Si vous n'êtes pas particulièrement inspiré, vous pouvez ajouter ces images : +Si vous n'êtes pas particulièrement inspiré, vous pouvez ajouter ces images :
```bash @@ -63,13 +63,13 @@ done
-### Prêt pour la production ? +### Prêt pour la production ? Avec l'option `-i`, nous pouvons encore transmettre les signaux de terminaison au conteneur. C'est pratique lorsque l'on développe, mais en production, notre -service ne s'exécutera pas dans notre terminal ! +service ne s'exécutera pas dans notre terminal ! -On utilise l'option `-d` pour lancer le conteneur en tâche de fond : +On utilise l'option `-d` pour lancer le conteneur en tâche de fond :
```bash @@ -79,7 +79,7 @@ docker container run -d -p 8080:8080 nemunaire/youp0m À partir de l'identifiant renvoyé par cette commande (que l'on peut également obtenir avec un `docker container ls`), nous pouvons consulter les logs du -service (en fait, les sorties standard et d'erreur) : +service (en fait, les sorties standard et d'erreur) :
```bash @@ -88,15 +88,15 @@ docker container logs 0123456789abcdef
-### Une autre instance ? +### Une autre instance ? Maintenant que nous avons un clone de , nous voulons -absolument un clone de ! +absolument un clone de  ! Il s'agit du même service, mais ce ne sont pas les mêmes images. On ne peut pas utiliser le même port sur la machine hôte, mais pour le reste, -il s'agit des mêmes options\ : +il s'agit des mêmes options\ :
```bash @@ -104,10 +104,10 @@ docker container run -d -p 8081:8080 nemunaire/youp0m ```
-Voyons le résultat : +Voyons le résultat : Nous avons réussi à lancer deux conteneurs à partir de la même image, et on -voit bien que ceux-ci ne partagent pas leur système de fichiers : notre +voit bien que ceux-ci ne partagent pas leur système de fichiers : notre nouvelle instance est encore immaculée. @@ -123,18 +123,19 @@ Outre les arguments que l'on peut passer au premier processus du conteneur, la plupart des images peuvent adapter leur comportement en fonction de variables d'environnement que l'on passe en paramètre. -Cette bonne pratique est recommandée par , qui détaille -les raisons qui devraient pousser les développeurs à privilégier les variables -d'environnements aux arguments sur la ligne de commande. +Cette bonne pratique est recommandée par +[`12factor.net`](https://12factor.net/), qui détaille les raisons qui devraient +pousser les développeurs à privilégier les variables d'environnements aux +arguments sur la ligne de commande. Il se trouve que les conteneurs `youp0m` peuvent créer le fichier `htpasswd`, -s'ils sont démarrés avec les variables d'environnement : +s'ils sont démarrés avec les variables d'environnement : - - `YOUP0M_USERNAME` : nom d'utilisateur pour l'administrateur (par défaut admin) ; - - `YOUP0M_PASSWORD` : mot de passe de l'utilisateur. + - `YOUP0M_USERNAME` : nom d'utilisateur pour l'administrateur (par défaut admin) ; + - `YOUP0M_PASSWORD` : mot de passe de l'utilisateur. Pour ajouter une variable d'environnement, cela se passe dans la commande -`run`, en ajoutant une ou plusieurs options `-e` : +`run`, en ajoutant une ou plusieurs options `-e` :
```bash @@ -143,13 +144,14 @@ docker container run -e YOUP0M_PASSWORD=foobar -p 8080:8080 nemunaire/youp0m
Une fois lancé, ce conteneur exposera une interface d'administration à cette -adresse : . +adresse :\ +. ### Arrêt des conteneurs et persistance des données Lorsque l'on souhaite stopper un conteneur lancé en tâche de fond, on utilise -son identifiant dans la commande suivante : +son identifiant dans la commande suivante :
```bash diff --git a/tutorial/docker-basis/ex-owncloud.md b/tutorial/docker-basis/ex-owncloud.md index ebaee74..4f33bf4 100644 --- a/tutorial/docker-basis/ex-owncloud.md +++ b/tutorial/docker-basis/ex-owncloud.md @@ -1,7 +1,5 @@ -\newpage - -Exercice -======== +Exercice {-} +-------- Pour mettre en pratiques toutes les notions que l'on a vu jusque là, écrivez un script `mycloud-run.sh` pour automatiser le lancement de votre instance @@ -16,25 +14,26 @@ pour se rendre sur la page de connexion. Une autre machine de votre réseau local devrait également pouvoir accéder à la plate-forme, simplement en renseignant l'IP de votre machine et en ajoutant éventuellement des règles de pare-feu (mais cette dernière partie n'est pas demandée, gardez simplement en -tête que cela doit pouvoir être fait manuellement au cas par cas : sur une +tête que cela doit pouvoir être fait manuellement au cas par cas : sur une machine sans pare-feu configurée, cela ne demande pas d'étape supplémentaire). Votre script devra se limiter aux notions vues durant cette partie du TP -(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra dans la -seconde partie). Il pourra cependant faire usage des commandes `docker OBJECT -inspect` pour ne pas avoir à faire d'analyse syntaxique sur les retours des -commandes lisibles par les humains. +(ie. sans utiliser `docker-compose` ou `docker stack` que l'on verra par la +suite). Il pourra cependant faire usage des commandes `docker OBJECT inspect` +pour ne pas avoir à faire d'analyse syntaxique sur les retours des commandes +lisibles par les humains. -Cette instance devra utiliser une base de données MySQL (lancée par vos soins -dans un autre conteneur) et contenir ses données dans un ou plusieurs volumes -(afin qu'elles persistent à une mise à jour des conteneurs par exemple). +Cette instance devra utiliser une base de données MySQL (lancée par votre +script dans un autre conteneur) et contenir ses données dans un ou plusieurs +volumes (afin qu'elles persistent à une mise à jour des conteneurs par +exemple). L'exécution doit être la plus sécurisée possible (pas de port MySQL exposé sur l'hôte par exemple, etc.) et la plus respectueuse des bonnes pratiques que l'on -a pu voir durant ce premier cours. +a pu voir jusque là. -### Exemple d'exécution +### Exemple d'exécution {-}
```bash diff --git a/tutorial/docker-basis/first.md b/tutorial/docker-basis/first.md index 1ae0d08..b415962 100644 --- a/tutorial/docker-basis/first.md +++ b/tutorial/docker-basis/first.md @@ -4,7 +4,7 @@ Mon premier conteneur --------------------- Afin de tester la bonne marche de notre installation, lançons notre premier -conteneur avec la commande\ : +conteneur avec la commande :
```bash @@ -13,7 +13,7 @@ docker container run hello-world
Cette commande va automatiquement exécuter une série d'actions pour nous, -comme indiqué dans le message affiché en retour : +comme indiqué dans le message affiché en retour : D'abord, le daemon va rechercher s'il possède localement l'image *hello-world*. Si ce n'est pas le cas, il va aller récupérer les différentes @@ -23,7 +23,7 @@ conteneur. Enfin, il lance la commande par défaut, telle que définie dans les métadonnées de l'image. Nous pouvons directement utiliser le client pour rechercher une image sur le -registre, en utilisant la commande `search` : +registre, en utilisant la commande `search` :
```bash @@ -32,7 +32,7 @@ docker search mariadb
Il est possible de mettre à jour les images locales, ou télécharger les couches -d'images qui nous intéressent, en utilisant la commande `pull` : +d'images qui nous intéressent, en utilisant la commande `pull` :
```bash @@ -41,40 +41,42 @@ docker image pull ubuntu
-#### Attention {-} +::::: {.warning} Les registres publics tels quel le Docker Hub mettent à disposition des images -officielles, mais aussi des images créés par la communauté. Chaque utilisateur -est libre d'envoyer une image qu'il a lui-même créée : soit car l'éditeur ne +officielles, mais aussi des images créées par la communauté. Chaque utilisateur +est libre d'envoyer une image qu'il a lui-même créé : soit car l'éditeur ne proposait pas d'image et que quelqu'un s'est dévoué pour la faire, soit parce qu'il avait des besoins plus spécifiques qui n'étaient pas couvert par l'image originale. Il est important de garder en tête que vous téléchargez des exécutables, et bien qu'ils s'exécutent dans un environnement isolé, ils -peuvent contenir du code malveillant. **De la même manière que vous devez être -attentif aux binaires que vous exécutez sur votre machine et au contexte de -leurs téléchargements, ici assurez-vous d'avoir confiance dans la personne -affiliée à l'image.** +peuvent contenir du code malveillant. +**De la même manière que vous devez être attentif aux binaires que vous +exécutez sur votre machine et au contexte de leurs téléchargements, ici +assurez-vous d'avoir confiance dans la personne affiliée à l'image.** + +::::: ### Arguments de la ligne de commande -Remarquez comment on interagit avec chaque *objet Docker* : dans la ligne de +Remarquez comment on interagit avec chaque *objet Docker* : dans la ligne de commande, le premier mot clef est le type d'objet (`container`, `image`, -`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on +`service`, `network`, `volume`, ...) ; ensuite, vient l'action que l'on souhaite faire dans ce cadre.[^oldcall] [^oldcall]: cela n'a pas toujours été aussi simple, cette syntaxe n'existe que depuis la version 1.13 (janvier 2017). C'est pourquoi, lorsque vous ferez des recherches sur internet, vous trouverez de nombreux articles utilisant - l'ancienne syntaxe, sans le type d'objets : `docker images` au lieu de - `docker image ls`, `docker run` au lieu de `docker container run`, ... + l'ancienne syntaxe, sans le type d'objets : `docker images` au lieu de + `docker image ls`, `docker run` au lieu de `docker container run`, ... L'ancienne syntaxe est dépréciée, mais il reste actuellement possible de l'utiliser. Par exemple, pour consulter la liste des images dont nous disposons localement (soit parce qu'on les a téléchargées, soit parce que nous les avons créées -nous-même), on utilise la commande `ls` sous le type d'objets `image` : +nous-même), on utilise la commande `ls` sous le type d'objets `image` :
```bash @@ -85,24 +87,26 @@ docker image ls ### *Image ID*, nom, tag -Chaque image est identifiable par son *Image ID* : il s'agit d'un long +Chaque image est identifiable par son *Image ID* : il s'agit d'un long identifiant unique. Chaque modification qui est apportée à l'image générera un *Image ID* différent. Un peu comme un identifiant de commit dans Git. -Pour s'y retrouver, on utilise habituellement les noms des images : +Pour s'y retrouver, on utilise habituellement les noms des images : `hello-world` est ainsi le nom de l'image `1b26826f602946860c279fce658f31050cff2c596583af237d971f4629b57792`. -Lorsque, comme dans le cas d'Ubuntu, il y a plusieurs *versions* -disponibles, il est possible de préciser la version au moyen d'un -*tag*. En consultant [la -documentation](https://hub.docker.com/_/ubuntu) qui accompagne chaque -conteneur, nous pouvons constater la présence de plusieurs versions -d'Ubuntu : `trusty`, `xenial`, `focal` ou `bionic`. +Lorsque, comme dans le cas d'Ubuntu, il y a plusieurs *versions* disponibles, +il est possible de préciser la version au moyen d'un *tag*. En consultant la +documentation[^hubDocUbuntu] qui accompagne chaque conteneur, nous pouvons +constater la présence de plusieurs versions d'Ubuntu : `trusty`, `xenial`, +`focal` ou `bionic`. + +[^hubDocUbuntu]: Pour voir la documentation des images d'Ubuntu, consultez + Par convention, lorsque l'on souhaite désigner un tag en particulier, -on utilise la syntaxe suivante : +on utilise la syntaxe suivante :
``` @@ -110,7 +114,7 @@ ubuntu:focal ```
-Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera : +Par exemple, pour lancer un conteneur Ubuntu Focal, on utilisera :
``` @@ -119,7 +123,7 @@ docker container run ubuntu:focal
-Chaque nom d'image possède au moins un tag associé par défaut : *latest*. C'est +Chaque nom d'image possède au moins un tag associé par défaut : *latest*. C'est le tag qui est automatiquement recherché lorsque l'on ne le précise pas en lançant l'image. @@ -127,11 +131,11 @@ lançant l'image. ### Exécuter un programme dans un conteneur Maintenant que nous avons à notre disposition l'image d'un conteneur Ubuntu, -nous allons pouvoir jouer avec ! +nous allons pouvoir jouer avec ! La commande `run` de Docker prend comme derniers arguments le programme à lancer dans le conteneur ainsi que ses éventuels arguments. Essayons d'afficher -un Hello World : +un Hello World :
```bash @@ -146,7 +150,7 @@ transféré dans le conteneur. Pour nous en convaincre, nous pouvons tenter d'exécuter un programme qui n'est pas présent sur notre machine, mais bien uniquement dans le conteneur. Si vous n'utilisez pas [Alpine Linux](https://www.alpinelinux.org), vous pourriez -tenter d'utiliser son gestionnaire de paquet `apk`, via : +tenter d'utiliser son gestionnaire de paquet `apk`, via :
```bash @@ -184,7 +188,7 @@ programme à exécuter par défaut si l'on ne le précise pas dans la ligne de commande. C'est grâce à cela que vous n'avez pas eu besoin de préciser de programme -lorsque vous avez lancé l'image `hello-world` : +lorsque vous avez lancé l'image `hello-world` :
```bash @@ -193,7 +197,7 @@ docker container run hello-world
Il est commun que le programme le plus attendu/approprié soit lancé par défaut, -il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello` : +il est donc tout naturel que pour l'image `hello-world`, ce soit `/hello` :
```bash @@ -201,20 +205,21 @@ docker container run hello-world /hello ```
-L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell : +L'image ne contenant que ce programme, vous ne pourrez pas y lancer de shell :
-```bash +``` 42sh$ docker container run hello-world /bin/sh -docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: - starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown. +docker: Error response from daemon: OCI runtime create failed: + container_linux.go:349: starting container process caused + "exec: \"/bin/sh\": stat /bin/sh: no such file or directory" ```
Pour les images `alpine` et `ubuntu`, le programme par défaut est un shell (`/bin/ash` pour `alpine` et `/bin/bash` pour `ubuntu`), mais il y a une -subtilité : il faut ajouter les options `--interactive` et `--tty` pour ne pas -que `docker` nous rende la main tout de suite : +subtilité : il faut ajouter les options `--interactive` et `--tty` pour ne pas +que `docker` nous rende la main tout de suite :
```bash @@ -239,7 +244,7 @@ s'assure que l'entrée standard ne sera pas fermée (`close(2)`). Nous demandons interractif[^bashnointer]. [^bashnointer]: Mais il sera possible de l'utiliser sans allouer de TTY, comme - dans cet exemple : + dans cet exemple :
``` @@ -253,7 +258,7 @@ interractif[^bashnointer]. L'option `-i` reste néanmoins nécessaire pour que l'entrée standard soit transmise au conteneur. -Rassurez-vous, on peut les abbréger en `-i` et `-t` : +Rassurez-vous, on peut les abréger en `-i` et `-t` :
```bash @@ -265,22 +270,22 @@ Rassurez-vous, on peut les abbréger en `-i` et `-t` : ### Les paramètres -Vous avez remarqué le placement des options `--tty` et `--interactive` ? Avant +Vous avez remarqué le placement des options `--tty` et `--interactive` ? Avant le nom de l'image, elles sont utilisées par Docker pour modifier le comportement du `run`. En fait, tout comme `git(1)` et ses sous-commandes, chaque niveau de -commande peut prendre des paramètres : +commande peut prendre des paramètres :
```bash -docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS ... +docker DOCKER_PARAMS container run RUN_OPTS image IMAGE_CMD IMAGE_ARGS … ```
-Par exemple : +Par exemple :
```bash -docker -H unix:///var/run/docker.sock container run -it alpine /bin/ash -c "echo foo" +docker -H unix:///run/docker.sock container run -it alpine /bin/ash -c "echo foo" ```
@@ -295,13 +300,13 @@ conteneur. Avant de quitter notre conteneur, regardons, à l'aide d'un autre terminal, l'état de notre conteneur. La commande suivante permet d'obtenir la liste des -conteneurs en cours d'exécution : +conteneurs en cours d'exécution :
``` 42sh$ docker container ls -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes suspicious_galileo +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +4c39fc049cd1 ubuntu "/bin/bash" 6 minutes ago Up 5 minutes bold_gates ```
diff --git a/tutorial/docker-basis/installation.md b/tutorial/docker-basis/installation.md index fd67c35..707cdaf 100644 --- a/tutorial/docker-basis/installation.md +++ b/tutorial/docker-basis/installation.md @@ -1,24 +1,16 @@ -\newpage - Installation ------------ -Avant de voir de quoi il s'agit, afin de gagner du temps, nous allons commencer -par installer Docker. - -### Prérequis - -Docker repose sur plusieurs techniques implémentées dans les récents noyaux -Linux (et plus marginalement, Windows). Nous consacrerons les prochains cours à -comprendre leur fonctionnement. Ces techniques, contrairement aux instructions -de virtualisation qui rendent les hyperviseurs attractifs, ne sont pas limitées -à une architecture de microprocesseur spécifique ; cependant la communauté -autour de Docker utilise principalement l'architecture `amd64`, c'est sur cette -dernière que Docker pourra être exploité à son plein potentiel, suivi de près -par l'architecture `arm64`. +Docker repose sur plusieurs techniques implémentées dans les noyaux Linux +récents (et plus marginalement, Windows). Ces techniques, contrairement aux +instructions de virtualisation qui rendent les hyperviseurs attractifs, ne sont +pas limitées à une architecture de microprocesseur spécifique ; cependant la +communauté autour de Docker utilise principalement l'architecture `amd64`, +c'est sur cette dernière que Docker pourra être exploité à son plein potentiel, +suivi de près par l'architecture `arm64`. Avant de continuer, assurez-vous que votre machine a bien démarré sur un noyau -64 bits. Le retour de la commande `uname -m` doit vous indiquer : +64 bits. Le retour de la commande `uname -m` doit vous indiquer :
``` @@ -26,7 +18,7 @@ x86_64 ```
-Ou si vous êtes intrépide : +Ou si vous êtes intrépide :
``` @@ -34,7 +26,7 @@ aarch64 ```
-Assurez-vous également d'avoir un noyau récent, avec la commande `uname -r` : +Assurez-vous également d'avoir un noyau récent, avec la commande `uname -r` :
``` @@ -46,53 +38,66 @@ Rassurez-vous, même si vous n'avez pas compilé le dernier noyau disponible sur [`kernel.org`](https://www.kernel.org/), Docker s'utilise à partir de Linux 3.10. -### Par le gestionnaire de paquets +### Sous Linux, par le gestionnaire de paquets En général, votre distribution mettra à votre disposition une version de Docker -plus ou moins récente. Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet +plus ou moins récente. Sous Debian et ses dérivés (Ubuntu, Mint, ...) le paquet a été nommé [`docker.io`](https://packages.debian.org/sid/docker.io). Si dans un environnement de production, on préférera sans doute utiliser une -version déjà bien éprouvée (comme celle des dépôts de sa distribution), pour ce -cours, nous allons avoir besoin de la **dernière version +version déjà bien éprouvée (comme celle des dépôts de sa distribution), pour +bien suivre les exemples, nous allons avoir besoin de la **dernière version disponible**. Référez-vous à la documentation officielle correspondant à votre -distribution : +distribution : -**Et Kali Linux alors ?** Kali étant basée sur Debian, référez-vous à +::::: {.question} + +**Et Kali Linux alors ?** Kali étant basée sur Debian, référez-vous à la procédure d'installation de cette distribution. +::::: -### Windows et macOS +### Sous Windows et macOS Bien que les fonctionnalités de contenerisation de Docker que nous utiliserons ne soient disponibles que sous Linux, il est possible d'utiliser Docker de -manière déportée : le daemon Docker tournera dans une VM Linux, mais vous -pourrez interagir avec lui via votre ligne de commande habituelle. +manière déportée : le daemon Docker tournera dans une machine virtuelle Linux, +mais vous pourrez interagir avec lui via votre ligne de commande habituelle. -Téléchargez la version correspondante à votre système d'exploitation : +Téléchargez la version correspondant à votre système d'exploitation : -* [Docker Desktop for Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac) -* [Docker Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows) +* Docker Desktop for Mac :\ + -Une fois l'installation terminée, lancez l'application : elle ajoutera une +* Docker Desktop for Windows :\ + + +Une fois l'installation terminée, lancez l'application : elle ajoutera une icône dans la zone de notification, vous permettant de contrôler l'exécution de la machine virtuelle sous-jacente. -Notez que depuis septembre 2021, ces applications passent sous une licence -payante pour les grosses entreprises[^DockerSubscription]. Cela ne nous -concerne pas, car la licence est gratuite pour un usage éducatif ou -personnel. Notez que ce n'est pas le binaire Docker qui change de licence, elle -reste libre, mais seulement les applications Docker Desktop. +::::: {.warning} + +Depuis septembre 2021, ces applications passent sous une licence payante pour +les grosses entreprises[^DockerSubscription]. Cela ne nous concerne pas, car la +licence est gratuite pour un usage éducatif ou personnel. + +Notez que cela ne concerne pas le projet ou le binaire Docker : ceux-ci restent +libres. Seules les applications Docker Desktop sont concernées. + +::::: [^DockerSubscription]: ### Évaluation en ligne -Si vous rencontrez des difficultés pour vous lancer, le projet -[Play With Docker](https://labs.play-with-docker.com/) vous donne accès à -un bac à sable dans lequel vous pourrez commencer à faire ce TP. +Si vous rencontrez des difficultés pour vous lancer, le projet Play With +Docker[^PlayWithDocker] vous donne accès à un bac à sable +dans lequel vous pourrez commencer à faire les exercices à suivre. + +[^PlayWithDocker]: Play With Docker est accessible à cette addresse : Il vous faudra disposer [d'un compte Docker](https://hub.docker.com/signup). Une fois identifié, vous pourrez créer @@ -101,7 +106,7 @@ une nouvelle instance, et vous connecter dessus via SSH. ### Vérifier la bonne marche de l'installation -Vous devriez maintenant être capable de lancer la commande suivante : +Vous devriez maintenant être capable de lancer la commande suivante :
```bash @@ -109,7 +114,7 @@ docker version ```
-Une sortie similaire au bloc suivant devrait apparaître sur votre écran : +Une sortie similaire au bloc suivant devrait apparaître sur votre écran :
``` @@ -149,8 +154,8 @@ Server: #### `no such file or directory`? -Si vous avez cette erreur : `dial unix /var/run/docker.sock: no such file or -directory.`, le deamon n'est sans doute pas lancé. Lancez-le : +Si vous avez cette erreur : `dial unix /var/run/docker.sock: no such file or +directory.`, le deamon n'est sans doute pas lancé. Lancez-le :
```bash @@ -161,9 +166,9 @@ sudo service docker restart #### `permission denied`? -Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission +Si vous avez cette erreur : `dial unix /var/run/docker.sock: permission denied.`, ajoutez votre utilisateur au groupe `docker` et **relancez votre -session** : +session** :
```bash @@ -171,5 +176,10 @@ sudo gpasswd -a $USER docker ```
-**Attention :** cette action n'est pas anodine d'un point de vue sécurité : +::::: {.warning} + +Cette action n'est pas anodine d'un point de vue de la sécurité : + + +::::: diff --git a/tutorial/docker-basis/linking-ex-fic.md b/tutorial/docker-basis/linking-ex-fic.md new file mode 100644 index 0000000..8b3585e --- /dev/null +++ b/tutorial/docker-basis/linking-ex-fic.md @@ -0,0 +1,44 @@ +## Exercice {-} + +À vous maintenant de connecter une instance de `nemunaire/fic-admin` à sa base +de données. + +Ne vous embêtez pas avec les mots de passes des services, initialisez la base +de données avec le nom d'utilisateur et le mot de passe par défaut. Vous les +obtiendrez en lisant la documentation de l'image fic-admin : + + +
+```bash +docker run --rm -e MYSQL_HOST=mysql_cntr_name nemunaire/fic-admin -help +``` +
+ +Notez la définition de la variable d'environnement `MYSQL_HOST`, celle-ci +indique le nom du serveur vers lequel le service doit se connecter. + +Vous aurez besoin de créer : +- un volume pour stocker la base de données, +- un réseau, dans lequel vous connecterez la base de données et le conteneur applicatif. + +Une fois le service `fic-admin` lancé, vous pouvez exposer le port 8081, sur +lequel vous devriez voir l'interface d'admin : . + +Placez les différentes commandes (volumes, réseau, `run`, ...) dans un +script `ficadmin-run.sh`. Vous devriez pouvoir appeler ce script +plusieurs fois, sans que les données ne soient perdues, entre deux +arrêts. + + +### Exemple d'exécution + +
+```bash +42sh$ ./ficadmin-run.sh +http://localhost:12345/ +42sh$ #docker kill db ficadmin +42sh$ ./ficadmin-run.sh # le script relancera une base de données, + # sans avoir perdu les données +http://localhost:12345/ +``` +
diff --git a/tutorial/docker-basis/linking-ex-help.md b/tutorial/docker-basis/linking-ex-help.md new file mode 100644 index 0000000..b2978bf --- /dev/null +++ b/tutorial/docker-basis/linking-ex-help.md @@ -0,0 +1,34 @@ +### Au secours, ça veut pas se connecter ! + +Lorsque nous lançons pour la première fois notre conteneur MySQL ou MariaDB, un +script est chargé d'initialisé le volume attaché à `/var/lib/mysql`. Les +démarrage suivant, ou si vous réutilisez un volume déjà initialisé avec une +base de données, le script ne refait pas d'initialisation. Même si les +variables d'environnement ont changées. + +Si vous rencontrez des difficultés pour connecter votre conteneur à +`my-db`, prenez le temps de recréer un volume. + + +### Entrer dans un conteneur en cours d'exécution + +Dans certaines circonstances, les journaux ne sont pas suffisants pour déboguer +correctement l'exécution d'un conteneur. + +En réalisant l'exercice, vous serez sans doute confronté à des comportements +étranges, que vous ne pourriez comprendre qu'en ayant la main sur le conteneur, +via un shell. + +Lorsqu'un conteneur est actif, vous pouvez y lancer un nouveau processus, +notamment un shell par exemple. + +
+```bash +docker container exec -it mycloud /bin/bash +(inctnr)$ ping mysql_cntr_name +``` +
+ +Notez qu'il n'est pas possible d'`exec` dans un conteneur éteint, et que si la +commande initiale du conteneur se termine, tous les `exec` seront instantanément +tués. diff --git a/tutorial/docker-basis/linking.md b/tutorial/docker-basis/linking.md index d2e9d78..80fbf83 100644 --- a/tutorial/docker-basis/linking.md +++ b/tutorial/docker-basis/linking.md @@ -12,14 +12,14 @@ ses données, mais la plupart des applications réclament un serveur de base de données. Les bonnes pratiques nous dictent de ne pas placer plus d'un service par -conteneur : en effet, on peut vouloir mettre à jour l'applicatif sans pour +conteneur : en effet, on peut vouloir mettre à jour l'applicatif sans pour autant redémarrer sa base de données, etc. Nous allons donc voir dans cette partie comment lier deux conteneurs. ## Mise en place du webservice -Nous allons utiliser l'interface d'administration des serveurs du FIC : +Nous allons utiliser l'interface d'administration des serveurs du FIC : [`nemunaire/fic-admin`](https://hub.docker.com/r/nemunaire/fic-admin). En lançant le conteneur avec les mêmes options que `youp0m`, les journaux @@ -30,17 +30,17 @@ MariaDB](https://hub.docker.com/_/mariadb). ## Les pilotes réseau -Docker propose de base trois pilotes (*drivers*) pour « gérer » cela : +Docker propose de base trois pilotes (*drivers*) pour « gérer » cela : -- `none` : pour limiter les interfaces réseau du conteneur à l'interface de +- `none` : pour limiter les interfaces réseau du conteneur à l'interface de loopback `lo` ; -- `host` : pour partager la pile réseau avec l'hôte ; -- `bridge` : pour créer une nouvelle pile réseau par conteneur et rejoindre un +- `host` : pour partager la pile réseau avec l'hôte ; +- `bridge` : pour créer une nouvelle pile réseau par conteneur et rejoindre un pont réseau dédié. Ces trois *drivers* sont instanciés de base dans Docker avec le même nom que -leur pilote. Pour consulter la liste de réseaux utilisables, lancez : +leur pilote. Pour consulter la liste de réseaux utilisables, lancez :
``` @@ -52,7 +52,7 @@ d5d907add6e2 host host local ```
-Par défaut, c'est le réseau `bridge` (de type `bridge`) qui est employé : ce +Par défaut, c'est le réseau `bridge` (de type `bridge`) qui est employé : ce réseau utilise le pont `docker0` que vous pouvez voir dans vos interfaces réseau via `ip link`. C'est via ce pont que les conteneurs peuvent avoir accès à Internet, au travers d'une couche de NAT. @@ -76,7 +76,7 @@ Afin de contrôler quels échanges peuvent être réalisés entre les conteneurs est recommandé de créer des réseaux utilisateur. La création d'un réseau se fait tout simplement au travers des sous-commandes -relatives aux objets Docker `network` : +relatives aux objets Docker `network` :
```bash @@ -86,7 +86,7 @@ docker network create --driver bridge my_fic C'est ensuite ce nom de réseau que vous passerez à l'option `--network` de vos `run`, ou vous pouvez également faire rejoindre un conteneur déjà lancé à un -réseau : +réseau :
```bash @@ -97,84 +97,3 @@ docker network connect NETWORK CONTAINER Lorsque plusieurs conteneurs ont rejoint un réseau utilisateur, ils peuvent mutuellement se découvrir grâce à un système de résolution de nom basé sur leur nom de conteneur. - - -## Exercice {-} - -À vous maintenant de connecter une instance de `nemunaire/fic-admin` à sa base -de données. - -Ne vous embêtez pas avec les mots de passes des services, initialisez la base -de données avec le nom d'utilisateur et le mot de passe par défaut. Vous les -obtiendrez en lisant la [documentation de l'image -fic-admin](https://hub.docker.com/r/nemunaire/fic-admin/) : - -
-```bash -docker container run --rm -e MYSQL_HOST=mysql_cntr_name nemunaire/fic-admin -help -``` -
- -Notez la définition de la variable d'environnement `MYSQL_HOST`, celle-ci -indique le nom du serveur vers lequel le service doit se connecter. - -Vous aurez besoin de créer un volume pour stocker la base de données, un réseau -dans lequel vous connecterez la base de données et le conteneur applicatif. - -Une fois le service `fic-admin` lancé, vous pouvez exposer le port 8081, sur -lequel vous devriez voir l'interface d'admin : . - -Placez les différentes commandes (volumes, réseau, `run`, ...) dans un -script `ficadmin-run.sh`, que vous rendrez à la fin du TP. Vous -devriez pouvoir appeler ce script plusieurs fois, sans que les données -ne soient perdues, entre deux arrêts. - - -### Exemple d'exécution - -
-```bash -42sh$ ./ficadmin-run.sh -http://localhost:12345/ -42sh$ #docker kill db ficadmin -42sh$ ./ficadmin-run.sh # le script relancera une base de données, - # sans avoir perdu les données -http://localhost:12345/ -``` -
- - -### Au secours, ça veut pas se connecter ! - -Lorsque nous lançons pour la première fois notre conteneur MySQL ou MariaDB, un -script est chargé d'initialisé le volume attaché à `/var/lib/mysql`. Les -démarrage suivant, ou si vous réutilisez un volume déjà initialisé avec une -base de données, le script ne refait pas d'initialisation. Même si les -variables d'environnement ont changées. - -Si vous rencontrez des difficultés pour connecter votre conteneur `fic-admin` à -`my-db`, prenez le temps de recréer un volume. - - -### Entrer dans un conteneur en cours d'exécution - -Dans certaines circonstances, les journaux ne sont pas suffisants pour déboguer -correctement l'exécution d'un conteneur. - -En réalisant l'exercice, vous serez sans doute confronté à des comportements -étranges, que vous ne pourriez comprendre qu'en ayant la main sur le conteneur, -via un shell. - -Lorsqu'un conteneur est actif, vous pouvez y lancer un nouveau processus, -notamment un shell par exemple. - -
-```bash -docker container exec -it ficadmin /bin/bash -(inctnr)$ ping mysql_cntr_name -``` -
- -Notez qu'il n'est pas possible d'`exec` dans un conteneur éteint, et que si la -commande initiale du conteneur se termine, tous les `exec` seront également -tués. diff --git a/tutorial/docker-basis/rendu.md b/tutorial/docker-basis/rendu.md index defc191..027ea05 100644 --- a/tutorial/docker-basis/rendu.md +++ b/tutorial/docker-basis/rendu.md @@ -17,7 +17,7 @@ pour se rendre sur la page de connexion. Une autre machine de votre réseau local devrait également pouvoir accéder à la plate-forme, simplement en renseignant l'IP de votre machine et en ajoutant éventuellement des règles de pare-feu (mais cette dernière partie n'est pas demandée, gardez simplement en -tête que cela doit pouvoir être fait manuellement au cas par cas : sur une +tête que cela doit pouvoir être fait manuellement au cas par cas : sur une machine sans pare-feu configurée, cela ne demande pas d'étape supplémentaire). Votre script devra se limiter aux notions vues durant ce TP (ie. sans utiliser @@ -67,7 +67,7 @@ Par ailleurs, n'oubliez pas de répondre à ## Tarball Tous les fichiers identifiés comme étant à rendre pour ce TP sont à -placer dans une tarball (pas d'archive ZIP, RAR, ...). +placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type: @@ -80,7 +80,7 @@ login_x-TP1/mycloud-run.sh ## Signature du rendu -Deux méthodes sont utilisables pour signer votre rendu : +Deux méthodes sont utilisables pour signer votre rendu : * signature du courriel ; * signature de la tarball. @@ -106,7 +106,7 @@ signature. #### No public key -Si vous recevez un rapport avec l'erreur suivante : +Si vous recevez un rapport avec l'erreur suivante :
``` @@ -129,7 +129,7 @@ rendu. #### Not explicit username -Si vous recevez un rapport avec l'erreur suivante : +Si vous recevez un rapport avec l'erreur suivante :
``` @@ -144,7 +144,7 @@ données. #### I've decided to skip your e-mail -Si vous recevez un rapport concluant ainsi : +Si vous recevez un rapport concluant ainsi :
``` diff --git a/tutorial/docker-basis/volumes.md b/tutorial/docker-basis/volumes.md index 2736a39..b8ec036 100644 --- a/tutorial/docker-basis/volumes.md +++ b/tutorial/docker-basis/volumes.md @@ -3,7 +3,7 @@ Stockage de données applicatives ================================ -Le concept principal de Docker est de concevoir des conteneurs applicatifs : on +Le concept principal de Docker est de concevoir des conteneurs applicatifs : on va préférer assigner un unique rôle à un conteneur (donc généralement on ne va lancer qu'une seule application par conteneur) et concevoir un service complet en créant un groupe de conteneurs, partageant des données entre eux par des @@ -25,21 +25,21 @@ Il est possible de monter un répertoire de la machine hôte dans un conteneur. L'intérêt reste plutôt limité à des fins de facilité ou de test, par exemple si vous voulez partager des fichiers avec votre voisin, en passant par le protocole HTTP, mais sans se casser la tête à installer et configurer un -serveur web : +serveur web :
```bash -docker container run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx +docker run --rm -p 80:80 -v ~/Downloads:/usr/share/nginx/html:ro -d nginx ```
Une fois cette commande lancée, votre voisin pourra accéder à votre dossier -Downloads en renseignant l'IP de votre machine dans son navigateur favori ! +Downloads en renseignant l'IP de votre machine dans son navigateur favori ! Par défaut, `nginx` ne va pas permettre de lister le contenu du répertoire (et va afficher une page 404, car il cherche un fichier `index.html` dans votre répertoire). Vous pouvez par contre accéder à un fichier directement, par -exemple : +exemple : ## Les volumes @@ -50,7 +50,7 @@ soucier de leur réel emplacement. Comme il s'agit d'un objet, la première chose à faire va être de créer notre -volume : +volume :
```bash @@ -59,7 +59,7 @@ docker volume create prod_foodp0m ```
-Ensuite, nous pouvons démarrer un conteneur utilisant, par exemple : +Ensuite, nous pouvons démarrer un conteneur utilisant, par exemple :
```bash @@ -67,7 +67,7 @@ docker container run --mount source=prod_youp0m,target=/images nemunaire/youp0m ```
-On pourra également faire de même avec un conteneur MySQL : +On pourra également faire de même avec un conteneur MySQL :
```bash @@ -86,7 +86,7 @@ Lorsque vous n'avez pas besoin de stocker les données et que vous ne désirez pas qu'elles persistent (des données sensibles par exemple) ou si cela peut améliorer les performances de votre conteneur, il est possible de créer des points de montages utilisant le système de fichiers `tmpfs` et donc résidant -exclusivement en RAM\ : +exclusivement en RAM\ :
```bash @@ -106,12 +106,15 @@ pour mettre à jour ou relancer un conteneur, sans perdre les données. Un autre intérêt est de pouvoir partager des fichiers entre plusieurs conteneurs. Il est ainsi parfaitement possible de lancer deux conteneurs qui partagent le -même volume : +même volume :
```bash -docker container run -d --mount source=prod_youp0m,target=/images -p 8080:8080 nemunaire/youp0m -docker container run -d --mount source=prod_youp0m,target=/images -p 8081:8080 nemunaire/youp0m +docker container run -d --mount source=prod_youp0m,target=/images \ + -p 8080:8080 nemunaire/youp0m + +docker container run -d --mount source=prod_youp0m,target=/images \ + -p 8081:8080 nemunaire/youp0m ```
@@ -119,7 +122,7 @@ Dans cet exemple, l'ajout d'une image dans un conteneur l'ajoutera également dans le second. Un exemple plus intéressant serait sur une architecture de micro-services -traitant des fichiers de grande taille : plutôt que de faire passer les +traitant des fichiers de grande taille : plutôt que de faire passer les fichiers par un système de message/socket, on peut partager un volume pour épargner les coûts de transferts inutiles, lorsqu'ils ne changent pas de machine. diff --git a/tutorial/docker-basis/what.md b/tutorial/docker-basis/what.md index 5d854a3..3923447 100644 --- a/tutorial/docker-basis/what.md +++ b/tutorial/docker-basis/what.md @@ -13,13 +13,13 @@ d'une socket. Le client peut d'ailleurs ne pas être sur la même machine qui exécutera effectivement les conteneurs.[^dockermachine] -C'est ce qu'il se passe lorsqu'on utilise *Docker4Windows* ou *Docker4Mac* : +C'est ce qu'il se passe lorsqu'on utilise *Docker4Windows* ou *Docker4Mac* : une machine virtuelle Linux est lancée parallèlement au système de base et chaque commande `docker` tapée est passée au deamon dans la machine virtuelle. [^dockermachine]: Il suffit de modifier la variable d'environnement `DOCKER_HOST` ou de passer le paramètre `-H` suivi de l'URL de la socket à - `docker`. Voir aussi : + `docker`. Voir aussi : Commençons par planter le décor, en détaillant les principaux mécanismes de Docker. @@ -30,17 +30,17 @@ Docker. Une image Docker est un système de fichiers en lecture seule. Elle est formée d'un ensemble de couches, agrégées selon le principe d'UnionFS. -Une image peut, par exemple, contenir : +Une image peut, par exemple, contenir : * un système Ubuntu opérationnel, * le programme `busybox`, * un serveur web et votre application web, prêts à l'emploi, -* ... +* ... Les images sont utilisées comme **modèle** qui sera ensuite dupliqué à chaque fois que l'on démarrera un nouveau conteneur. -Il y a deux méthodes pour obtenir des images Docker : soit les construire avec +Il y a deux méthodes pour obtenir des images Docker : soit les construire avec les outils fournis, soit les récupérer depuis un registre. @@ -50,8 +50,8 @@ Les registres sont des plates-formes de stockage, publiques ou privées, contenant des images. Ils permettent de récupérer des images, mais également d'en envoyer. -Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/) : il -contient à la fois des images officielles (ubuntu, debian, nginx, ...), des +Le registre utilisé de base est le [Docker Hub](https://hub.docker.com/) : il +contient à la fois des images officielles (ubuntu, debian, nginx, ...), des images créées par des utilisateurs, mais aussi des images de grands éditeurs, payantes, à destination des entreprises. @@ -65,10 +65,10 @@ proposent également. ### Les conteneurs Docker Alors que les images constituent la partie immuable de Docker, les conteneurs -sont sa partie vivante. Chaque conteneur est créé à partir d'une image : à +sont sa partie vivante. Chaque conteneur est créé à partir d'une image : à chaque fois que nous lançons un conteneur, une couche lecture/écriture est ajoutée au dessus de l'image. Cette couche est propre au conteneur et -temporaire : l'image n'est pas modifiée par l'exécution d'un conteneur. +temporaire : l'image n'est pas modifiée par l'exécution d'un conteneur. ![Couches d'un conteneur](layers-multi-container.png "Couches d'un conteneur"){ width=70% } diff --git a/tutorial/docker-internals/clair.md b/tutorial/docker-internals/clair.md index c0f3cc2..317b355 100644 --- a/tutorial/docker-internals/clair.md +++ b/tutorial/docker-internals/clair.md @@ -113,10 +113,13 @@ Puis on lui demande la génération d'un rapport `html` :
```bash -paclair --conf conf.yml Docker nemunaire/fic-admin analyse --output-format html --output-report file +paclair --conf conf.yml Docker nemunaire/fic-admin analyse \ + --output-format html --output-report file ```
+![Rapport d'analyse statique des vulnérabilités par Clair](paclair.png) + Si l'on souhaite uniquement avoir des statistiques dans la console :
diff --git a/tutorial/docker-internals/linuxkit-content.md b/tutorial/docker-internals/linuxkit-content.md index 68b8b7c..821000c 100644 --- a/tutorial/docker-internals/linuxkit-content.md +++ b/tutorial/docker-internals/linuxkit-content.md @@ -4,7 +4,7 @@ Si vous n'avez pas déjà le binaire `linuxkit`, vous pouvez télécharger ici  . 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] ;-) [^lollibc]: à condition tout de même que vous utilisiez une libc habituelle. @@ -17,17 +17,17 @@ 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 ; + 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 ; + 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 ; + que le dernier conteneur de `onboot` aura rendu la main ; - `files` : des fichiers supplémentaires à placer dans le rootfs. Le format est documenté @@ -63,7 +63,7 @@ trust:
L'image `getty` est très pratique pour déboguer, car elle permet d'avoir un -shell sur la machine ! +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 @@ -143,7 +143,7 @@ réutiliser plus tard ce chemin, en remplacement du mot clef `new` : 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 ! +plates-formes pour aller y lancer des instances de cette image ! Pour construire l'image faite précédemment : @@ -154,7 +154,7 @@ linuxkit build hello.yml
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 +partie `kernel`) ainsi qu'une image. Exactement ce qu'attend QEMU ! Pour tester, n'attendons pas davantage pour lancer :
@@ -227,7 +227,7 @@ choix](https://www.vaultproject.io/docs/configuration/storage/index.html) 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 +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) diff --git a/tutorial/docker-internals/linuxkit.md b/tutorial/docker-internals/linuxkit.md index 0a7ba70..aeb4ba6 100644 --- a/tutorial/docker-internals/linuxkit.md +++ b/tutorial/docker-internals/linuxkit.md @@ -8,8 +8,8 @@ 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 ! +des images pour les différents fournisseurs de cloud ! -Bien entendu, au sein de ce système, tout est fait de conteneur ! Alors quand +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 ! +il faut savoir jouer avec les *namespaces* pour arriver à ses fins ! diff --git a/tutorial/docker-internals/oci.md b/tutorial/docker-internals/oci.md index 9942a8b..4d4096d 100644 --- a/tutorial/docker-internals/oci.md +++ b/tutorial/docker-internals/oci.md @@ -9,14 +9,14 @@ fragmentation de l'écosystème. Trois spécifications ont été écrites : -- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définit les paramètres du démarrage d'un conteneur ; -- [`image-spec`](https://github.com/opencontainers/image-spec/blob/master/spec.md): définit la construction, le transport et la préparation des images ; +- [`runtime-spec`](https://github.com/opencontainers/runtime-spec/blob/master/spec.md#platforms): définit les paramètres du démarrage d'un conteneur ; +- [`image-spec`](https://github.com/opencontainers/image-spec/blob/master/spec.md): définit la construction, le transport et la préparation des images ; - [`distribution-spec`](https://github.com/opencontainers/distribution-spec/blob/master/spec.md): définit la manière dont sont partagées et récupérées les images. ## `runtime-spec` -`runc` est l'implémentation de cette spécification ; elle a été extraite de +`runc` est l'implémentation de cette spécification ; elle a été extraite de `docker`, puis donnée par Docker Inc. à l'OCI. Pour démarrer un conteneur, la spécification indique qu'il est nécessaire @@ -82,5 +82,5 @@ effectivement nos conteneurs, c'est que l'on peut changer cette implémentation ? la réponse dans l'article : -Et `containerd` dans l'histoire ? +Et `containerd` dans l'histoire ? diff --git a/tutorial/docker-internals/registry.md b/tutorial/docker-internals/registry.md index f2c74e9..a939a5c 100644 --- a/tutorial/docker-internals/registry.md +++ b/tutorial/docker-internals/registry.md @@ -21,13 +21,13 @@ Hub](https://hub.docker.com/), le registre par défaut de `docker`, nous allons devoir nous plier à leur mécanisme d'authentification : chaque requête au registre doit être effectuée avec un jeton, que l'on obtient en s'authentifiant auprès d'un service dédié. Ce service peut délivrer un jeton sans authentifier -l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux -images publiques. Ça tombe bien, c'est ce qui nous intéresse aujourd'hui ! +l'interlocuteur, en restant anonyme ; dans ce cas, on ne pourra accéder qu'aux +images publiques. Ça tombe bien, c'est ce qui nous intéresse aujourd'hui ! -Il n'en reste pas moins que le jeton est forgé pour un service donné (dans -notre cas `registry.docker.io`) et avec un objectif bien cerné (pour nous, on -souhaite récupérer le contenu du dépôt[^quiddepot] `hello-world` : -`repository:hello-world:pull`). Ce qui nous donne : +Il n'en reste pas moins que le jeton est forgé pour un service donné (ici +`registry.docker.io`) et avec un objectif bien cerné (pour nous, on souhaite +récupérer le contenu du dépôt[^quiddepot] `hello-world` : `repository:hello-world:pull`). Ce qui nous donne : [^quiddepot]: Dans un registre, les fichiers qui composent l'image forment un dépôt (*repository*). @@ -58,7 +58,11 @@ Avec `jq`, on peut l'extraire grâce à : ```
-**Attention :** le token expire ! Pensez à le renouveler régulièrement. +::::: {.warning} + +Le token expire ! Pensez à le renouveler régulièrement. + +::::: En cas d'erreur inexplicable, vous pouvez ajouter un `-v` à la ligne de commande `curl`, afin d'afficher les en-têtes. Prêtez une attention toute @@ -94,12 +98,12 @@ système d'exploitation : curl -s \ -H "Authorization: Bearer ${TOKEN}" \ -H "Accept: ${MEDIATYPE}" \ - "https://registry-1.docker.io/v2/library/hello-world/manifests/${MANIFEST_DIGEST}" | jq . + "https://registry-1.docker.io/v2/library/hello-world/manifests/${MNFST_DGST}" ```
Nous voici donc maintenant avec le manifest de notre image. Nous pouvons -constater qu'il n'a bien qu'une seule couche, ouf ! +constater qu'il n'a bien qu'une seule couche, ouf ! ## Récupération de la configuration et de la première couche @@ -115,7 +119,7 @@ Pour récupérer la configuration de l'image : ```bash curl -s --location \ -H "Authorization: Bearer ${TOKEN}" \ - "https://registry-1.docker.io/v2/library/hello-world/blobs/${CONFIG_DIGEST}" | jq . + "https://registry-1.docker.io/v2/library/hello-world/blobs/${CONFIG_DIGEST}" ```
@@ -132,9 +136,11 @@ wget --header "Authorization: Bearer ${TOKEN}" \ ## Extraction -Le type indiqué par le manifest pour cette couche était -`application/vnd.docker.image.rootfs.diff.tar.gzip`, il s'agit donc d'une -tarball compressée au format gzip : +Le type indiqué par le manifest pour cette couche était : + + application/vnd.docker.image.rootfs.diff.tar.gzip + +Il s'agit donc d'une tarball compressée au format gzip :
```bash @@ -179,7 +185,7 @@ Pensez également à tester avec d'autres images, comme par exemple `nemunaire/youp0m`. Il vous faudra alors extraire plusieurs couches. Pour gérer les différentes couches, vous pouvez utiliser une stratégie -similaire au driver `vfs` : en extrayant chaque tarball l'une au dessus de +similaire au driver `vfs` : en extrayant chaque tarball l'une au dessus de l'autre, en essayant de gérer les *whiteout files*. Ou bien en suivant le driver `overlayfs`, en montant un système de fichier à chaque couche (dans ce cas, votre script devra être lancé en `root`). diff --git a/tutorial/docker-internals/runc.md b/tutorial/docker-internals/runc.md index 9ab7007..2942782 100644 --- a/tutorial/docker-internals/runc.md +++ b/tutorial/docker-internals/runc.md @@ -22,13 +22,13 @@ essayer de lancer un shell `alpine` avec un volume dans notre home. 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 : -. La 1.0.0-rc92 est Ok. +. ## Extraction du rootfs -À l'aide du script d'extraction de registre réalisé dans le TP 3, extrayons le -rootfs d'alpine : `library/alpine` dans le registre Docker. +À l'aide du script d'extraction de registre déjà réalisé, extrayons le +*rootfs* d'alpine : `library/alpine` dans le registre Docker. Si vous n'avez pas eu le temps de terminer le script d'extraction, vous pouvez utiliser : @@ -55,9 +55,7 @@ runc spec Pour savoir à quoi correspondent tous ces éléments, vous pouvez consulter : -Nous verrons dans les prochains TP, plus en détails tout ce qui porte sur les -*namespaces*, rassurez-vous, il n'y a que très peu de champs à modifier -aujourd'hui. +Rassurez-vous, il n'y a que très peu de champs à modifier. ## Test brut @@ -143,8 +141,8 @@ stocker les photos (dossier `/srv/images`)[^chmod]. simple pour l'instant serait d'attribuer les permissions `0777` à la source, temporairement. -Pour ce TP, considérez que vous avez réussi si vous voyez s'afficher : +Pour cette étape, Considérez que vous avez réussi si vous voyez s'afficher : > `Ready, listening on :8080` -Il faudra attendre les TP suivants pour avoir du réseau dans notre conteneur. +On ne pourra pas tester davantage sans avoir du réseau dans notre conteneur. diff --git a/tutorial/docker-internals/vulnerability-scan.md b/tutorial/docker-internals/vulnerability-scan.md index eb71eff..facd8fa 100644 --- a/tutorial/docker-internals/vulnerability-scan.md +++ b/tutorial/docker-internals/vulnerability-scan.md @@ -10,10 +10,10 @@ machine hébergeant des conteneurs, car cela lui apporte des garanties quant à l'effort de cloisonnement mis en place. Mais doit-on pour autant s'arrêter là et considérer que nous avons réglé -l'ensemble des problématiques de sécurité liées aux conteneurs ? +l'ensemble des problématiques de sécurité liées aux conteneurs ? Évidemment, non : une fois nos services lancés dans des conteneurs, il ne sont -pas moins exposés aux bugs et autres failles applicatives ; qu'elles soient +pas moins exposés aux bugs et autres failles applicatives ; qu'elles soient dans notre code ou celui d'une bibliothèque, accessible par rebond, ... Il est donc primordial de ne pas laisser ses conteneurs à l'abandon une fois @@ -23,7 +23,7 @@ image telle que Debian, Ubuntu ou Redhat n'apparaît que pour cela) ou bien lorsqu'un des programmes ou l'une des bibliothèques que l'on a installés ensuite est mise à jour. -Convaincu ? Cela sonne encore comme des bonnes pratiques difficiles à mettre en +Convaincu ? Cela sonne encore comme des bonnes pratiques difficiles à mettre en œuvre, pouvant mettre en péril tout un système d'information. Pour s'en protéger, nous allons avoir besoin de réaliser à intervalles réguliers une analyse statique de nos conteneurs. @@ -42,9 +42,9 @@ automatiquement) les images que l'on publie sur un registre public, sans oublier de mettre à jour l'image de base. D'ailleurs, avez-vous vérifié qu'une mise à jour de l'image `nemunaire/youp0m` -n'était pas disponible depuis que vous avez commencé à l'utiliser ? Docker ne +n'était pas disponible depuis que vous avez commencé à l'utiliser ? Docker ne vérifie jamais si une mise à jour des images que vous avez précédemment -téléchargées. Pensez donc régulièrement à appeler : +téléchargées. Pensez donc régulièrement à appeler :
``` @@ -65,10 +65,11 @@ si vous n'en avez pas, nous verrons dans la section suivante `trivy` qui permet de réaliser ses scans directement sur notre machine, sans passer par un intermédiaire. -#### Attention {-} +::::: {.warning} Par cette méthode, vous êtes limité à 10 scans par mois. +::::: ### Installation du plugin @@ -82,13 +83,14 @@ préalablement connecté à votre compte Docker avec la commande `docker login`. Comme `docker scan` est un plugin, suivant la méthode d'installation que vous avez suivie, il n'a pas forcément été installé. Si vous obtenez un message d'erreur en lançant la commande, [voici comment récupérer le plugin et -l'installer manuellement :](https://github.com/docker/scan-cli-plugin#on-linux) +l'installer manuellement :](https://github.com/docker/scan-cli-plugin#on-linux)
``` mkdir -p ~/.docker/cli-plugins -curl https://github.com/docker/scan-cli-plugin/releases/latest/download/docker-scan_linux_amd64 \ - -L -s -S -o ~/.docker/cli-plugins/docker-scan +curl -L -s -S -o ~/.docker/cli-plugins/docker-scan \ + https://github.com/docker/scan-cli-plugin/releases/\ + latest/download/docker-scan_linux_amd64 chmod +x ~/.docker/cli-plugins/docker-scan ```
@@ -96,7 +98,7 @@ chmod +x ~/.docker/cli-plugins/docker-scan ### Utilisation Une fois le plugin installé et la licence du service acceptée, nous pouvons -commencer notre analyse : +commencer notre analyse :
``` @@ -112,7 +114,8 @@ Base image: alpine:3.14.2 ✓ Tested 16 dependencies for known vulnerabilities, no vulnerable paths found. -According to our scan, you are currently using the most secure version of the selected base image +According to our scan, you are currently using the most secure version of +the selected base image ```
@@ -128,10 +131,10 @@ Testing mysql... ✗ High severity vulnerability found in gcc-8/libstdc++6 Description: Insufficient Entropy Info: https://snyk.io/vuln/SNYK-DEBIAN10-GCC8-469413 - Introduced through: apt@1.8.2.3, mysql-community/mysql-community-client@8.0.26-1debian10, mysql-community/mysql-community-server-core@8.0.26-1debian10, mecab-ipadic@2.7.0-20070801+main-2.1, meta-common-packages@meta + Introduced through: apt@1.8.2.3, mysql-community/mysql-community-client@[...] From: apt@1.8.2.3 > gcc-8/libstdc++6@8.3.0-6 - From: mysql-community/mysql-community-client@8.0.26-1debian10 > gcc-8/libstdc++6@8.3.0-6 - From: mysql-community/mysql-community-server-core@8.0.26-1debian10 > gcc-8/libstdc++6@8.3.0-6 + From: mysql-community/mysql-community-client@8.0.26-1debian10 > gcc-8[...] + From: mysql-community/mysql-community-server-core@8.0.26-1debian10 > gcc-8[...] and 7 more... Image layer: Introduced by your base image (mysql:8.0.26) @@ -143,11 +146,12 @@ Base image: mysql:8.0.26 Tested 135 dependencies for known vulnerabilities, found 79 vulnerabilities. -According to our scan, you are currently using the most secure version of the selected base image +According to our scan, you are currently using the most secure version of +the selected base image ```
-Ce dernier exemple est sans appel : `mysql` est une image officielle, et sa +Ce dernier exemple est sans appel : `mysql` est une image officielle, et sa dernière version à l'écriture de ses lignes contient pas moins de 79 vulnérabilités dont 11 *high*. @@ -168,7 +172,7 @@ un certain nombre d'arguments, notamment le nom de l'image à analyser. ### Utilisation -Tentons à nouveau d'analyser l'image `mysql` : +Tentons à nouveau d'analyser l'image `mysql` :
``` @@ -189,7 +193,7 @@ Les résultats sont un peu différents qu'avec `docker scan`, mais on constate que l'image `mysql` contient vraiment de nombreuses vulnérabilités. Même si elles ne sont heureusement pas forcément exploitable directement. -Voyons maintenant s'il y a des différentes avec l'image `nemunaire/fic-admin` : +Voyons maintenant s'il y a des différentes avec l'image `nemunaire/fic-admin` :
``` @@ -217,7 +221,7 @@ vulnérabilités de l'image, a aussi fait une analyse des dépendances du binair `/srv/admin`. Trivy est en effet capable de rechercher des vulnérabilités par rapport aux -dépendances connues de certains langages : Python, PHP, Node.js, .NET, Java, +dépendances connues de certains langages : Python, PHP, Node.js, .NET, Java, Go, ... @@ -225,7 +229,7 @@ Go, ... Pour éviter de surcharger les serveurs de distributions de la base de données de vulnérabilités, nous devrions utiliser un cache pour faire nos -analyses. Préférez lancer `trivy` avec les options suivantes : +analyses. Préférez lancer `trivy` avec les options suivantes :
``` @@ -242,7 +246,7 @@ pouvoir l'exporter pour l'afficher dans un navigateur (par exemple pour le mettre à disposition des développeurs, lors d'une analyse automatique). Pour ce faire, on peut ajouter les options suivantes à la ligne de commande de -notre conteneur : +notre conteneur :
```bash @@ -253,8 +257,6 @@ notre conteneur : En redirigeant la sortie standard vers un fichier, vous pourrez l'ouvrir dans votre navigateur favori. ---- - -![Scan de vulnérabilités sur le registre Quay.io](quay-vulns.png){ width=90% } +![Scan de vulnérabilités sur le registre Quay.io](quay-vulns.png){ width=80% } ## Clair diff --git a/tutorial/docker-orchestration/machine.md b/tutorial/docker-orchestration/machine.md index fb62cc8..85bc6d6 100644 --- a/tutorial/docker-orchestration/machine.md +++ b/tutorial/docker-orchestration/machine.md @@ -1,23 +1,21 @@ \newpage Création du cluster -=================== +------------------- -## Le provisionnement de machine - -Pour travailler sur un cluster, il faut avoir plusieurs machines ... au moins -plus d'une ! +Pour travailler sur un cluster, il faut avoir plusieurs machines ... au moins +plus d'une ! Mais qui dit plusieurs machines, dit généralement de nombreuses installations à faire, de nombreuses configurations à partager, etc. Tout ce qu'un -administrateur système redoute : du travail ! +administrateur système redoute : du travail ! Évidemment, de nombreuses solutions existent pour travailler moins, tout en -déployant plus et de manière plus fiable ! On peut parler +déployant plus et de manière plus fiable ! On peut parler d'[`ansible`](https://www.ansible.com/), de [`chef`](https://docs.chef.io/provisioning.html), ou encore de -[`puppet`](https://puppet.com/products/capabilities/automated-provisioning), -... Toutes ces solutions permettent d'obtenir des configurations finement +[`puppet`](https://puppet.com/products/capabilities/automated-provisioning), ... +Toutes ces solutions permettent d'obtenir des configurations finement personnalisées, mais nécessitent une phase d'apprentissage plutôt lourde. Comme nous voulons lancer des conteneurs, les machines à provisionner n'ont pas @@ -25,9 +23,7 @@ besoin de configuration bien particulière et les seuls paquets importants sont une version récente de `docker` et ses dépendances. -## Provisionner des machines ... - -### Automagiquement +### Provisionner des machines ... La solution magique consiste à passer par `docker-machine` pour créer des machines virtuelles automatiquement provisionnées avec Docker. @@ -38,21 +34,20 @@ virtuelles. Si votre machine Linux est en fait une machine virtuelle hébergée par VirtualBox sous Windows, vous allez sans doute préférer la deuxième solution, que d'utiliser PowerShell et Docker4Windows[^amazon]. -[^amazon]: Vous pouvez aussi vous inscrire sur - [Amazon Web Services](https://aws.amazon.com/), `docker-machine` est - capable, à partir de vos - [clefs d'API](https://docs.docker.com/machine/examples/aws/), de créer et - lancer des machines dans le cloud ! Et ce n'est pas le seul service de - [cloud supporté](https://docs.docker.com/machine/drivers/) ! +[^amazon]: Vous pouvez aussi vous inscrire sur [Amazon Web + Services](https://aws.amazon.com/) , + `docker-machine` est capable, à partir de vos clefs d'API, de créer et + lancer des machines dans le cloud ! Et ce n'est pas le seul service de + cloud supporté ! -#### Créer une machine +##### Créer une machine {-} Pour créer une nouvelle machine, nous allons utiliser la commande `docker-machine create`, en prenant soin de préciser le pilote à utiliser, les éventuelles options que prend ce pilote, ainsi que le nom que vous souhaitez donner à cette machine (les machines ne sont pas considérées comme jetables, -leur nom vous permettra par exemple de relancer une machine plus tard) : +leur nom vous permettra par exemple de relancer une machine plus tard) :
```bash @@ -61,34 +56,37 @@ docker-machine create --driver virtualbox echinoidea
Consultez la section suivante, réservée aux gens qui ne peuvent pas passer par -`docker-machine` si vous souhaitez avoir plus d'information sur ce que fait +`docker-machine`, si vous souhaitez avoir plus d'information sur ce que fait cette commande. -#### Commandes usuelles de `docker-machine` +##### Commandes usuelles de `docker-machine` {-} De la même manière que `docker`, vous pouvez lister les machines connues -(`ls`), changer leur état d'exécution (`start`/`stop`/`kill`/`restart`) ou encore supprimer la machine (`rm`) +(`ls`), changer leur état d'exécution (`start`/`stop`/`kill`/`restart`) ou +encore supprimer une machine (`rm`). -Si vous avez besoin d'obtenir un shell : `docker-machine ssh $NAME` et +Si vous avez besoin d'obtenir un shell : `docker-machine ssh $NAME` et évidemment la commande `scp` s'utilise de la même manière, pour transférer des fichiers. -#### Utilisation avec Docker +##### Utilisation avec Docker {-} -Rappelez-vous, au cours précédent, nous avions évoqué le fait que le deamon -pouvait ne pas se trouver sur la même machine que le client `docker`. Eh bien -avec `docker-machine` cela prend tout son sens, car vous pouvez très facilement -changer de daamon/machine avec une simple commande : +Nous avons déjà évoqué le fait que le deamon pouvait ne pas se trouver sur la +même machine que le client `docker`. Eh bien avec `docker-machine` cela prend +tout son sens, car vous pouvez très facilement changer de daemon/machine avec +une simple commande :
``` -42sh$ docker container ls -CONTAINER ID IMAGE COMMAND CREATED STATUS -42sh$ eval $(docker-machine env echinoidea) 42sh$ docker container ls -a -CONTAINER ID IMAGE COMMAND CREATED STATUS -a814293b9f45 armbuild/busybox "/bin/sh" 18 seconds ago Up 10 minutes -0caddeed5037 armbuild/alpine "/bin/sh" 2 weeks ago Created +CONTAINER ID IMAGE COMMAND CREATED STATUS + +42sh$ eval $(docker-machine env echinoidea) + +42sh$ docker container ls -a +CONTAINER ID IMAGE COMMAND CREATED STATUS +a814293b9f45 armbuild/busybox "/bin/sh" 18 seconds ago Up 10 minutes +0caddeed5037 armbuild/alpine "/bin/sh" 2 weeks ago Created ```
@@ -102,43 +100,44 @@ supprimer manuellement les variables qui ont été ajoutées par l'évaluation, soit lancer `eval $(docker machine env -u)`. -### Automanuellement +#### Derrière Docker Machine... Si votre environnement ne vous permet pas d'utiliser `docker-machine`, vous -pouvez vous contenter aujourd'hui de démarrer une ou deux autres machines -virtuelles sur le même réseau que votre machine actuelle. +pouvez vous contenter de démarrer une ou deux autres machines virtuelles sur le +même réseau que votre machine virtuelle. Rassurez-vous, vous n'allez pas avoir besoin de refaire toute la phase -d'installation. Des contributeurs maintiennent une petite ISO ne contenant que -le strict nécessaire pour utiliser Docker. C'est d'ailleurs cette ISO qui est -utilisé par `docker-machine` pour démarrer et configurer en un rien de temps -ses machines virtuelles. +d'installation. Des contributeurs ont conçu une petite image de CD ne contenant +que le strict nécessaire pour utiliser Docker. C'est d'ailleurs cette ISO qui +est utilisée par `docker-machine` pour démarrer et configurer en un rien de +temps ses machines virtuelles. -1. Dans un premier temps, commençons par - [télécharger la dernière ISO de `boot2docker.iso`](https://github.com/boot2docker/boot2docker/releases/latest). +1. Dans un premier temps, commençons par télécharger la dernière ISO de + `boot2docker.iso` :\ + 1. Ensuite, dans notre hyperviseur, créons deux nouvelles machines, avec suffisamment de ressources pour pouvoir lancer des conteneurs. Ce n'est pas - parce que l'images que l'on va démarrer est petite, que l'on ne va pas + parce que l'image que l'on va démarrer est petite que l'on ne va pas pouvoir allouer beaucoup d'espace disque ou de RAM. 1. Lançons ensuite nos deux images, configurées pour démarrer sur l'image ISO que l'on a téléchargée précédemment. 1. Faisons un `ip a` pour connaître l'IP de la machine, nous devrions pouvoir - s'y connecter en SSH avec l'utilisateur `docker` dont le mot de passe est + nous y connecter en SSH avec l'utilisateur `docker` dont le mot de passe est `tcuser`. Vous constaterez que le daemon `dockerd` est déjà lancé. `docker` est déjà -pleinement utilisable dans cette machine ! +pleinement utilisable dans cette machine ! #### (Optionnel) Déporter le client Docker -Dans le suite de ce TP, nous n'allons taper que quelques commandes dans nos +Dans la suite, nous n'allons taper que quelques commandes dans nos machines virtuelles, il n'est donc pas primordial d'avoir configuré son environnement pour utiliser localement les daemons Docker des machines virtuelles. Néanmoins, cela ne coûte rien de voir les procédures mise en œuvre. Commençons par voir sur quel port le daemon `dockerd` de notre machine -virtuelle écoute : +virtuelle écoute :
```bash @@ -148,26 +147,25 @@ tcp 0 0 :::2376 :::* 980/dockerd ```
-Essayons de renseigner simplement cette configuration à notre client Docker : +Essayons de renseigner simplement cette configuration à notre client Docker :
```bash (main) 42sh$ docker -H tcp://$VM1_IP:2376/ info -Get http://$VM1_IP:2376/v1.32/info: net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x01\x00\x02\x02". +Get http://$VM1_IP:2376/v1.32/info: net/http: transport connection broken * Are you trying to connect to a TLS-enabled daemon without TLS? ```
-En effet, Docker met tout en œuvre pour rendre compliqué l'utilisation +En effet, Docker met tout en œuvre pour rendre compliquée l'utilisation non-sécurisée de la plate-forme. Mais ils font également en sorte que la sécurité soit la plus transparente et la moins contraignante possible pour l'utilisateur, sans pour autant être faible. Afin de contacter un daemon Docker distant, il est nécessaire présenter un -certificat client TLS approuvé par ce daemon (comme lorsque vous vous connectez -sur [Epitaf](https://www.epitaf.fr/moodle)). Il est également nécessaire de +certificat client TLS approuvé par ce daemon. Il est seulement nécessaire de vérifier le certificat présenté par le daemon, comme dans le cadre d'une -connexion TLS classique. +connexion SSH classique. Tout le nécessaire est déjà configuré au sein de `boot2docker`, pour nos tests, nous n'avons qu'à recopier la clef et les certificats en place. @@ -182,12 +180,12 @@ key.pem ```
-Tentons maintenant de nous connecter au daemon distant en utilisant ces éléments : +Tentons maintenant de nous connecter au daemon distant utilisant ces éléments :
```bash -42sh$ DOCKER_CERT_PATH=remote/virt1/ docker -H tcp://$VM1_IP:2376/ --tlsverify info +DOCKER_CERT_PATH=remote/vir1/ docker -H tcp://$VM1_IP:2376/ --tlsverify info ```
-Vous pouvez effectuer la même opération pour la seconde VM. +Nous pouvons effectuer la même opération pour la seconde machine virtuelle. diff --git a/tutorial/docker-orchestration/rendu.md b/tutorial/docker-orchestration/rendu.md index e1653d1..b104770 100644 --- a/tutorial/docker-orchestration/rendu.md +++ b/tutorial/docker-orchestration/rendu.md @@ -34,7 +34,7 @@ Tous les fichiers identifiés comme étant à rendre pour ce TP sont à placer dans une tarball (pas d'archive ZIP, RAR, ...). Voici une arborescence type (vous pourriez avoir des fichiers supplémentaires, -cela dépendra de votre avancée dans le projet) : +cela dépendra de votre avancée dans le projet) :
``` diff --git a/tutorial/docker-orchestration/setup.md b/tutorial/docker-orchestration/setup.md index 3bfa7e6..88708d7 100644 --- a/tutorial/docker-orchestration/setup.md +++ b/tutorial/docker-orchestration/setup.md @@ -1,42 +1,35 @@ -\newpage - Mise en place -============= +------------- +Pour cette partie, nous allons avoir besoin de `docker-machine`, installons-le sur +notre machine hôte, même si ce n'est pas un Linux : le but va être de lancer +plusieurs machines virtuelles dédiées à Docker pour simuler un cluster. -## `docker-machine` - -Pour ce TP, nous allons avoir besoin de `docker-machine`, installez-le sur -votre machine hôte, même si ce n'est pas un Linux : le but va être de lancer -plusieurs machines virtuelles Docker pour simuler un cluster. - -Ce programme permet de simplifier la gestion du multiples environnements -Docker, comme par exemple lorsque l'on souhaite gérer un cluster de machines +Ce programme permet de simplifier la gestion de multiples environnements +Docker, comme par exmple lorsque l'on souhaite gérer un cluster de machines pour un projet. Ainsi, il est possible de provisionner et gérer des machines hôtes sur les plates-formes de cloud habituelles. C'est également ce projet qui est à la base -de *Docker for Mac* et *Docker for Windows*, en permettant de lancer via, -respectivement, VirtualBox et Hyper-V, un environnement Linux prêt à être -utilisé avec Docker. +de *Docker Dektop*, en permettant de lancer via, respectivement, VirtualBox ou +Hyper-V, un environnement Linux prêt à être utilisé avec Docker. ### Par la distribution binaire L'équipe en charge de `docker-machine` met à disposition un exécutable compilé -pour bon nombres d'environnements. Nous pouvons l'installer en suivant la -procédure suivante : +pour bon nombre d'environnements. Nous pouvons l'installer en suivant la +procédure suivante :
```bash -curl -L https://github.com/docker/machine/releases/download/v0.15.0/docker-machine-Linux-x86_64 \ +V=0.16.2 +P=docker-machine-`uname -s`-`uname -m` +curl -L https://github.com/docker/machine/releases/download/v${V}/${P} \ > /usr/bin/docker-machine chmod +x /usr/bin/docker-machine ```
-Si vous êtes dans un environnement différent, jetez un œil à -[la documentation d'installation](https://docs.docker.com/machine/install-machine/). - ### Support de KVM @@ -46,28 +39,30 @@ plug-ins. Si vous utilisez KVM comme hyperviseur, vous allez avoir besoin d'installer le plugins -[`docker-machine-kvm`](https://github.com/dhiltgen/docker-machine-kvm). Vous -n'aurez qu'à suivre les instructions du -[`README`](https://github.com/dhiltgen/docker-machine-kvm/blob/master/README.md) -! +[`docker-machine-kvm`](https://github.com/machine-drivers/docker-machine-kvm). Vous +n'aurez qu'à suivre les instructions du `README` :\ + +Les autres plugins sont disponibles au sein de l'organisation Machine-Driver +sur GitHub :\ + ### Vérification du fonctionnement Comme avec Docker, nous pouvons vérifier le bon fonctionnement de -`docker-machine` en exécutant la commande : +`docker-machine` en exécutant la commande :
``` 42sh$ docker-machine version -docker-machine version 0.12.2, build 9371605 +docker-machine version 0.16.2, build 9371605 ```
-## Play With Docker +### Play With Docker -Tout comme pour le TP précédent, si vous avez des difficultés pour réaliser les -exercices sur vos machines, vous pouvez utiliser le projet -[Play With Docker](https://play-with-docker.com/) qui vous donnera accès à un -bac à sable avec lequel vous pourrez réaliser tous les exercices de ce TP. +Si vous avez des difficultés pour réaliser les exercices sur votre machine, +vous pouvez utiliser le projet [Play With +Docker](https://play-with-docker.com/) qui vous donnera accès à un bac à sable +avec lequel vous pourrez réaliser tous les exercices de cette partie. diff --git a/tutorial/docker-orchestration/stack.md b/tutorial/docker-orchestration/stack.md index 79e9433..8be67ff 100644 --- a/tutorial/docker-orchestration/stack.md +++ b/tutorial/docker-orchestration/stack.md @@ -1,15 +1,15 @@ \newpage Déploiement de services -======================= +----------------------- -## Services ? +### Services ? Une petite minute terminologie avant de continuer, car lorsque l'on passe sur -les clusters de Docker, cela change un peu : +les clusters de Docker, cela change un peu : * une *tâche* correspond à **un** unique conteneur, lancé sur l'un des nœuds - *workers* du cluster ; + *workers* du cluster ; * un *service* est un groupe de tâches (oui, les tâches du point précédent), exécutant la même image. @@ -18,13 +18,13 @@ la haute-disponibilité ou pour répartir la charge.
-### Hello world, again? +#### Hello world, again?
Non, pas d'hello-world ici, mais nous allons prendre en main les services avec un serveur web, qui sera bien plus représentatif de ce que l'on pourra obtenir. -Précédemment, nous lancions notre serveur web favori avec : +Précédemment, nous lancions notre serveur web favori avec :
```bash @@ -33,7 +33,7 @@ docker container run --name mywebs -d nginx
La même commande, mais déployée à partir d'un nœud manager, vers un nœud -*workers*, est : +*workers*, est :
```bash @@ -41,7 +41,7 @@ docker service create --name myWebS nginx ```
-Allons-y, essayons ! +Allons-y, essayons ! On peut consulter l'état du service avec, comme d'habitude `ls` : @@ -59,7 +59,7 @@ déployé, le tâche apparaît dans la liste des conteneurs ! Rien de très excitant pour le moment, car nous ne pouvons pas vraiment accéder à notre serveur. Essayons de modifier sa configuration en direct, afin -d'ajouter une redirection de port : +d'ajouter une redirection de port :
```bash @@ -71,13 +71,13 @@ docker service update --publish-add 80 myWebS service sont stoppés puis, le manager voyant que le service n'est pas dans l'état demandé, va lancer des tâches avec la nouvelle configuration. -La commande `update` est très puissante : vous pouvez mettre à jour +La commande `update` est très puissante : vous pouvez mettre à jour pratiquement n'importe quel élément de configuration, y compris le nom de l'image ou son tag. Grâce à cela, faire des mises à jour se fait de manière transparente. -#### Magie du mesh +##### Magie du mesh {-} Lorsque l'on publie un port de cette manière, chaque nœud du cluster devient un point d'entrée pour ce port, même si la tâche ne s'exécute pas sur ce nœud @@ -88,25 +88,26 @@ nœuds. Vous devriez voir la même page. Lorsque plusieurs tâches s'exécutent pour ce service, le nœud d'entrée choisi selon un round-robin à quelle tâche il va diriger la requête. C'est grâce à ce -mécanisme qu'il est possible faire une répartition de charge très simplement. +mécanisme qu'il est possible de faire de la répartition de charge très +simplement. \vspace{1.5em} Cette méthode n'est pas la seule permettant d'exposer des ports. Mais c'est -sans doute la plus intuitive. Si vous souhaitez en apprendre plus, vous deviez -consulter la -[documentation à ce sujet](https://docs.docker.com/engine/swarm/networking/). +sans doute la plus intuitive. Si vous souhaitez en apprendre plus, vous devriez +consulter la documentation à ce sujet :\ + -### Mise à l'échelle et placement +#### Mise à l'échelle et placement On parle depuis toute à l'heure de lancer plusieurs tâches pour le même -service. La mise à l'échelle c'est ça : exécuter plusieurs conteneurs pour la +service. La mise à l'échelle, c'est ça : exécuter plusieurs conteneurs pour la même tâche afin de mieux répartir la charge, idéalement sur des machines -physique différentes. +physiques différentes. -Ce qui se fait souvent avec beaucoup de douleur hors de Docker, se résume ici à -: +Ce qui se fait souvent avec beaucoup de douleur hors de Docker, se résume ici +à :
```bash @@ -122,21 +123,21 @@ docker service ps myWebS ```
-nous montre bien, a priori 3 tâches en cours d'exécution pour ce service ! +nous montre bien, a priori 3 tâches en cours d'exécution pour ce service ! -Enfin, vous avez compris le principe ! +Enfin, vous avez compris le principe ! -## Stack ? +### Stack ? -Refermons cette longue parenthèse et revenons-en au sujet du jour : la +Refermons cette longue parenthèse et revenons-en au sujet du jour : la supervision de nos machines. Une *stack* est un groupe de services. Un projet, par exemple un site web dans -son ensemble : frontend, API, base de données, ... +son ensemble : frontend, API, base de données, ... Notre système de monitoring est une *stack* lui aussi, d'ailleurs, nous pouvons -la lancer grâce à notre `docker-compose.yml` : +la lancer grâce à notre `docker-compose.yml` :
```bash @@ -144,7 +145,7 @@ docker stack deploy --compose-file docker-compose.yml tic ```
-### Règle de déploiement +#### Règle de déploiement Par rapport à `docker-compose`, nous pouvons indiquer dans ce fichier des paramètres qui ne serviront qu'au déploiement de notre tâche. diff --git a/tutorial/docker-orchestration/swarm.md b/tutorial/docker-orchestration/swarm.md index 0d6cbc3..a7b95b4 100644 --- a/tutorial/docker-orchestration/swarm.md +++ b/tutorial/docker-orchestration/swarm.md @@ -1,61 +1,13 @@ \newpage Déploiement de conteneurs -========================= - -Historiquement, le passage d'une application en production ou simplement dans -un environnement de qualification, n'est pas toujours aisé. Parfois d'ailleurs, -on ne teste pas, on fait les modifications en production ... et à chaque -déploiement, on prie pour ne pas écraser une modification qui faisait que notre -projet tombait en marche dans cet environnement. - -Déployer des conteneurs sur sa propre machine, c'est extrêmement simple -grâce. Et mieux encore, tout l'environnement étant contenu dans l'image, il -suffit de suivre les bonnes pratiques pour que le déploiement en production se -fasse de manière transparente. - - -## L'orchestration - -Cependant, notons une différence de taille entre notre environnement de -développement sur nos machines locales et la production : les clients ! Pour -répondre de manière adéquate, il convient de dimensionner correctement les -machines, le nombre de conteneurs que chacune peut exécuter, en fonction de -caractéristiques (on privilégiera les machines avec des SSD pour les serveurs -de base de données par exemple), ... - -Il n'est pas question pour un administrateur système de faire cette répartition -de la charge à la main : le nombre de critères à prendre en compte est beaucoup -trop grand, évolue sans cesse ; cela serait trop long s'il y a beaucoup de -conteneurs et de variété de machines. - -Ce processus d'optimisation s'appelle l'*orchestration*. Il s'agit de réussir à -répartir au mieux les conteneurs sur les différentes machines disponibles. - -Ce sujet fait l'objet de très nombreuses thèse depuis plusieurs années (avant -les conteneurs, c'était pour répartir les machines virtuelles entre différents -hôtes), et autant de projets disponibles. Citons par exemple -[Google Kubernetes](https://kubernetes.io), -[Hashicorp Nomad](https://www.nomadproject.io/) ou encore -[Apache Mesos](https://mesos.apache.org/), ... - -Le point commun entre la plupart des orchestrateurs, c'est généralement leur -extrême complexité de mise en œuvre. Dans le cadre de notre TP, nous allons -plutôt utiliser l'orchestrateur intégré à Docker, dont la caractéristique -principale est sa simplicité[^dockerconEU2017]. - -[^dockerconEU2017]: À noter qu'une annonce faite à la Docker Con EU - 2017 indique le début du support de Kubernetes au sein de Docker - EE, pouvant être utilisé en symbiose avec Swarm. - - -### Concepts clefs +------------------------- Regroupés au sein d'un cluster (on parle de *swarm* pour Docker), chaque *Docker engine* représente un nœud (*node*) dans lequel on va déployer des *services*. -Certain nœud ont un rôle de *manager*, parmi ceux-ci, un seul est élu leader et +Certain nœuds ont un rôle de *manager*, parmi ceux-ci, un seul est élu leader et prendra les décisions d'orchestration. Les autres sont là pour prendre le relais en cas de dysfonctionnement sur le manager élu. @@ -66,15 +18,16 @@ cluster. En cas de crash d'un manager ou d'un *worker*, le (nouveau) manager fera en sorte de redéployer les conteneurs perdus, afin de toujours maintenir le cluster dans l'état désiré. -En terme de cluster, des tâches sont l'équivalent des conteneurs, hors de Swarm. +En termes de cluster, des tâches sont l'équivalent des conteneurs, hors de +Swarm. -## Création du cluster Swarm +### Création du cluster Swarm -### Initialisation du cluster +#### Initialisation du cluster -La première chose à faire, est d'initialiser un cluster swarm. Pour se faire, -ce n'est pas plus compliqué que de faire : +La première chose à faire est d'initialiser un cluster Swarm. Pour se faire, +ce n'est pas plus compliqué que de faire :
```bash @@ -88,14 +41,14 @@ cluster, afin de pouvoir lancer des tâches ... au moins sur lui-même en attendant d'autres nœuds. -### Rejoindre le cluster +#### Rejoindre un cluster Pour rejoindre un cluster, il est nécessaire d'avoir le jeton associé à ce cluster. -La commande pour rejoindre le cluster et contenant le jeton, est indiquée +La commande pour rejoindre un cluster et contenant le jeton est iniquée lorsque vous initialisez le cluster. Si vous avez raté la sortie de la -commande, vous pouvez retrouver le jeton avec : +commande, vous pouvez retrouver le jeton avec :
```bash @@ -106,17 +59,11 @@ docker swarm join-token worker Lançons maintenant la commande `join` indiquée, sur une autre machine, en utilisant `docker-machine`. -**Pro tips:** envoyez votre commande `join` à votre voisin qui a réussi à - provisionner plusieurs machines Docker (via `docker-machine` ou manuellement, - peu importe du moment que les VMs ont bien accès au même réseau que votre - *Swarm*[^avertVM]). Et soyez fair-play, attendez un peu avant de lancer - l'image `embano1/cpuburn` ;) - [^avertVM]: Si vous utilisez Docker dans une VM, il faut que celle-ci soit configurée en mode bridge pour qu'elle soit sur le même sous-réseau. Il n'y a pas de problème à avoir des nœuds *workers* derrière un NAT, mais il est primordial que les managers soient joignables. Vous pouvez tenter de faire - des redirections de ports, mais le résultat n'est pas garanti ! + des redirections de ports, mais le résultat n'est pas garanti !
```bash @@ -125,11 +72,12 @@ docker swarm join --token SWMTKN-1-...-... 10.10.10.42:2377 ```
-Une fois rejoint, vous devriez voir apparaître un nouveau nœud *worker* dans : +Une fois rejoint, vous devriez voir apparaître un nouveau nœud *worker* dans :
``` 42sh$ eval $(docker-machine env -u) + 42sh$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS y9skzvuf989hjrkciu8mnsy echinoidea Ready Active @@ -138,21 +86,21 @@ ovgh6r32kgcbswb2we48br1 * wales Ready Active Leader
-### Rejoindre en tant que manager +#### Rejoindre en tant que manager Lorsqu'il est nécessaire d'avoir de la haute-disponibilité, on définit plusieurs managers. Cela permet qu'en cas de dysfonctionnement du manager, un nouveau manager soit élu. -Nous n'allons pas faire rejoindre de manager supplémentaire durant ce TP, mais +Nous n'allons pas faire rejoindre de manager supplémentaire à ce stade, mais vous pouvez facilement expérimenter la chose en lançant 5 machines virtuelles et en définissant trois des cinq machines comme étant managers. Pour que l'algorithme de consensus fonctionne de manière optimale, il convient -toujours un nombre impair de managers, Docker en recommande 3 ou 5. La pire -configuration est avec deux managers, car si un tombe, il ne peut pas savoir si -c'est lui qui est isolé (auquel cas il attendrait d'être à nouveau en ligne -avant de se proclamer leader) ou si c'est l'autre manager qui est tombé. Avec -trois managers, en cas de perte d'un manager, les deux restants peuvent -considérer qu'ils ont perdu le troisième et peuvent élire le nouveau manager -entre-eux et continuer à faire vivre le cluster. +de toujours avoir un nombre impair de managers : Docker en recommande 3 +ou 5. La pire configuration est avec deux managers, car si l'un des deux tombe, +il ne peut pas savoir si c'est lui qui est isolé (auquel cas il attendrait +d'être à nouveau en ligne avant de se procalmer leader) ou si c'est l'autre qui +est tombé. Avec trois managers, en cas de perte d'un manager, les deux restants +peuvent considérer qu'ils ont perdu le troisième et peuvent élire le nouveau +manager entre eux et continuer à faire vivre le cluster. diff --git a/tutorial/docker-orchestration/tutorial.md b/tutorial/docker-orchestration/tutorial.md index 6833810..0301d04 100644 --- a/tutorial/docker-orchestration/tutorial.md +++ b/tutorial/docker-orchestration/tutorial.md @@ -6,7 +6,7 @@ institute: EPITA date: Jeudi 18 octobre 2018 abstract: | Dans la troisième partie de ce TP, nous allons orchestrer nos - conteneurs ! + conteneurs ! \vspace{1em} @@ -21,4 +21,4 @@ abstract: | [me](https://pgp.mit.edu/pks/lookup?op=vindex&search=0x842807A84573CC96) faire signer votre clef et n'hésitez pas à [faire signer la vôtre](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/). - ... +... diff --git a/tutorial/dockerfiles/dockerfile.md b/tutorial/dockerfiles/dockerfile.md index 312738b..9b2f87e 100644 --- a/tutorial/dockerfiles/dockerfile.md +++ b/tutorial/dockerfiles/dockerfile.md @@ -1,6 +1,6 @@ \newpage -Ma première image ... par `Dockerfile` +Ma première image ... par `Dockerfile` -------------------------------------- Pour construire une image, nous ne sommes pas obligés de passer par une série @@ -22,7 +22,7 @@ l'intitulé d'une instruction (que l'on écrit généralement en majuscule), ell est suivie de ses arguments. Dans notre exemple, nous utilisons `FROM`{.dockerfile} qui indique une image de -départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée dans +départ à utiliser ; `RUN`{.dockerfile} est une commande qui sera exécutée dans le conteneur, dans le but de le construire. Pour lancer la construction de la nouvelle image, créons un nouveau dossier ne @@ -136,9 +136,9 @@ Rendez-vous ensuite dans votre navigateur sur . #### À vous de jouer {-} Utilisez l'instruction `COPY`{.dockerfile} pour afficher votre propre -`index.html` remplaçant celui installé de base par `nginx`. Si vous manquez +`index.html` remplaçant celui installé de base par `nginx`. ### Les caches @@ -177,9 +177,10 @@ images), en haut du `Dockerfile`. L'instruction `LABEL`{.dockerfile} permet d'ajouter une métadonnée à une image, sous forme de clef/valeur. -Une métadonnée -[courante](https://github.com/nginxinc/docker-nginx/blob/master/stable/debian/Dockerfile#L8) -est d'indiquer le nom du mainteneur de l'image : +Une métadonnée courante[^MAINTAINER] est d'indiquer le nom du +mainteneur de l'image : + +[^MAINTAINER]: Voir par exemple :
```dockerfile @@ -221,15 +222,15 @@ retirez cette option pour voir ce qui ne va pas, ou utilisez la commande `docker container logs`. -### Construire son application au moment de la construction du conteneur ? +### Construire son application au moment de la construction du conteneur ? Comment faire lorsque l'on a besoin de compiler une application avant de -l'intégrer dans le conteneur ? +l'intégrer dans le conteneur ? On peut vouloir lancer la compilation sur notre machine, mais cela ne sera pas très reproductible et cela aura nécessité d'installer le compilateur et les outils liés au langage que l'on souhaite compiler. Peut-être que plusieurs -versions de ces outils existent, laquelle choisir ? ... Ok c'est trop +versions de ces outils existent, laquelle choisir ? ... Ok c'est trop compliqué. D'un autre côté, si l'on fait cela dans un conteneur, celui-ci contiendra dans @@ -300,7 +301,7 @@ sélectionnera ainsi avec l'option `--target` l'un ou l'autre en fonction de l'environnement dans lequel on souhaite se déployer. -### D'autres instructions ? +### D'autres instructions ? Consultez pour la liste complète des instructions reconnues. @@ -310,12 +311,12 @@ complète des instructions reconnues. Pour mettre en application tout ce que nous venons de voir, réalisons le `Dockerfile` du service web [`youp0m`](https://you.p0m.fr/) que nous avons -utilisé la semaine dernière. +déjà utilisé précédemment. Pour réaliser ce genre de contribution, on ajoute généralement un `Dockerfile` à la racine du dépôt. -Vous pouvez cloner le dépôt de sources de `youp0m` à : +Vous pouvez cloner le dépôt de sources de `youp0m` à :\ Pour compiler le projet, vous pouvez utiliser dans votre `Dockerfile` diff --git a/tutorial/dockerfiles/entrypoint.md b/tutorial/dockerfiles/entrypoint.md index aaf91c2..db591b0 100644 --- a/tutorial/dockerfiles/entrypoint.md +++ b/tutorial/dockerfiles/entrypoint.md @@ -37,7 +37,7 @@ Hello world
Dans ce premier cas, il n'y a pas d'argument après le nom de l'image, c'est -donc le contenu de `CMD`{.dockerfile} qui est utilisé ; il est donc passé en +donc le contenu de `CMD`{.dockerfile} qui est utilisé ; il est donc passé en argument à l'`ENTRYPOINT`{.dockerfile}. Concrètement, la première ligne de commande exécutée est : diff --git a/tutorial/dockerfiles/goodpractices.md b/tutorial/dockerfiles/goodpractices.md index e4fbf9a..a9e18a1 100644 --- a/tutorial/dockerfiles/goodpractices.md +++ b/tutorial/dockerfiles/goodpractices.md @@ -27,8 +27,8 @@ dépendances ont bien été enregistrée. Ce fichier fonctionne de la même manière que le `.gitignore` : vous pouvez utiliser du globing. -Pour plus d'informations, vous pouvez consulter la documentation accessible à -. +Pour plus d'informations, vous pouvez consulter la documentation accessible à\ + ### N'installez rien de superflu @@ -40,7 +40,7 @@ comme serveur web. Un autre conteneur pourra contenir cet éditeur de texte dans les cas où vous avez besoin de modifier des données. En plus, cela réduira le temps de construction et la taille des images -produites ! +produites ! Avec `apt` par exemple, vous pouvez ajouter l'option `--no-install-recommends` lors vous installer un paquet qui vient avec de nombreuses recommandations @@ -64,7 +64,7 @@ place. #### Allez à la ligne pour séparer les longues lignes de commandes complexes\ -Aérez vos `Dockerfile` ! +Aérez vos `Dockerfile` ! N'hésitez pas à commenter et séparer les blocs logiques ensemble, comme lorsque vous codez. @@ -176,7 +176,7 @@ CMD ["-g", "daemon", "off;"] - Vous pouvez aussi utiliser un script qui servira à faire les initialisations ou les configurations nécessaire au bon fonctionnement du conteneur - (rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour + (rappelez-vous, il doit être éphémère !). Par exemple, le `Dockerfile` pour l'image de PostgreSQL possède cet entrypoint :
diff --git a/tutorial/dockerfiles/interactive.md b/tutorial/dockerfiles/interactive.md index 55feb1a..0d35352 100644 --- a/tutorial/dockerfiles/interactive.md +++ b/tutorial/dockerfiles/interactive.md @@ -9,8 +9,8 @@ docker container run -it ubuntu /bin/bash ```
-Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de -superflu : même pas d'éditeur de texte : ni vim, ni emacs, même pas `vi` ! +Nous voilà maintenant dans le conteneur ! Il est assez épuré, il n'y a rien de +superflu : même pas d'éditeur de texte : ni vim, ni emacs, même pas `vi` ! La première chose à faire est de télécharger la liste des paquets. En effet, afin de ne pas livrer de superflu, la liste des paquets et son cache ne sont @@ -69,7 +69,7 @@ doit servir de modèle. `my_nano` est le nom que vous voudrez utiliser Cette action va figer la couche la plus haute de systèmes de fichiers, qui -était jusqu'alors en lecture-écriture pour le conteneur ; afin d'en faire la +était jusqu'alors en lecture-écriture pour le conteneur ; afin d'en faire la dernière couche de notre nouvelle image. ![`docker commit`](commit.png) @@ -83,10 +83,10 @@ docker container run -it my_nano /bin/bash
Vous constatez cette fois que vous pouvez lancer `nano`, alors que vous ne -pouvez toujours pas le faire dans un conteneur issu d'une image `ubuntu` ! +pouvez toujours pas le faire dans un conteneur issu d'une image `ubuntu` ! -### Scripté ? +### Scripté ? On peut automatiser les étapes ci-dessus avec un script qui ressemblerait à ça : diff --git a/tutorial/dockerfiles/others.md b/tutorial/dockerfiles/others.md index 69d25e8..9fce49d 100644 --- a/tutorial/dockerfiles/others.md +++ b/tutorial/dockerfiles/others.md @@ -32,9 +32,10 @@ vous pouvez l'installer comme ceci :
``` +V="v0.6.3" mkdir -p ~/.docker/cli-plugins -curl https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64 \ - -L -s -S -o ~/.docker/cli-plugins/docker-buildx +curl -L -s -S -o ~/.docker/cli-plugins/docker-buildx \ + https://github.com/docker/buildx/releases/download/$V/buildx-$V.linux-amd64 chmod +x ~/.docker/cli-plugins/docker-buildx ```
@@ -52,7 +53,8 @@ docker buildx build . Nous ne rentrerons pas plus dans les détails de cette nouvelle commande, mais sachez qu'on la retrouve particulièrement fréquemment dans les *GitHub -Actions* : +Actions* :\ + #### Changer la syntaxe de nos `Dockerfile`\ @@ -108,7 +110,7 @@ La version habituelle de la syntaxe des `Dockerfile` est la version 1.1. En utilisant BuildKit, nous pouvons dès à présent passer à la version 1.2 (stable) ou 1.3 (expérimentale). -Les ajouts par rapport à la syntaxe usuelle sont répertoriés sur cette page :\ +Les ajouts par rapport à la syntaxe usuelle sont répertoriés sur cette page :\ . diff --git a/tutorial/dockerfiles/tutorial.md b/tutorial/dockerfiles/tutorial.md index 402ac7c..24df4db 100644 --- a/tutorial/dockerfiles/tutorial.md +++ b/tutorial/dockerfiles/tutorial.md @@ -6,7 +6,7 @@ institute: EPITA date: Mercredi 16 octobre 2019 abstract: | Durant ce deuxième TP, nous allons voir comment créer nos propres - images ! + images ! \vspace{1em} diff --git a/tutorial/header.tex b/tutorial/header.tex index 0392eae..1343528 100644 --- a/tutorial/header.tex +++ b/tutorial/header.tex @@ -27,6 +27,7 @@ \usepackage{tcolorbox} \usepackage{../virli} +\usepackage{../virli-section} \makeatletter \pretocmd{\subsection}{\addtocontents{toc}{\protect\addvspace{-5\p@}}}{}{} diff --git a/tutorial/k8s/Makefile b/tutorial/k8s/Makefile index 70a0630..ce61613 100644 --- a/tutorial/k8s/Makefile +++ b/tutorial/k8s/Makefile @@ -1,6 +1,6 @@ include ../pandoc-opts.mk -SOURCES_TUTO = tutorial-el.md setup.md intro.md overview.md discover.md run.md scaling.md rendu.md +SOURCES_TUTO = tutorial-el.md setup.md intro-srs.md intro.md overview.md discover.md run.md scaling.md rendu.md all: tutorial.pdf diff --git a/tutorial/k8s/discover.md b/tutorial/k8s/discover.md index d78aedd..23fe0ef 100644 --- a/tutorial/k8s/discover.md +++ b/tutorial/k8s/discover.md @@ -1,22 +1,21 @@ \newpage Découverte de `kubectl` -======================= +----------------------- `kubectl` ([prononcé](https://www.reddit.com/r/kubernetes/comments/5qthoc/how_should_i_pronounce_kubectl/) -'cube C T L', 'cube cuttle', 'kyoob cuddle', 'cube control', ...) est le principal +'cube C T L', 'cube cuttle', 'kyoob cuddle', 'cube control', ...) est le principal programme que l'on utilise pour interagir avec notre cluster. Étant donné qu'il s'agit d'un programme client, qui ne fait rien de plus que discuter avec une API REST HTTP, on peut le considérer comme un gros wrapper au dessus de `curl`. -Obtenir de l'aide ------------------ +### Obtenir de l'aide Commençons par apprivoiser `kubectl` en prenant quelques -renseignements et surtout en apprennant comment obtenir de l'aide : +renseignements et surtout en apprennant comment obtenir de l'aide :
```bash @@ -26,44 +25,43 @@ kubectl explain type
Les `type`s que vous pouvez découvrir sont ceux que l'on a vu à la -sections précédentes : `node`, `pod`, ... +sections précédentes : `node`, `pod`, ... La commande `describe` permet d'afficher l'état tel qu'il est attendu et tel qu'il est actuellement (cela permet de se rendre lorsque les deux divergent). -`get` ------ +### `get` Une autre manière, moins verbeuse, de récupérer des informations est -d'utiliser `get` : +d'utiliser `get` : ```bash kubectl get node ``` -On peut ajouter des options pour avoir plus d'infos : +On peut ajouter des options pour avoir plus d'infos : ```bash kubectl get nodes -o wide ``` -... ou rendre la sortie lisible par une machine : +... ou rendre la sortie lisible par une machine : ```bash kubectl get no -o yaml kubectl get no -o json ``` -On aimera utiliser `jq(1)` avec la sortie `-o json` : +On aimera utiliser `jq(1)` avec la sortie `-o json` : ```bash kubectl get no -o json | \ jq ".items[] | {name:.metadata.name} + .status.capacity" ``` -### Services +#### Services ```bash kubectl get services @@ -75,15 +73,15 @@ Pour le moment, nous n'avons qu'un seul service, il s'agit de l'API Kubernetes. `ClusterIP` désigne l'IP d'un service accessible en interne, pour le cluster. -### Conteneurs actifs +#### Conteneurs actifs -Jetons un œil aux conteneurs actifs : +Jetons un œil aux conteneurs actifs : ```bash kubectl get pods ``` -Regardons maintenant les `namespaces` : +Regardons maintenant les `namespaces` : ```bash kubectl get namespaces @@ -91,34 +89,33 @@ kubectl get namespaces On l'a vu, les *namespaces* ici désignent des espaces de noms qui n'ont rien à voir avec les *namespaces* de Linux. Regardons par exemple les conteneurs d'un -autre espace de noms : +autre espace de noms : ```bash kubectl -n kube-system get pods ``` -Eh oui ! De nombreux services de base pour Kubernetes tournent dans des -conteneurs, gérés par lui-même... notamment : +Eh oui ! De nombreux services de base pour Kubernetes tournent dans des +conteneurs, gérés par lui-même... notamment : -- `etcd` : notre base de données clef/valeur, -- `kube-apiserver` : l'API REST avec qui communique `kubectl`, +- `etcd` : notre base de données clef/valeur, +- `kube-apiserver` : l'API REST avec qui communique `kubectl`, - `kube-controller-manager` et `kube-scheduler`, deux autres composants indispensables, -- `coredns` : un composant additionnel pour gérer la résolution de noms internes +- `coredns` : un composant additionnel pour gérer la résolution de noms internes (pour ne pas avoir à s'embêter avec les IP), -- `kube-proxy` : 1 par nœud, pour gérer l'ouverture des ports notamment, -- `kindnet`, `weave` : 1 par nœud, le plugin réseau. +- `kube-proxy` : 1 par nœud, pour gérer l'ouverture des ports notamment, +- `kindnet`, `weave` : 1 par nœud, le plugin réseau. -Mon premier conteneur ---------------------- +### Mon premier conteneur -Prêt à lancer notre premier conteneur ?! +Prêt à lancer notre premier conteneur ?! -Pas si vite ! En fait ... Kubernetes ne permet pas de lancer de conteneur... +Pas si vite ! En fait ... Kubernetes ne permet pas de lancer de conteneur... Nous devons lancer un *pod* (qui ne contiendra qu'un seul conteneur). -### Mon premier pod +#### Mon premier pod ```bash kubectl run pingpong --image alpine ping 1.1.1.1 @@ -127,7 +124,7 @@ kubectl run pingpong --image alpine ping 1.1.1.1 `kubectl` doit nous indiquer nous qu'un *pod* a été créé. Si l'on affiche la liste des *pod*s, vous devriez avoir quelque chose qui -ressemble à cela : +ressemble à cela : ``` $ kubectl get pods @@ -135,18 +132,18 @@ NAME READY STATUS RESTARTS AGE pingpong 1/1 Running 0 123s ``` -#### Sortie d'un conteneur +##### Sortie d'un conteneur \ Allons maintenant regarder si nous recevons bien nos PONG. Pour cela, nous allons utiliser la commande `kubectl logs`. Cette commande -s'utilise d'une manière similaire à `docker logs` : +s'utilise d'une manière similaire à `docker logs` : ```bash kubectl logs pingpong ``` -ou bien : +ou bien : ```bash kubectl logs -f pingpong @@ -155,27 +152,27 @@ kubectl logs -f pingpong Notez ici l'option -f qui permet de suivre les logs en direct. -Notre premier test ayant réussi, nous pouvons arrêter de DDos Cloudflare : +Notre premier test ayant réussi, nous pouvons arrêter de DDos Cloudflare : ```bash kubectl delete pods pingpong ``` -### Déploiement³ +#### Déploiement³ -Bien ... maintenant que nous savons nous débrouiller avec `kubectl`, attaquons -les choses sérieuses : en temps normal avec Kubernetes, nous ne déploierons pas +Bien ... maintenant que nous savons nous débrouiller avec `kubectl`, attaquons +les choses sérieuses : en temps normal avec Kubernetes, nous ne déploierons pas de *pod* directement, car cela reviendrait à utiliser Docker. Nous allons plutôt créer des tâches de déploiement. -Essayons sans plus attendre de lancer nos `ping` à travers une tâche de déploiement : +Essayons sans plus attendre de lancer nos `ping` à travers une tâche de déploiement : ```bash kubectl create deployment pingpong --image=alpine -- ping 8.8.8.8 ``` -Si l'on regarde maintenant la sortie de `kubectl get all`, on obtient : +Si l'on regarde maintenant la sortie de `kubectl get all`, on obtient : ``` NAME READY STATUS RESTARTS AGE @@ -191,12 +188,12 @@ NAME DESIRED CURRENT READY AGE replicaset.apps/pingpong-98f6d5899 1 1 0 123s ``` -Oula, on a vraiment lancé tout ça ?! +Oula, on a vraiment lancé tout ça ?! -Pas de panique, on peut très facilement le décortiquer : +Pas de panique, on peut très facilement le décortiquer : Les tâches de déploiement (*deployment.apps*) sont des ressources de -haut niveau et sont là pour s'assurer que les migrations se font en douceur : +haut niveau et sont là pour s'assurer que les migrations se font en douceur : elles vont permettre de basculer progressivement les *pod*s d'une version X à une version Y (par exemple si l'on change notre ping d'alpine 3.14 vers alpine edge), mais éventuellement de revenir sur la version X si besoin, en cours de @@ -207,14 +204,14 @@ s'assurer que le nombre de *pod*s actuellement lancé est bien en adéquation av le nombre de *pod*s attendu. \ -Pour résumer : `kubectl` a créé une tâche de déploiement +Pour résumer : `kubectl` a créé une tâche de déploiement `deploy/pingpong`. Cette tâche de déploiement a créé elle-même un *replicatset* `rs/pingpong-xxxx`. Ce *replicatset* a créé un *pod* `po/pingpong-yyyy`. -### Passage à l'échelle : facile ? +#### Pasage à l'échelle : facile ? -Pour lancer 3 `ping`s en parallèle, modifions la tâche de déploiement comme suit : +Pour lancer 3 `ping`s en parallèle, modifions la tâche de déploiement comme suit : ```bash kubectl scale deploy/pingpong --replicas 3 @@ -227,7 +224,7 @@ de *pod*s en cours d'exécution, il va en lancer de nouveaux, afin de répondre la demande. \ -Et que se passe-t-il alors, si l'on tue un *pod* ? +Et que se passe-t-il alors, si l'on tue un *pod* ? ```bash kubectl delete pod pingpong-yyyy @@ -242,14 +239,14 @@ chacun des *pod*s un par un, car de nouveaux seraient créés par le recréera un similaire (avec de nouveaux *pod*s). Pour arrêter nos conteneurs, il convient donc de supprimer la tâche de -déploiement : +déploiement : ```bash kubectl delete deploy pingpong ``` -### Exposer son conteneur +#### Exposer son conteneur Exposer un conteneur revient à créer un nouveau service (une ressource *service*). Un service est une adresse IP que l'on peut considérer comme stable @@ -262,37 +259,37 @@ Une fois le *service* créé, le serveur DNS interne va permettre de résoudre l nom du *pod* depuis les autres conteneurs. -#### Types de services +##### Types de services\ -Il y a différents types de services : +Il y a différents types de services : -- `ClusterIP` (par défaut) : une adresse IP virtuelle est allouée pour le +- `ClusterIP` (par défaut) : une adresse IP virtuelle est allouée pour le service, elle n'est accessible que depuis le réseau interne (par les *pod*s et les nœuds). Il n'y a pas de translation de port à effectuer. -- `NodePort` : un port est alloué pour le service, sur tous les nœuds le +- `NodePort` : un port est alloué pour le service, sur tous les nœuds le cluster et n'importe qui peut alors s'y connecter. Le port est choisi aléatoirement. -- `LoadBalancer` : lorsque l'infrastructure sous-jacente fournit un - load-balancer (typiquement AWS, GCE, Azure, ...), un service `NodePort` est +- `LoadBalancer` : lorsque l'infrastructure sous-jacente fournit un + load-balancer (typiquement AWS, GCE, Azure, ...), un service `NodePort` est créé pour utiliser ce load-balancer externe. -- `ExternalName` : une entrée DNS est créée pour avoir un alias. +- `ExternalName` : une entrée DNS est créée pour avoir un alias. -#### Le retour de `youp0m` +##### Le retour de `youp0m`\ -Déployons maintenant l'image `youp0m` pour voir comment utiliser les *service*s : +Déployons maintenant l'image `youp0m` pour voir comment utiliser les *service*s : ```bash kubectl create deployment youp0m --image=nemunaire/youp0m ``` -Commençons par créer un service `ClusterIP` : +Commençons par créer un service `ClusterIP` : ```bash kubectl expose deployment youp0m --port 8080 ``` -Ce qui donne : +Ce qui donne : ``` $ kubectl get service @@ -304,15 +301,14 @@ Depuis un nœud du cluster, on peut donc venir interroger cette IP. Si l'on essaie avec plusieurs nœuds, on voit alors que les requêtes sont balancées sur différents nœuds. -Si vous passez par `kind`, vous pouvez constater le bon fonctionnement grâce à : +Si vous passez par `kind`, vous pouvez constater le bon fonctionnement grâce à : ```bash docker exec -it kind-control-plane curl 10.102.129.233:8080 ``` -Kubernetes dashboard --------------------- +### Kubernetes dashboard L'équipe de Kubernetes propose un tableau de bord assez pratique, qui permet de voir toutes les *resources*, comme nous l'avons fait avec `kubectl`, mais dans @@ -320,7 +316,7 @@ une interface web. Ils mettent à disposition un fichier décrivant l'état d'un cluster ayant une telle application. Nous pouvons demander à ce que notre cluster converge vers -la configuration nécessaire : +la configuration nécessaire : ```bash kubectl create -f https://virli.nemunai.re/insecure-dashboard.yaml @@ -329,13 +325,13 @@ kubectl create -f https://virli.nemunai.re/insecure-dashboard.yaml ::::: {.warning} Notez que le dashboard, avec cette configuration, va s'exécuter sans les -prérequis minimum de sécurité : pas de certificat TLS, ni +prérequis minimum de sécurité : pas de certificat TLS, ni d'authentification. Ceci est juste pour jouer avec l'interface, en production, on n'utilisera pas cette recette. ::::: -Regardons où nous pouvons contacter notre dashboard : +Regardons où nous pouvons contacter notre dashboard : ```bash $ kubectl get svc @@ -344,7 +340,7 @@ dashboard NodePort 10.96.78.69 80:31505/TCP 3m10s kubernetes ClusterIP 10.96.0.1 443/TCP 6m51s ``` -Regardons si cela répond : +Regardons si cela répond : ```bash $ docker exec -it kind-control-plane curl 10.96.78.69:80 @@ -362,7 +358,7 @@ configuration. Il va donc falloir indiquer à Kubernetes que l'on désire utiliser un port spécifique pour exposer le tableau de bord. Pour ce faire, éditons le fichier `insecure-dashboard.yaml`, pour ajouter, dans -la partie `Service` un *node port* plus spécifique : +la partie `Service` un *node port* plus spécifique : ```yaml - port: 80 @@ -371,8 +367,8 @@ la partie `Service` un *node port* plus spécifique : nodePort: 30002 ``` -Maintenant, nous n'allons pas recréer un nouveau dashboard : nous allons -simplement « appliquer » la nouvelle configuration : +Maintenant, nous n'allons pas recréer un nouveau dashboard : nous allons +simplement « appliquer » la nouvelle configuration : ```bash kubectl apply -f my-insecure-dashboard.yaml diff --git a/tutorial/k8s/intro-book.md b/tutorial/k8s/intro-book.md new file mode 100644 index 0000000..2cb68c1 --- /dev/null +++ b/tutorial/k8s/intro-book.md @@ -0,0 +1,10 @@ +\newpage + +Présentation du fil rouge +------------------------- + +Afin d'évaluer Kubernetes, nous allons travailler avec un mineur de +pépites ... de chocolat ! + +Alors, on se sert un bon thé, on prend sa boîte de gâteaux pour teniir le coup, +et c'est parti ! diff --git a/tutorial/k8s/intro-srs.md b/tutorial/k8s/intro-srs.md new file mode 100644 index 0000000..bfdadfe --- /dev/null +++ b/tutorial/k8s/intro-srs.md @@ -0,0 +1,16 @@ +\newpage + +Introduction +------------ + +Aujourd'hui, nous allons travailler avec un mineur de pépites ... de +chocolat ! + + +Comme c'est notre dernier cours ensemble, de véritables cookies sont à +gagner pour celles et ceux qui auront amassé le plus de pépites d'ici +la fin du TP[^cookies] ! Vous pouvez suivre votre progression sur +[cette page](https://virli.nemunai.re/scores.html). + +[^cookies]: dans la limite des stocks disponibles. diff --git a/tutorial/k8s/intro.md b/tutorial/k8s/intro.md index dc55b24..8091fb1 100644 --- a/tutorial/k8s/intro.md +++ b/tutorial/k8s/intro.md @@ -1,23 +1,9 @@ -\newpage - -Introduction -============ - -Aujourd'hui, nous allons travailler avec un mineur de pépites ... de chocolat ! - - -Comme c'est notre dernier cours ensemble, de véritables cookies sont à -gagner pour celles et ceux qui auront amassé le plus de pépites d'ici -la fin du TP[^cookies] ! Vous pouvez suivre votre progression sur -[cette page](https://virli.nemunai.re/scores.html). - -[^cookies]: Dans la limite des stocks disponibles. +\ ![ChocoMiner](dockercoins-diagram.svg) Fier de respecter le paradigme des micro-services, notre ChocoMiner fonctionne -ainsi : +ainsi : * le `worker` demande à `rng` de générer un grand nombre aléatoire, * le `worker` envoie ce grand nombre au `hasher`, qui lui retourne un hash, @@ -31,8 +17,9 @@ Une interface graphique (`chronograf`) permet d'interroger la base de données pour afficher des statistiques. -Obtenir l'application ---------------------- +### Obtenir l'application + +Les micro-services sont regroupés sur le dépôt suivant :
```shell @@ -41,57 +28,64 @@ git clone https://git.nemunai.re/srs/chocominer.git
-Rappels sur la découverte de services -------------------------------------- +### Rappels sur la découverte de services Dans Docker, nous avions vu que nous n'avions pas besoin de connaître les IP -des conteneurs : un serveur DNS nous permettait de se connecter aux différents +des conteneurs : un serveur DNS nous permettait de se connecter aux différents services à partir de leurs noms. -Dans Kubernetes, le même principe s'applique : dans aucun cas, nous ne devrions +Dans Kubernetes, le même principe s'applique : dans aucun cas, nous ne devrions inscrire en dur des adresses IP. Il convient d'utiliser au maximum le système -DNS, car les IP sont susceptibles de changer ! +DNS, car les IP sont susceptibles de changer ! -Tester avec `docker-compose` ----------------------------- +### Tester avec `docker-compose` +
```bash docker-compose up ``` +
-Une fois le docker-compose lancé, nous devrions pouvoir accéder à l'interface -de chronograf pour voir l'avancement de recherche de pépites : +Une fois le `docker-compose` lancé, nous devrions pouvoir accéder à l'interface +de chronograf pour voir l'avancement de recherche de pépites : -Montée en puissance -------------------- +### Montée en puissance +Avec `docker-compose`, on peut facilement monter en puissance. Commençons en +augmentant doucement le nombre de `worker`, pour voir si cela a un impact : + +
```bash docker-compose up -d --scale worker=2 ``` +
-On remarque que le nombre de hashs calculés augmente ! Génial ! +On remarque que le nombre de hashs calculés augmente ! Génial ! Continuons +d'augmenter alors : +
```bash docker-compose up -d --scale worker=10 ``` +
-Mais ça atteint un palier au bout d'un moment... +Mais l'augmentation n'est plus aussi nette, on semble atteindre un palier au +bout d'un moment... -Identification du goulot d'étranglement ---------------------------------------- +### Identification du goulot d'étranglement De nombreux outils existent pour réaliser des tests de performance, essayons `httping` sur nos différents services pour voir si un service ne serait pas -la cause des ralentissements : +la cause des ralentissements : -- Testons `rng` : `httping -c 3 localhost:8001`, -- puis testons `hasher` : `httping -c 3 localhost:8002`. +- Testons `rng` : `httping -c 3 localhost:8001`, +- puis testons `hasher` : `httping -c 3 localhost:8002`. -Il semblerait que notre application `rng` nécessite d'être exécutée en parallèle -! Mais on ne peut pas faire de répartition de charge facilement avec -`docker-compose` ! +Il semblerait que notre application `rng` nécessite d'être exécutée en +parallèle ! Mais on ne peut pas faire la répartition de charge facilement avec +`docker-compose` ! diff --git a/tutorial/k8s/overview.md b/tutorial/k8s/overview.md index 51cfc45..d97b782 100644 --- a/tutorial/k8s/overview.md +++ b/tutorial/k8s/overview.md @@ -1,16 +1,16 @@ -\newpage - Vue d'ensemble de Kubernetes -============================ +---------------------------- -*Kubernetes* est un système open source d'orchestration et de gestion de +*Kubernetes* (prononcé +Ku-ber-né-tice](https://github.com/kubernetes/kubernetes/issues/44308) en grec) +est un système open source d'orchestration et de gestion de conteneurs. C'est-à-dire qu'il se charge de coller constamment aux spécifications qu'on lui aura demandées. -Ce projet est l'aboutissement de plus d'une dizaine d'années d'expérience de -gestion de conteneurs applicatifs chez Google (rappelons que c'est eux qui ont -poussé de nombreuses technologies dans le noyau Linux, notamment les -*cgroups*, ...). +Ce projet est l'aboutissement de plus d'une dizaine d'années +d'expérience de gestion de conteneurs applicatifs chez Google +(rappelons que c'est eux qui ont poussé de nombreuses technologies +dans le noyau Linux, notamment les *cgroups*, ...). Dans Kubernetes, il n'est pas question d'indiquer comment lancer ses conteneurs, ni même quels *cgroups* utiliser. On va fournir à l'orchestrateur @@ -18,23 +18,22 @@ des informations, des *spécifications*, qui vont altérer l'état du cluster. E c'est en cherchant à être constamment dans l'état qu'on lui a décrit, qu'il va s'adapter pour répondre aux besoins. -Par exemple, on ne va pas lui expliquer comment lancer des conteneurs ou -récupérer des images ; mais on va lui demander d'avoir 5 conteneurs `youp0m` -lancés, de placer ces conteneurs derrière un load-balancer ; on pourra -également lui demander d'adapter la charge pour absorber les pics de trafic -(par exemple lors du Black Friday sur une boutique), mais également, il pourra -gérer les mises à jour des conteneurs selon différentes méthodes, ... +Par exemple, on ne va pas lui expliquer comment lancer des conteneurs +ou récupérer des images ; mais on va lui demander d'avoir 5 conteneurs +`youp0m` lancés, de placer ces conteneurs derrière un load-balancer ; +on pourra également lui demander d'adapter la charge pour absorber les +pics de trafic (par exemple lors du Black Friday sur une boutique), +mais également, on pourra gérer les mises à jour des conteneurs selon +différentes méthodes ... -Architecture de Kubernetes --------------------------- +### Architecture de Kubernetes ![Architecture de Kubernetes](k8s-archi.png) -Un cluster Kubernetes est composé d'un (ou plusieurs) nœuds *master*, et d'une -série de *workers*. +Un cluster Kubernetes est composé d’un (ou plusieurs) nœuds *master*, et d’une série de *workers*. -Sur le(s) *master(s)*, on retrouve les composants suivants : +Sur le(s) *master(s)*, on retrouve les composants suivants : API HTTP : On distingue plusieurs API, elles sont toutes utilisées pour communiquer avec @@ -56,7 +55,7 @@ Le contrôleur Chaque nœud (généralement, le nœud *master* est également *worker*) est utilisé -via deux composants : +via deux composants : `kubelet` : C'est l'agent qui va se charger de créer les conteneurs et les manager, afin @@ -72,19 +71,18 @@ effectivement se charger de lancer les conteneurs demandés par `kubelet`. Évidemment, chaque élément de l'architecture est malléable à souhait, c'est la raison pour laquelle il peut être très difficile de mettre en place une -architecture Kubernetes : avec ou sans haute-disponibilité, un nœud master +architecture Kubernetes : avec ou sans haute-disponibilité, un nœud master dédié au contrôle, avec un moteur de conteneur exotique (`rkt`, `ctr`, ...). -*Resources* ------------ +### *Resources* Avec Docker, nous avons eu l'habitude de travailler avec des objets (images, containers, networks, volumes, secrets, ...). Au sein de Kubernetes, cela s'appelle des *resources* et elles sont très nombreuses. Parmi les plus courantes, citons les types (désignés *Kind* dans l'API, rien à -voir avec le projet `kind` au début du sujet) suivants : +voir avec le projet `kind` au début du sujet) suivants : node : il s'agit d'une machine de notre cluster (elle peut être physique ou @@ -109,12 +107,11 @@ secret : comme `docker secret`, il s'agit d'un moyen de passer des données sensibles à un conteneur. -Pour voir la liste complète des *resources*, on utilise : `kubectl +Pour voir la liste complète des *resources*, on utilise : `kubectl api-resources`. -Modèle réseau -------------- +### Modèle réseau Pour Kubernetes, il n'y a qu'un seul gros réseau au sein duquel se retrouve tous les conteneurs. Il ne doit pas y avoir de NAT, que ce soit entre les @@ -135,8 +132,9 @@ loisir d'allouer l'adresse IP, d'ajouter les interfaces réseaux adéquates, de configurer les routes, les règles de pare-feu, ... -Pour aller plus loin --------------------- +### Pour aller plus loin -* [Kubernetes Documentation](https://kubernetes.io/docs/) -* [A Reference Architecture for Deploying WSO2 Middleware on Kubernetes](https://medium.com/containermind/a-reference-architecture-for-deploying-wso2-middleware-on-kubernetes-d4dee7601e8e) +* La documentation de Kubernetes : +* A Reference Architecture for Deploying WSO2 Middleware on Kubernetes :\ + +* Les spécifications CNI : diff --git a/tutorial/k8s/rendu.md b/tutorial/k8s/rendu.md index 7df82b1..116413d 100644 --- a/tutorial/k8s/rendu.md +++ b/tutorial/k8s/rendu.md @@ -30,7 +30,7 @@ Tarball Tous les exercices de ce TP sont à placer dans une tarball (pas d'archive ZIP, RAR, ...). -Voici une arborescence type : +Voici une arborescence type :
``` diff --git a/tutorial/k8s/run.md b/tutorial/k8s/run.md index b66f01d..5b639cf 100644 --- a/tutorial/k8s/run.md +++ b/tutorial/k8s/run.md @@ -1,27 +1,26 @@ \newpage Cookies dans Kube -================= +----------------- Maintenant que nous en savons un peu plus sur Kubernetes, nous allons commencer à déployer notre application ChocoMiner dans notre cluster. Pour cela, nous -allons devoir : +allons devoir : -- lancer des déploiements de ces images ; +- lancer des déploiements de ces images ; - exposer avec un ClusterIP les services qui ont besoin de communiquer - entre-eux ; + entre-eux ; - exposer avec un NodePort l'interface graphique de contrôle. -Lancement des *pod*s --------------------- +### Lancement des *pod*s -### Via Helm +#### Via Helm [Helm](https://helm.sh/) est l'équivalent d'un gestionnaire de paquets, mais pour Kubernetes. Nous avons pu voir dans la section précédente qu'il faut parfois écrire des fichiers de description YAML assez volumineux (et encore, -celui du tableau de bord est tout petit !) afin de se faire comprendre de +celui du tableau de bord est tout petit !) afin de se faire comprendre de Kubernetes. Helm se veut donc, notamment, être un moyen de packager une application, pour @@ -37,14 +36,14 @@ que `kubectl`, il n'y a rien de plus à configurer. Une fois `helm` installé, et le dépôt `influxdata` ajouté, comme précisé dans la documentation du *chart* d'InfluxDB, nous pouvons le déployer dans notre -cluster : +cluster : ```bash helm install influxdb influxdata/influxdb ``` Les valeurs de configuration indiquées dans le `README` du *chart* se modifient -ainsi : +ainsi : ```bash helm upgrade -f values.yml your-influx-name influxdata/influxdb @@ -58,18 +57,18 @@ Nous pouvons ensuite faire de même avec mixer avec la méthode ci-dessous (en adaptant certaines valeurs). -### Via `kubectl` +#### Via `kubectl` Si vous ne souhaitez pas utiliser `helm`, vous pouvez vous rabattre sur les YAML que l'on a utilisés jusqu'à maintenant, et utiliser `kubectl`. Commençons -par lancer `influxdb` : +par lancer `influxdb` : ```bash kubectl apply -f https://virli.nemunai.re/influxdb.yaml ``` Pour chronograf, la commande suivante fonctionnerait, mais prenons exemple sur -le fichier YAML d'InfluxDB pour Chronograf : +le fichier YAML d'InfluxDB pour Chronograf : ```bash kubectl create deployment chronograf --image=chronograf -- chronograf \ @@ -78,7 +77,7 @@ kubectl create deployment chronograf --image=chronograf -- chronograf \ --influxdb-password=eBoo8geingie8ziejeeg8bein6Yai1a ``` -### Notre application +#### Notre application ```bash TAG=0.1 @@ -87,7 +86,7 @@ for SERVICE in hasher rng worker; do done ``` -### Exposer les ports +#### Exposer les ports Pour trois des applications, des `ClusterIP` font l'affaire, car ils n'ont pas besoin d'être exposés en dehors du cluster. @@ -101,26 +100,27 @@ kubectl expose deployment hasher --port 80 Si vous avez utilisé le *chart* Helm d'InfluxDB, Un `ClusterIP` a été automatiquement créé. -Par contre, notre Chronograf doit être exposé, on lui alloue donc un NodePort : +Par contre, notre Chronograf doit être exposé, on lui alloue donc un NodePort : ```bash kubectl create service nodeport chronograf --tcp=8888 --node-port=30001 ``` -À ce stade, nous devrions pouvoir accéder à l'interface de Chronograf ! +À ce stade, nous devrions pouvoir accéder à l'interface de Chronograf ! Le port 30001 est exposé par `kind` (cela faisait partie des ports redirigés par -Docker entre le nœud *master* et votre machine !), nous devrions donc pouvoir -nous rendre sur : pour y voir Chronograf. +Docker entre le nœud *master* et votre machine !), nous devrions donc pouvoir +nous rendre sur : pour y voir Chronograf. -Pour afficher un graphique intéressant, on se rend dans *Explore*, on choisit -la base `chocominer.autogen`, puis la table `hashes` et enfin on sélectionne -l'élément `value`. Pour être tout à fait juste, il faut choisir la fonction -`sum`, car nous voulons afficher le nombre total de condensat générés. Un -second graphique intéressant est celui du nombre de pépites trouvées : il faut -compter (`count`) le nombre d'éléments dans la table `chunks`. +Pour afficher un graphique intéressant, on se rend dans la partie +*Explore*, puis on choisit la base `chocominer.autogen`, puis la table `hashes` +et enfin on sélectionne l'élément `value`. Pour être tout à fait juste, il faut +choisir la fonction `summ`, car nous voulons afficher le nombre total de +condensat générés. Un second graphique intéressant est celui du nombre de +pépites trouvées : il faut compter (`count`) le nombre d'éléments dans la table +`chunks`. ![Montée en charge progressive dans Chronograph](nuggets-graph.png) -Vous n'avez pas la même courbe de progression ? Continuons le TP alors, pour -augmenter la puissance de notre *rig* ! +Vous n'avez pas la même courbe de progression ? Alors continuons pour augmenter +la puissance de notre *rig* ! diff --git a/tutorial/k8s/scaling.md b/tutorial/k8s/scaling.md index a284aeb..f8b6965 100644 --- a/tutorial/k8s/scaling.md +++ b/tutorial/k8s/scaling.md @@ -1,16 +1,15 @@ -Montée en charge ----------------- +### Montée en charge -Commençons facilement, en augmentant le nombre de `workers` : +Commençons facilement, en augmentant le nombre de `workers` : ```bash kubectl scale deploy/worker --replicas=10 ``` Tout comme cela fonctionnait en partie avec `docker-compose`, on obtient ici le -même résultat. Ouf ... c'était pas trop tôt ! +même résultat. Ouf ... c'était pas trop tôt ! -Nous pouvons profiter de regarder l'augmentation en direct, via la commande : +Nous pouvons profiter de regarder l'augmentation en direct, via la commande : ```bash kubectl get pods -w @@ -20,7 +19,7 @@ Par contre, ce ne sera pas aussi simple d'augmenter le nombre de `rng`. En effet, il nous faut répartir les services entre plusieurs machines. -### Daemon sets +#### Daemon sets Une ressource *daemon sets* va s'assurer que tous les nœuds (ou une partie) vont exécuter une instance d'un *pod*. Ainsi, si un nouveau nœud rejoint le @@ -31,7 +30,7 @@ On s'en sert principalement pour exécuter une instance de daemon de stockage (tel que Ceph, `glusterd`, ...) ou pour la collecte de logs (`fluentd`, `logstash`, ...), voire du monitoring (Prometheus, `collectd`, ...) -Pour créer un *daemon sets*, il est nécessaire d'écrire un fichier YAML : +Pour créer un *daemon sets*, il est nécessaire d'écrire un fichier YAML : ```yaml apiVersion: apps/v1 @@ -78,7 +77,7 @@ spec: path: /var/lib/docker/containers ``` -Ensuite, on crée le *DaemonSet* en appliquant la nouvelle spécification : +Ensuite, on crée le *DaemonSet* en appliquant la nouvelle spécification : ```bash kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml @@ -88,17 +87,17 @@ Pour plus d'informations, consultez [la documentation](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/). -#### *DaemonSet* `rng` +##### *DaemonSet* `rng` Pour réaliser le *DaemonSet* de notre *pod* `rng`, le plus simple est de partir -d'un export de la ressource existante : +d'un export de la ressource existante : ```bash kubectl get deploy/rng -o yaml > rng.yml ``` La première chose que l'on peut faire, c'est changer le type décrit dans le -champ `kind` : +champ `kind` : ```yaml kind: DaemonSet @@ -111,24 +110,24 @@ Il vous faudra également retirer le champ `replicas` (qui n'a pas de sens ici, vu que la réplication est basée sur les nœuds), les champs `strategy`, `progressDeadlineSeconds`, ainsi que la ligne `status: {}`. -##### Force ! {-} +###### Force ! {-} En fait, plutôt que de corriger ces erreurs, on aurait aussi très bien pu -désactiver la validation comme ceci : +désactiver la validation comme ceci : ```bash kubectl apply -f rng.yml --validate=false ``` -#### Trop de *pods* `rng` {-} +##### Trop de *pods* `rng` {-} Après avoir appliqué la nouvelle spec, on constate qu'il y a beaucoup de *pod*s `rng`. En effet, l'ancien *pod* déployé avec la ressource *deployment* est toujours là. -#### Bootleneck résolu ? {-} +##### Botleneck résolu ? {-} Admirez maintenant dans Chronograf si vous avez réussi à augmenter votre nombre -de pépites ! +de pépites ! diff --git a/tutorial/k8s/setup.md b/tutorial/k8s/setup.md index 628fc24..b43b948 100644 --- a/tutorial/k8s/setup.md +++ b/tutorial/k8s/setup.md @@ -3,11 +3,9 @@ Mise en place ============= -La mise en place d'un cluster Kubernetes ([prononcé -Ku-ber-né-tice](https://github.com/kubernetes/kubernetes/issues/44308) en grec) -est une opération qui peut s'avérer très longue et complexe, car elle nécessite -l'installation et la configuration de nombreux composants avant de pouvoir être -utilisé sereinement. +La mise en place d'un cluster Kuernetes est une opération qui peut s'avérer +très longue et complexe, car elle nécessite l'installation et la configuration +de nombreux composants avant de pouvoir être utilisé pleinement. Cette opération n'étant pas très palpitante (c'est beaucoup de lecture de documentations et d'heures passées à essayer de faire tomber en marche tous les @@ -19,7 +17,7 @@ plupart des entreprises qui font le choix d'utiliser Kubernetes pour gérer leur infrastructures, choisissent de passer par un prestataire. L'entreprise délègue donc la gestion de son/ses cluster(s) à une autre entreprise, dont c'est le cœur de métier. La plupart du temps, il va s'agir d'Amazon (via [Elastic Kubernetes -Service](https://aws.amazon.com/fr/eks/)), d'Azur ([Kubernetes +Service](https://aws.amazon.com/fr/eks/)), d'Azure [Kubernetes Service](https://azure.microsoft.com/fr-fr/services/kubernetes-service/)) ou Google ([Kubernetes Engine](https://cloud.google.com/kubernetes-engine/)), mais d'autres acteurs plus petits existent aussi @@ -28,79 +26,63 @@ d'autres acteurs plus petits existent aussi ::::: {.more} Pour l'IoT ou l'Edge Computing, sur du matériel léger, il existe le projet -k3s[^k3s] : il s'agit d'une distribution Kubernetes beaucoup plus simple à +k3s[^k3s] : il s'agit d'une distribution Kubernetes beaucoup plus simple à déployer, et parfaitement adaptée à la production sur Raspberry Pi et autres. ::::: -[^k3s]: https://k3s.io/ +[^k3s]: Lightweight Kubernetes : Pour jouer aujourd'hui, plusieurs solutions s'offrent à nous pour commencer à utiliser Kubernetes facilement : -- [Docker Desktop (for Mac ou for Windows) :](#dockerdesktop) si vous êtes sur l'un de ces +- [Docker Desktop (for Mac ou for Windows) :](#dockerdesktop) si vous êtes sur l'un de ces systèmes c'est la solution la plus simple, -- [Kubernetes in Docker (kind) :](#kind) pour tenter l'aventure sur votre machine, -- [Play With Kubernetes :](#pwk) si vous ne vous en sortez pas avec `kind`. +- [Kubernetes in Docker (kind) :](#kind) pour tenter l'aventure sur votre machine, +- [Play With Kubernetes :](#pwk) si vous ne vous en sortez pas avec `kind`. \newpage -Docker for Mac/Windows {#dockerdesktop} ----------------------- +### Docker for Mac/Windows {#dockerdesktop} *Docker Desktop* pour Mac ou pour Windows intégre Kubernetes directement. Il n'est pas activé par défaut, pour cela il convient d'activer l'option dans les -préférences de l'application : +préférences de l'application : -![Paramètres de Docker Desktop](docker-desktop-k8s.png) +![Paramètres de Docker Desktop](../k8s/docker-desktop-k8s.png) Une fois l'option activée, vous pouvez passer au chapitre suivant, la commande `kubectl` devrait marcher directement pour vous. C'est principalement grâce à cette commande que nous interagirons avec l'API de Kubernetes. -Une fois que tout sera opérationnel, nous devrions obtenir : +Une fois que tout sera opérationnel, nous devrions obtenir :
``` 42sh$ kubectl version -Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.2", GitCommit:"8b5a19147530eaac9476b0ab82980b4088bbc1b2", GitTreeState:"archive", BuildDate:"2021-11-18T15:50:50Z", GoVersion:"go1.17.2", Compiler:"gc", Platform:"linux/amd64"} -Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5+k3s2", GitCommit:"724ef700bab896ff252a75e2be996d5f4ff1b842", GitTreeState:"clean", BuildDate:"2021-10-05T19:59:14Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"} +Client Version: version.Info{Major:"1", minor:"22", GitVersion:"v1.22.2", [...] +Server Version: version.Info{Major:"1", minor:"21", GitVersion:"v1.21.5", [...] ```
-Kubernetes in Docker (kind) {#kind} ---------------------------- +### Kubernetes in Docker (kind) {#kind} `kind` est un projet permettant de lancer un cluster Kubernetes directement via Docker. Pour commencer, il nous faudra télécharger le binaire (go, donc statique) -suivant (il existe pour Linux, macOS et Windows) : +suivant (il existe pour Linux, macOS et Windows) : -
-```bash -curl -Lo kind https://github.com/kubernetes-sigs/kind/releases/download/v0.11.1/kind-$(uname)-amd64 -chmod +x kind -``` -
+ -Placez le binaire dans un endroit où il sera accessible de votre `$PATH`. - -::::: {.question} - -`uname` est à remplacer par votre système d'exploitation : `darwin` (macOS), `linux`, `windows`. - -Il existe également pour d'autres architectures, consultez la [page des -versions](https://github.com/kubernetes-sigs/kind/releases/latest) pour voir -les différents binaires existants. - -::::: +Placez le binaire (`chmod +x {}`) dans un endroit où il sera accessible de +votre `$PATH`. -Notre prochaine étape est de décrire le cluster que l'on souhaite avoir : 1 +Notre prochaine étape est de décrire le cluster que l'on souhaite avoir : 1 master et 2 workers, ça fera l'affaire. Attention tout de même de ne pas être -trop extravagant, car chaque nœud consomme pas mal de RAM ! Et puis nous +trop extravagant, car chaque nœud consomme pas mal de RAM ! Et puis nous pourrons facilement changer cette configuration plus tard.
@@ -126,25 +108,19 @@ kind create cluster --config my-cluster.yml La création du cluster peut prendre quelques minutes. -Profitons-en pour télécharger `kubectl` : - -
-```bash -curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.2/bin/linux/amd64/kubectl -chmod +x kubectl -``` -
+Profitons-en pour télécharger `kubectl` :\ + C'est principalement grâce à cette commande que nous interagirons avec l'API de Kubernetes. -Une fois que tout sera opérationnel, nous devrions obtenir : +Une fois que tout sera opérationnel, nous devrions obtenir :
``` 42sh$ kubectl version -Client Version: version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.2", GitCommit:"8b5a19147530eaac9476b0ab82980b4088bbc1b2", GitTreeState:"archive", BuildDate:"2021-11-18T15:50:50Z", GoVersion:"go1.17.2", Compiler:"gc", Platform:"linux/amd64"} -Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5+k3s2", GitCommit:"724ef700bab896ff252a75e2be996d5f4ff1b842", GitTreeState:"clean", BuildDate:"2021-10-05T19:59:14Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"} +Client Version: Version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.2", [...] +Server Version: Version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5", [...] ```
@@ -153,8 +129,7 @@ pris soin de l'exposer pour vous au moment de la création du cluster. Passez ensuite au chapitre suivant si vous avez réussi à mettre en place `kind`. -Play With Kubernetes {#pwk} --------------------- +### Play With Kubernetes {#pwk} ::::: {.warning} @@ -163,18 +138,18 @@ cluster Kubernetes selon les autres méthodes décrites. ::::: -De la même manière que pour les TP utilisant Docker, si vous avez des +De la même manière que pour les exercices utilisant Docker, si vous avez des difficultés pour réaliser les exercices sur vos machines, vous pouvez utiliser le projet [Play With K8s](https://play-with-k8s.com/) qui vous donnera accès à -un bac à sable avec lequel vous pourrez réaliser tous les exercices de ce TP. +un bac à sable avec lequel vous pourrez réaliser tous les exercices. -Il nous faut créer plusieurs instances, disons 3 : parmi elles, 1 instance sera +Il nous faut créer plusieurs instances, disons 3 : parmi elles, 1 instance sera la master, nous l'utiliserons principalement, les deux autres ne feront qu'exécuter des conteneurs, nous pourrons les oublier dès qu'on les aura connectées au master. Pour initialiser notre cluster Kubernetes, nous allons devoir créer notre -master. Pour cela, dans notre première instance, nous allons taper : +master. Pour cela, dans notre première instance, nous allons taper :
```bash @@ -183,7 +158,7 @@ kubeadm init --apiserver-advertise-address $(hostname -i)
Cette action peut prendre quelques minutes et devrait se finir, si tout se -passe bien, par : +passe bien, par :
``` @@ -202,7 +177,7 @@ Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: You can now join any number of machines by running the following on each node as root: -kubeadm join --token SOMETOKEN SOMEIPADDRESS --discovery-token-ca-cert-hash SOMESHAHASH +kubeadm join --token TOKEN IPADDRESS --discovery-token-ca-cert-hash SHAHASH ```
@@ -212,18 +187,18 @@ master. Dernière étape pour la mise en place de notre cluster, il s'agit de définir un profil de politique réseau, sur le master (nous n'exécuterons plus de commande -sur les autres workers) : +sur les autres workers) :
```bash kubectl apply -n kube-system -f \ - "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 |tr -d '\n')" + "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | \ + base64 | tr -d '\n')" ```
-Minikube, k3d, MicroK8s, ... ----------------------------- +### Minikube, k3d, MicroK8s, ... Si les solutions précédentes ne sont pas adaptées à votre usage, de nombreuses autres applications permettent de mettre en place un cluster plus ou moins @@ -239,7 +214,7 @@ Vous pouvez tenter d'utiliser est un script similaire à `kind`, mais utilise `k3s`, une version plus légère et compacte de Kubernetes. -Après l'avoir installé, vous pouvez lancer +Après l'avoir installé, vous pouvez lancer :
```bash diff --git a/tutorial/virli-section.sty b/tutorial/virli-section.sty new file mode 100644 index 0000000..f98cb6d --- /dev/null +++ b/tutorial/virli-section.sty @@ -0,0 +1 @@ +\renewcommand\section{\@startsection{section}{1}{\z@}{\z@}{5mm}{\section@box}} diff --git a/tutorial/virli.sty b/tutorial/virli.sty index ea6fad8..1774046 100644 --- a/tutorial/virli.sty +++ b/tutorial/virli.sty @@ -4,8 +4,6 @@ boxsep=0mm,top=4mm,bottom=4mm,left=\oddsidemargin+1in,right=\oddsidemargin+1in, spread sidewards,fuzzy halo=1mm with ForestGreen!50!black} -\renewcommand\section{\@startsection{section}{1}{\z@}{\z@}{5mm}{\section@box}} - \newtcolorbox{alertbox}[1][]{breakable,enhanced, before skip balanced=2mm,after skip balanced=3mm, tile,left=11mm,right=2mm,top=1mm,bottom=1mm, @@ -40,5 +38,5 @@ sharp corners, underlay={% \path[fill=ForestGreen!50!white,draw=none] (interior.south west) rectangle node[white]{\Huge\bfseries (} ([xshift=6mm]interior.north west); - \path[fill=ForestGreen!50!white,draw=none] (interior.south east) rectangle node[white]{\Huge\bfseries )} ([xshift=6mm]interior.north east); + \path[fill=ForestGreen!50!white,draw=none] (interior.south east) rectangle node[white]{\Huge\bfseries )} ([xshift=-6mm]interior.north east); },#1}