2021 tuto

This commit is contained in:
nemunaire 2021-09-11 14:41:43 +02:00
parent ba77aca73b
commit c4bb727cd4
29 changed files with 426 additions and 261 deletions

View File

@ -1 +1 @@
../../tutorial/4/project-rendu.md
../../tutorial/5/project-rendu.md

View File

@ -7,8 +7,9 @@ Exemples
```
42sh$ ./mymoulette -h
MyMoulette, the students' nightmare, now highly secured
Usage: ./mymoulette [-v student_workdir] environment moulette_prog [moulette_arg [...]]
environment is the path to the directory containing the new rootfs
Usage: ./mymoulette [-v student_workdir] <-I docker-img|rootfs-path> moulette_prog [moulette_arg [...]]
rootfs-path is the path to the directory containing the new rootfs (exclusive with -I option)
docker-img is an image available on hub.docker.com (exclusive with rootfs-path)
moulette_prog will be the first program to be launched, must already be in the environment
student_workdir is the directory containing the code to grade
```
@ -44,7 +45,7 @@ rtt min/avg/max/mdev = 3.789/3.847/3.906/0.085 ms
<div lang="en-US">
```
42sh$ ./mymoulette ./newrootfs/ /usr/bin/curl http://www.linuxcontainers.org/ | md5sum
c7d68d1cb4737125a84cd69f55add202
79c12c02c8a08b4ec3fe219f97df8e78
```
</div>

View File

@ -2,7 +2,7 @@
title: Virtualisation légère -- Projet
author: Pierre-Olivier *nemunaire* Mercier
institute: EPITA
date: EPITA -- SRS 2020
date: EPITA -- SRS 2021
abstract: |
Le laboratoire des assistants a besoin de votre expertise afin de
renforcer la sécurité et la réactivité de son système de correction
@ -29,7 +29,7 @@ abstract: |
\vspace{1em}
Ce projet est à rendre à <virli@nemunai.re> au plus tard le dimanche
1er décembre 2019 à 23 h 42.
6 décembre 2020 à 23 h 42.
...
\newpage

View File

@ -195,7 +195,7 @@ Et de ces quelques articles :
* [Guidelines for extended attributes](https://www.freedesktop.org/wiki/CommonExtendedAttributes/)
* [File-based capabilities](https://lwn.net/Articles/211883/)
* [A bid to resurrect Linux capabilities](https://lwn.net/Articles/199004/)
* [False Boundaries and Arbitrary Code Execution](https://forums.grsecurity.net/viewtopic.php?f=7&t=2522&sid=c6fbcf62fd5d3472562540a7e608ce4e#p10271)
* [False Boundaries and Arbitrary Code Execution](https://forums.grsecurity.net/viewtopic.php?f=7&t=2522#p10271)
Pour revenir à Docker, par défaut, un certain nombre de *capabilities* sont
désactivées par défaut ; vous pouvez en ajouter et en retirer via les arguments

View File

@ -149,7 +149,7 @@ interagir avec InfluxDB :
<div lang="en-US">
```bash
docker container exec -i mytsdb influxdb <<EOF
docker container exec -i mytsdb influx <<EOF
CREATE DATABASE metrics;
SHOW DATABASES;
EOF

View File

@ -72,7 +72,7 @@ de base sous forme de tarball\ :
<div lang="en-US">
```bash
wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20191020T214501Z.tar.xz
wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20201104T214503Z.tar.xz
tar xpf stage3-amd64-*.tar.xz -C newroot/
```
</div>

View File

@ -98,5 +98,5 @@ requises seront a priori déjà sélectionnées et vous n'aurez donc pas à comp
votre propre noyau. Néanmoins, durant ce TP, nous allons nous interfacer avec
le noyau, il est donc nécessaire d'avoir les en-têtes de votre noyau.
Sous Debian, vous pouvez les installer via le paquet au nom semblable
à `linux-headers`.
Sous Debian, vous pouvez les installer via le paquet au nom semblable à
`linux-headers`. Le paquet porte le même nom sous Arch Linux et ses dérivés.

View File

@ -10,7 +10,7 @@ envoyé à une autre adresse et/ou non signé et/ou reçu après la correction n
sera pas pris en compte.
Par ailleurs, n'oubliez pas de répondre à
[l'évaluation du cours](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=308).
[l'évaluation du cours](https://virli.nemunai.re/quiz/6).
## Tarball

View File

@ -1,9 +1,9 @@
---
title: Virtualisation légère -- TP n^o^ 3
title: Virtualisation légère -- TP n^o^ 4
subtitle: Linux Internals partie 1
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA
date: Mercredi 23 octobre 2019
date: Jeudi 4 novembre 2020
abstract: |
Ce premier TP consacré aux Linux Internals va nous permettre
d'appréhender les notions de pseudos systèmes de fichiers, de
@ -12,14 +12,13 @@ abstract: |
\vspace{1em}
Certains éléments de ce TP sont à rendre à <virli@nemunai.re> au
plus tard le mercredi 6 novembre 2019 à 13 h 42. Consultez la
plus tard le jeudi 12 novembre 2020 à 12 h 42. Consultez la
dernière section de chaque partie pour plus d'information sur les
éléments à rendre.
En tant que personnes sensibilisées à la sécurité des échanges
électroniques, vous devrez m'envoyer vos rendus signés avec votre
clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re)
faire signer votre clef et n'hésitez pas à [faire signer la
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re) faire signer
votre clef et n'hésitez pas à [faire signer la
votre](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
...

View File

@ -38,13 +38,15 @@ programmes s'exécutent dans les mêmes *namespaces*.
```
</div>
Ici, `self` fait référence au processus actuellement exécuté.
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 !).
Et pourquoi pas :
<div lang="en-US">
```
42sh$ unshare -m ./cmpns $$ self
42sh# unshare -m ./cmpns $$ self
- cgroup: same
- ipc: same
- mnt: differ

View File

@ -10,8 +10,8 @@ Petite parenthèse avant de parler des *namespaces* ...
Au premier abord, les points de montage dans l'arborescence d'un système de
fichiers n'ont pas l'air d'être remplis de notions complexes : un répertoire
peut être le point d'entrée d'un montage vers la partition d'un disque
physique... ou d'une partition virtuelle, comme nous l'avons vu dans la partie
précédente.
physique... ou d'une partition virtuelle, comme nous l'avons vu dans le TP
précédent.
Mais avez-vous déjà essayé de monter la même partition d'un disque physique à
deux endroits différents de votre arborescence ?
@ -214,7 +214,7 @@ mount --make-private mountpoint
### non-attachable -- *unbindable mount*
Ce mode interdira tout tentative d'attache à un autre endroit.
Ce mode interdira toute tentative d'attache à un autre endroit.
<div lang="en-US">
```bash
@ -254,8 +254,9 @@ Il n'est pas nécessaire que le point d'accroche que l'on cherche à dupliquer
pointe sur un point de montage (c'est-à-dire, dans la plupart des cas : une
partition ou un système de fichiers virtuel). Il peut parfaitement pointer sur
un dossier, et même sur un simple fichier, à la manière d'un *hardlink*, mais
que l'on pourrait faire entre plusieurs partitions et qui ne persisterait pas au
redémarrage.
que l'on pourrait faire entre plusieurs partitions et qui ne persisterait pas
au redémarrage (le *hardlink* persiste au redémarrage, mais doit se faire au
sein d'une même partition).
Nous verrons dans la partie [*namespace* réseau](#net-ns), une utilisation
d'attache sur un fichier.
@ -269,7 +270,7 @@ faire même si un fichier est en cours d'utilisation. Il faut cependant veiller
à ce que les programmes susceptibles d'aller chercher un fichier à l'ancien
emplacement soient prévenus du changement.
On utilise pour cela l'option `--move` de `mount(8)` :
Pour déplacer un point de montage, on utilise l'option `--move` de `mount(8)` :
<div lang="en-US">
```bash
@ -285,9 +286,9 @@ mount --move /dev /newroot/dev
```
</div>
Il est courant de faire appel à cette option lorsque l'on souhaite changer la
racine de notre système de fichiers : par exemple pour passer de l'*initramfs*
au système démarré, de notre système hôte au système d'un conteneur, ...
Cette possibilité s'emploie notamment lorsque l'on souhaite changer la racine
de notre système de fichiers : par exemple pour passer de l'*initramfs* au
système démarré, de notre système hôte au système d'un conteneur, ...
## Aller plus loin {-}

View File

@ -10,8 +10,8 @@ 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 sept depuis Linux 4.6 : `cgroup`, `IPC`, `network`,
`mount`, `PID`, `user` et `UTS`.
On en dénombre sept (le dernier ayant été ajouté dans Linux 4.6) : `cgroup`,
`IPC`, `network`, `mount`, `PID`, `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
@ -27,12 +27,12 @@ Depuis Linux 2.4.19.
Cet espace de noms isole la liste des points de montage.
Chaque processus appartenant à un *namespace* différent peut monter, démonter
et réorganiser à sa guise les points de montage, sans que cela n'ait d'impact
sur les processus hors de cet espace de noms. Une partition ne sera donc pas
nécessairement démontée après un appel à `umount(2)`, elle le sera lorsqu'elle
aura effectivement été démontée de chaque *namespace* dans lequel elle était
montée.
Chaque processus appartenant à un *namespace mount* différent peut monter,
démonter et réorganiser à sa guise les points de montage, sans que cela n'ait
d'impact sur les processus hors de cet espace de noms. Une partition ne sera
donc pas nécessairement démontée après un appel à `umount(2)`, elle le sera
lorsqu'elle aura effectivement été démontée de chaque *namespace mount* dans
lequel elle était montée.
Attention il convient cependant de prendre garde aux types de liaison existant
entre vos points de montage (voir la partie sur
@ -198,20 +198,23 @@ similaire à :
```c
#include <sched.h>
#define STACKSIZE (1024*1024)
#define STACKSIZE (1024 * 1024)
static char child_stack[STACKSIZE];
int clone_flags = CLONE_CGROUP | CLONE_NEWNET | SIGCHLD;
pid_t pid = clone(do_execvp,
child_stack + STACKSIZE,
clone_flags,
&args);
pid_t pid = clone(do_execvp, // First function executed by child
child_stack + STACKSIZE, // Assume stack grows downward
clone_flags, // clone specials flags
args); // Arguments to pass to do_execvp
```
</div>
Le premier argument est un pointeur sur fonction. Il s'agit de la fonction qui
sera appelée par le nouveau processus.
Dans cet exemple, le processus fils créé disposera d'un nouvel espace de noms
pour les *CGroups* et disposera d'une nouvelle pile réseau.
Un exemple complet d'utilisation de `clone(2)` et du *namespace* `UTS` est
donné dans le `man` de l'appel système.
## Rejoindre un *namespace*
@ -310,6 +313,6 @@ les *namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il
faut ajouter [le petit dernier sur le `cgroup`
*namespace*](https://lwn.net/Articles/621006/).
[Cet article de Michael Crosby montrant l'utilisation de clone(2)](http://crosbymichael.com/creating-containers-part-1.html)
[Cet article de Michael Crosby montrant l'utilisation de clone(2)](https://web.archive.org/web/20190206073558/http://crosbymichael.com/creating-containers-part-1.html)
est également des plus intéressants, pour ce qui concerne la programmation
plus bas-niveau.

View File

@ -235,3 +235,7 @@ Pour construire une nouvelle interface de ce type :
Pour approfondir les différentes techniques de routage, je vous
recommande cet article :
[Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking).
Appliqué à Docker, vous apprécirez cet article : [Understanding Docker
Networking Drivers and their use
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/).

View File

@ -41,8 +41,8 @@ contenu de `/proc`. D'ailleurs, si l'on affiche le PID du processus courant
En l'état, beaucoup d'informations sont divulguées. Mais il n'est pas possible
de monter le bon `/proc` car il serait également monté pour les processus de
notre système initial. Pour s'en sortir, il est nécessaire de s'isoler du
*namespace* `mount`.
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`

View File

@ -15,6 +15,9 @@ sera pas pris en compte.
Pour différencier le rendu du TP, du rendu du projet, ajoutez une balise
`[PROJET]` au sujet de votre courriel, afin qu'il soit traité comme tel.
N'hésitez pas à indiquer dans le corps du courriel votre
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
drôle si vous n'avez rien à dire.
Tarball
-------

View File

@ -23,8 +23,13 @@ et exclusivement à celle-ci que vous devez envoyer vos rendus. Tout rendu
envoyé à une autre adresse et/ou non signé et/ou reçu après la correction ne
sera pas pris en compte.
Afin d'orienter correctement votre rendu, ajoutez une balise `[TP5]` au sujet
de votre courriel. N'hésitez pas à indiquer dans le corps du courriel votre
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
drôle si vous n'avez rien à dire.
Par ailleurs, n'oubliez pas de répondre à
[l'évaluation du cours](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=309).
[l'évaluation du cours](https://virli.nemunai.re/quiz/7).
Tarball
@ -37,8 +42,8 @@ Voici une arborescence type :
<div lang="en-US">
```
login_x-TP4/cmpns.sh
login_x-TP4/mydocker_exec.sh
login_x-TP4/myswitch_root.sh
login_x-TP5/cmpns.sh
login_x-TP5/mydocker_exec.sh
login_x-TP5/myswitch_root.sh
```
</div>

View File

@ -1,9 +1,9 @@
---
title: Virtualisation légère -- TP n^o^ 4
title: Virtualisation légère -- TP n^o^ 5
subtitle: Linux Internals partie 2
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA
date: Mercredi 6 novembre 2019
date: Jeudi 12 novembre 2020
abstract: |
Le but de ce second TP sur les mécanismes internes du noyau va nous
permettre d'utiliser les commandes et les appels systèmes relatifs
@ -13,12 +13,11 @@ abstract: |
\vspace{1em}
Tous les exercices de ce TP sont à rendre à <virli@nemunai.re> au
plus tard le mercredi 20 novembre 2017 à 13 h 42.
plus tard le jeudi 19 novembre 2020 à 12 h 42.
En tant que personnes sensibilisées à la sécurité des échanges
électroniques, vous devrez m'envoyer vos rendus signés avec votre
clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re)
faire signer votre clef et n'hésitez pas à [faire signer la
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re) faire signer
votre clef et n'hésitez pas à [faire signer la
votre](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
...

View File

@ -43,7 +43,9 @@ Aller c'est parti ! première chose à faire : installer et configurer
[gitlab](https://gitlab.org/) ou une autre plate-forme, mais la suite du TP
sera moins guidée pour eux).
Nous allons utiliser l'image : <https://hub.docker.com/r/gitea/gitea>.
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)).
Votre playbook resemblera à quelque chose comme ça :

View File

@ -1,6 +1,6 @@
include ../pandoc-opts.mk
SOURCES_TUTO = tutorial.md setup.md intro.md overview.md discover.md run.md scaling.md rendu.md
SOURCES_TUTO = tutorial-el.md setup.md intro.md overview.md discover.md run.md scaling.md rendu.md
all: tutorial.pdf

View File

@ -84,13 +84,13 @@ kubectl -n kube-system get pods
```
Eh oui ! De nombreux services de base pour Kubernetes tournent dans des
conteneurs, géré par lui-même... notamment :
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`,
- `kube-controller-manager` et `kube-scheduler`, deux autres composants
indispensables,
- `coredns` : un composant additionnel pour gérer la résolution de noms interne
- `coredns` : un composant additionnel pour gérer la résolution de noms internes
(pour 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.
@ -110,87 +110,98 @@ Nous devons lancer un *pod* (qui ne contiendra qu'un seul conteneur).
kubectl run pingpong --image alpine ping 1.1.1.1
```
Outre un avertissement, `kubectl` doit indiquer nous qu'une tâche de
déploiement a été créée.
`kubectl` doit nous indiquer nous qu'un *pod* a été créée.
Si l'on affiche la liste des pods, vous devriez avoir quelque chose qui
ressemble à cela :
```
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
pingpong-7d49d9bc9-k8fpg 1/1 Running 0 123s
NAME READY STATUS RESTARTS AGE
pingpong 1/1 Running 0 123s
```
#### Déploiement³
#### Sortie d'un conteneur
Si l'on affiche davantage d'informations, on obtient :
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` :
```bash
kubectl logs pingpong
```
ou bien :
```bash
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 :
```bash
kubectl delete deploy/pingpong
```
### 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
de *pod* directement, car cela reviendrait à utiliser Docker, mais des tâches
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 1.1.1.1
```
Si l'on regarde maintenant la sortie de `kubectl get all`, on obtient :
```
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/pingpong-7d49d9bc9-k8fpg 1/1 Running 0 123s
NAME READY STATUS RESTARTS AGE
pod/pingpong-98f6d5899-5wsrm 0/1 ContainerCreating 0 123s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2m3s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 123h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/pingpong 1/1 1 1 123s
deployment.apps/pingpong 0/1 1 0 123s
NAME DESIRED CURRENT READY AGE
replicaset.apps/pingpong-7d49d9bc9 1 1 1 123s
replicaset.apps/pingpong-98f6d5899 1 1 0 123s
```
Pas de panique, on peut très facilement le décortiquer :
Les tâches de déploiements (*deployment.apps*) sont des ressources de
haut-niveau et sont là pour 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 pods d'une version X à une
version Y (par exemple si l'on change notre ping d'alpine vers debian), mais
éventuellement de revenir sur la version X si besoin, en cours de migration.
Elles délèguent aux *replicatsets* la gestion des pods.
Le *replicatset* est là pour indiquer le nombre de pods que l'on désire, et
s'assure que le nombre de pods actuellement lancé est bien en adéquation avec
le nombre de pods attendus.
s'assurer que le nombre de pods actuellement lancé est bien en adéquation avec
le nombre de pods attendu.
Pour résumer : `kubectl run` 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`.
#### Sortie d'un conteneur
### Passage à l'échelle : facile ?
Bref ... 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` :
Pour lancer 3 ping en parallèle, modifions la tâche de déploiement comme suit :
```bash
kubectl logs deploy/pingpong
```
Cette ligne est la plus simple, et nous affichera la sortie du premier pod de
la tâche de déploiement.
Pour afficher un pod en particulier, il faut indiquer son nom en entier, en
remplaçant `yyyy` par son identifiant :
```bash
kubectl logs -f pingpong-yyyy
```
Notez ici l'option -f qui permet de suivre les logs en direct.
#### Mise à l'échelle : facile ?
Bien ... maintenant que nous savons nous débrouiller avec `kubectl`, attaquons
les choses sérieuses.
Pour lancer 8 ping en parallèle, modifions la tâche de déploiement comme suit :
```bash
kubectl scale deploy/pingpong --replicas 8
kubectl scale deploy/pingpong --replicas 3
```
À ce stade, comme nous ne modifions que le nombre de replicats, Kubernetes va
@ -199,55 +210,18 @@ tout simplement propager ce nombre au *replicatset* existant. Puis, le
de pods 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
```
Cela supprime bien un *pod*, mais un autre est relancé instantannément car le
*replicatset* constate une différence dans le nombre attendu.
#### Autres usages de `run`
Si l'on veut des tâche qui ne redémarrent pas systématiquement, on peut
utiliser : `kubectl run --restart=OnFailure` ou `kubectl run --restart=Never`,
... au lieu de créer des tâches de déploiement, cela va créer des *jobs* ou des
*pods*. On peut même créer l'équivalent de tâches cron avec : `kubectl run
--schedule=...`.
Comme nous venons de le voir, actuellement `kubectl run` sert un peu à tout et
n'importe quoi, la ressource créée n'est pas évidente, c'est pour cela que
l'avertissement nous recommande d'utiliser `kubectl create` :
- `kubectl create deployment` pour créer une tâche de déploiement,
- `kubectl create job` pour créer un *job*.
Dans le futur, `kubectl run` servira à lancer un *pod* à usage unique, sans
tâche de déploiement ni réplicat.
En fait, `kubectl run` génère une nouvelle spécification, qu'il envoie à l'API
de Kubernetes. On peut voir le fichier généré avec la ligne de commande
suivante :
```bash
kubectl run --dry-run -o yaml pingpong --image alpine ping 1.1.1.1
```
Le fichier YAML récupéré peut s'utiliser comme suit :
```bash
kubectl apply -f my-specs.yml
```
#### Arrêter de flooder 1.1.1.1
Ok, on s'est bien amusé à ping Cloudflare, pour ne pas être trop méchants, nous
pouvons maintenant arrêter nos pods.
Comme nous l'avons vu juste avant, il ne s'agit pas de tuer chacun des pods un
par un, car de nouveaux seraient créés par le *replicatset*. Si l'on supprime
le *replicatset*, la tâche de déploiement en rećréera un similaire.
Si nous voulons arrêter de DDoS Cloudflare, il ne s'agit pas de tuer chacun des
pods un par un, car de nouveaux seraient créés par le *replicatset*. Si l'on
supprime le *replicatset*, la tâche de déploiement en rećréera un similaire.
Pour arrêter nos conteneurs, il convient donc de supprimer la tâche de
déploiement :
@ -276,13 +250,13 @@ Il y a différents types de services :
- `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 pods et
les nœuds). Il n'y a pas de translation de port a effectuer.
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
cluster, et n'importe qui peut alors s'y connecter. Le port est choisi
aléatoirement.
- `LoadBalancer` : lorsque l'infrastructure sous-jacente fourni un
load-balancer (typiquement AWS, GCE, Azure, ...), un service `NodePort` est
créé pour utiiser ce load-balancer externe.
créé pour utiliser ce load-balancer externe.
- `ExternalName` : une entrée DNS est créée pour avoir un alias.
@ -309,3 +283,86 @@ youp0m ClusterIP 10.102.129.233 <none> 8080/TCP 42s
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 à :
```bash
docker exec -it kind-control-plane curl 10.96.179.154:8080
```
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
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 :
```bash
kubectl create -f https://virli.nemunai.re/insecure-dashboard.yaml
```
Notez que le dashboard, avec cette configuration, va s'exécuter sans les
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 :
```bash
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard NodePort 10.96.78.69 <none> 80:31505/TCP 3m10s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6m51s
```
Regardons si cela répond :
```bash
$ docker exec -it kind-control-plane curl 127.0.0.1:31505
<p class="browsehappy">You are using an <strong>outdated</strong> browser.
```
Pas très sympa... il faudrait que l'on puisse le voir dans un navigateur plus
... moderne alors.
Étant donné que notre cluster ne se trouve pas directement sur notre machine,
mais dans différents conteneurs Docker, nous ne pouvons pas accéder à
`127.0.0.1`. Heureusement, au moment de la création de notre cluster, nous
avons renseigné plusieurs ports redirigés au sein de notre 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 :
```yaml
- port: 80
protocol: TCP
targetPort: 80
nodePort: 30002
```
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
```
En voyant la divergence entre la réalité et la configuration demandée,
Kubernetes va tout mettre en œuvre pour se conformer à nos directives. En
l'occurrence, il s'agit de changer le port qui expose le service au sein du
cluster.
En fait, on pourra faire exactement la même chose lors d'un changement de
version. Kubernetes verra la différence et appliquera une politique de
migration déterminée.
Une fois que c'est fait, nous pouvons fièrement utiliser notre navigateur pour
aller sur <http://localhost:30002/> (vous pouvez *Skip* l'authentification,
dans cette configuration d'exemple, elle n'est pas nécessaire).

View File

@ -7,8 +7,10 @@ Notre application du jour
-------------------------
Aujourd'hui, nous allons travailler avec un mineur de pépites ... de chocolat !
De véritables cookies sont à gagner pour celles et ceux qui auront amassés le
plus de pépites avant la pause !
Alors, on se fait un bon thé, on prend sa boîte de gâteaux pour tenir le coup,
et c'est parti !
<!--De véritables cookies sont à gagner pour celles et ceux qui auront amassés le
plus de pépites avant la pause !-->
![ChocoMiner](dockercoins-diagram.svg)
@ -32,7 +34,7 @@ Obtenir l'application
<div lang="en-US">
```shell
git clone https://git.nemunai.re/chocominer.git
git clone https://gitea.nemunai.re/srs/chocominer.git
```
</div>
@ -62,8 +64,8 @@ de chronograf pour voir l'avancement de recherche de pépites :
<http://localhost:8888/sources/1/dashboards/1>
Monté en puissance
------------------
Montée en puissance
-------------------
```bash
docker-compose up -d --scale worker=2
@ -88,6 +90,6 @@ la cause des ralentissements :
- 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é en parallèle
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` !

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -9,13 +9,13 @@ spécifications qu'on lui aura demandé.
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és de nombreuses technologies dans le noyau Linux, notamment les
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 des
informations, des *spécifications* qui vont altérer l'état du cluster. Et c'est
en cherchant à être constamment dans l'état que l'on lui a décrit, qu'il va
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
@ -94,7 +94,7 @@ node
pod
: un groupe de conteneurs travaillant ensemble. Il s'agit de la ressource que
l'on déploie sur un *node*. Les conteneurs au sein d'un *pod* ne peuvent pas
être séparés pour travailler sur deux *nodes* différent.
être séparés pour travailler sur deux *nodes* différents.
service
: c'est un point de terminaison (*endpoint*), stable dans le temps, sur lequel
@ -128,8 +128,8 @@ compléter ce schéma...
Chaque plugin implémente la [spécification
CNI](https://github.com/containernetworking/cni/blob/master/SPEC.md#network-configuration)
(Container Network Interface). On trouve donc autant de plugin qu'il n'y a de
besoin en terme de réseau.
(Container Network Interface). On trouve donc autant de plugin qu'il y a de
besoins en terme de réseau.
Ainsi, à la création d'un conteneur, Kubernetes va laisser aux plugins CNI le
loisir d'allouer l'adresse IP, d'ajouter les interfaces réseaux adéquates, de

View File

@ -3,8 +3,41 @@
Rendu
=====
Il n'y a rien à rendre pour ce TP. Profitez-en pour avancer sur le projet !
Modalités de rendu
------------------
Mais n'oubliez pas de répondre au
[sondage](https://www.epitaf.fr/moodle/mod/feedback/view.php?id=305) pour me
permettre d'améliorer ce cours.
Un service automatique s'occupe de réceptionner vos rendus, de faire des
vérifications élémentaires et de vous envoyer un accusé de réception (ou de
rejet).
Ce service écoute sur l'adresse <ανδροππήςρε@nemunai.re>. C'est donc à cette adresse
et exclusivement à celle-ci que vous devez envoyer vos rendus. Tout rendu
envoyé à une autre adresse et/ou non signé et/ou reçu après la correction ne
sera pas pris en compte.
Afin d'orienter correctement votre rendu, ajoutez une balise `[TP6]` au sujet
de votre courriel. N'hésitez pas à indiquer dans le corps du courriel votre
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
drôle si vous n'avez rien à dire.
Mais n'oubliez pas de répondre au [sondage](https://virli.nemunai.re/quiz/8)
pour me permettre d'améliorer ce cours.
Tarball
-------
Tous les exercices de ce TP sont à placer dans une tarball (pas d'archive ZIP,
RAR, ...).
Voici une arborescence type :
<div lang="en-US">
```
login_x-TP6/my-cluster.yml
login_x-TP6/my-dashboard.yaml
login_x-TP6/influxdb.yml # values.yml avec Helm ou le fichier passé à kubectl -f
login_x-TP6/chronograph.yml
login_x-TP6/daemonset-rng.yml
```
</div>

View File

@ -7,94 +7,87 @@ 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 :
- construire les images de notre application ;
- publier ces images dans un registre ;
- lancer des déploiements de ces images ;
- exposer avec un ClusterIP les services qui ont besoin de communiquer
entre-eux ;
- exposer avec un NodePort l'interface graphique de contrôle.
Rappels sur les registres
-------------------------
Lancement des *pods*
--------------------
Pour rappel, lorsque l'on exécute un `docker run alpine`, Docker va étendre le
nom de l'image en `library/alpine` puis `index.docker.io/library/alpine`. Pour
interroger `index.docker.io` au sujet d'une image `library/alpine:latest`.
### Via Helm
Si l'on souhaite utiliser un autre registre que le Docker Hub, il faut alors
préciser le domaine à utiliser : `registry.mycompany.io:5000/myimage:awesome`,
...
[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
Kubernetes.
Helm se veut donc, notamment, être un moyen de packager une application, pour
que ce soit plus simple de l'ajouter à son cluster k8s. L'[artifact
hub](https://artifacthub.io/) est une agrégation de différents dépôts,
permettant de trouver facilement son bonheur. On va y trouver
[`influxdb`](https://artifacthub.io/packages/helm/influxdata/influxdb) dont on
va avoir besoin pour la suite.
Sur la route du registre auto-hébergé
-------------------------------------
Mais d'abord, il va nous falloir [installer
helm](https://helm.sh/docs/intro/install/). Il utilisera la même configuration
que `kubectl`, il n'y a rien de plus à configurer.
Profitons d'avoir notre cluster Kubernetes pour y installer un registre Docker
!
Nous allons déployer l'image officielle de registre Docker : `registry` et
faire en sorte que celle-ci stocke les couches des images en local.
La subtilité à ne pas oublier, est que Docker nécessite d'avoir une connexion
chiffrée avec ses registres, à moins qu'il ne soit lancé avec le flag
`--insecure-registry`, ou que le registre soit sur `127.0.0.0/8`.
L'idée sera donc de publier notre registre via un `NodePort`, afin qu'il soit
disponible sur un port `127.0.0.1:xxxxx` de chaque nœud :
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 :
```bash
kubectl create deployment registry --image=registry
kubectl expose deploy/registry --port=5000 --type=NodePort
helm install influxdata/influxdb --generate-name
```
Pour tester, vous pouvez :
Les valeurs de configuration indiquées dans le `README` du *chart* se modifient
ainsi :
```bash
NODEPORT=$(kubectl get svc/registry -o json | jq .spec.ports[0].nodePort)
REGISTRY=127.0.0.1:$NODEPORT
curl $REGISTRY/v2/_catalog
helm upgrade -f values.yml your-influx-name influxdata/influxdb
```
```bash
docker pull busybox
docker tag busybox $REGISTRY/busybox
docker push $REGISTRY/busybox
```
Il vous sera entre-autre nécessaire d'ajouter un administrateur afin de pouvoir
utiliser la base de données.
Nous pouvons ensuite faire de même avec
[Chronograf](https://artifacthub.io/packages/helm/influxdata/chronograf) ou
mixer avec la méthode ci-dessous (en adaptant certaines valeurs).
Utiliser les images du Docker Hub
---------------------------------
### Via `kubectl`
Si vous n'avez pas réussi à déployer votre propre registre (ou si on n'est pas
en avance pour avoir le temps de regarder ça !), utilisez les images mises à
disposition sur le Docker Hub :
- `nemunaire/worker:v0.1`
- `nemunaire/rng:v0.1`
- `nemunaire/hasher:v0.1`
Lançons les images standards
----------------------------
#### `influxdb` et `chronograf`
Si vous ne souhaitez pas utiliser `helm`, vous pouvez vous rabattre sur les
YAML que l'on a utilisé jusqu'à maintenant, et utiliser `kubectl`. Commençons
par lancer `influxdb` :
```bash
kubectl create deployment chronograf --image=chronograf
kubectl apply -f https://virli.nemunai.re/influxdb.yaml
```
#### Notre application
Pour chronograf, la commande suivante fonctionnerait, mais prenons exemple sur
le fichier YAML d'InfluxDB pour Chronograf :
```bash
TAG=v0.1
kubectl create deployment chronograf --image=chronograf -- chronograf \
--influxdb-url=http://influxdb:8086 \
--influxdb-username=chronograf \
--influxdb-password=eBoo8geingie8ziejeeg8bein6Yai1a
```
### Notre application
```bash
TAG=0.1
for SERVICE in hasher rng worker; do
kubectl create deployment $SERVICE --image=nemunaire/$SERVICE:$TAG
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.
@ -112,3 +105,19 @@ kubectl create service nodeport chronograf --tcp=8888 --node-port=30001
```
À 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 : <http://localhost:30001/> 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`.
![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* !

View File

@ -1,7 +1,5 @@
\newpage
Montée en charge
================
----------------
Commençons facilement, en augmentant le nombre de `workers` :
@ -22,8 +20,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
@ -91,13 +88,13 @@ 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 :
```bash
kubectl get deploy/rng -o yaml --export > rng.yml
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
@ -108,13 +105,13 @@ kind: DaemonSet
```
Vous pouvez essayer d'appliquer cette spec, pour voir et essayer de tâtonner
grâce aux erreurs renvoyés par l'API.
grâce aux erreurs renvoyées par l'API.
Il vous faudra également retirer le champ `replicas` (qui n'a pas de sens ici,
vu que la réplication est basé sur les nœuds), les champs `strategy`,
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 :
@ -124,14 +121,14 @@ 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 *pods*
`rng`. En effet, l'ancien *pod* déployé avec la resource *deployment* est
toujours là.
### Bootleneck résolu ?
#### Bootleneck résolu ? {-}
Admirez maintenant dans Chronograf si vous avez réussi à augmenter votre nombre
de pépites !

View File

@ -3,12 +3,35 @@
Mise en place
=============
La mise en place d'un cluster Kubernetes est une opération très longue, car
elle nécessite l'installation et la configuration de nombreux composants.
Cette opération n'étant pas très palpitante, nous ne la verrons pas
aujourd'hui.
La mise en place d'un cluster Kubernetes ([prononcé
Ku-ber-né-tèce](https://github.com/kubernetes/kubernetes/issues/44308) en grec
ancien) 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.
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
composants d'un seul coup), nous ne la verrons pas aujourd'hui.
D'ailleurs, dans le milieu professionnel, il est plutôt rare de voir des
entreprises investir dans la gestion de leur propre cluster Kubernetes. La
plupart des entreprises qui choisissent d'utiliser Kubernetes pour gérer leurs
infrastructures, choisissent de passer par un prestataire. L'entreprise délègue
donc la gestion de leur cluster à une autre entreprise, dont c'est la 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://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
([OVHcloud](https://www.ovhcloud.com/fr/public-cloud/kubernetes/), ...).
Pour jouer aujourd'hui, deux solutions s'offrent à nous pour commencer à
utiliser Kubernetes facilement :
- Kubernetes in Docker (kind) : pour tenter l'aventure sur votre machine,
- Play With Kubernetes : si vous ne vous en sortez pas avec `kind`.
Pour jouer aujourd'hui, deux solutions s'offrent à nous :
Kubernetes in Docker (kind)
---------------------------
@ -17,11 +40,11 @@ Kubernetes in Docker (kind)
Docker.
Pour commencer, il nous faudra télécharger le binaire (go, donc statique)
suivant :
suivant (il existe pour Linux, macOS et Windows) :
<div lang="en-US">
```bash
curl -Lo kind https://github.com/kubernetes-sigs/kind/releases/download/v0.6.0/kind-$(uname)-amd64
curl -Lo kind https://github.com/kubernetes-sigs/kind/releases/download/v0.9.0/kind-$(uname)-amd64
chmod +x kind
```
</div>
@ -35,9 +58,16 @@ master et 2 workers. Avant de lancer leur création.
```bash
cat > my-cluster.yml <<EOF
kind: Cluster
apiVersion: kind.sigs.k8s.io/v1alpha3
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 8080
hostPort: 12345
- containerPort: 30001
hostPort: 30001
- containerPort: 30002
hostPort: 30002
- role: worker
- role: worker
EOF
@ -51,7 +81,7 @@ Profitons-en pour télécharger `kubectl` :
<div lang="en-US">
```bash
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.16.3/bin/linux/amd64/kubectl
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.19.4/bin/linux/amd64/kubectl
chmod +x kubectl
```
</div>
@ -64,11 +94,15 @@ Une fois que tout sera opérationnel, nous devrions obtenir :
<div lang="en-US">
```
42sh$ kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.3", GitCommit:"b3cbbae08ec52a7fc73d334838e18d17e8512749", GitTreeState:"archive", BuildDate:"2019-11-26T02:51:51Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.3", GitCommit:"b3cbbae08ec52a7fc73d334838e18d17e8512749", GitTreeState:"clean", BuildDate:"2019-11-16T01:01:59Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
Client Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.3", GitCommit:"1e11e4a2108024935ecfcb2912226cedeafd99df", GitTreeState:"archive", BuildDate:"2020-11-18T12:02:06Z", GoVersion:"go1.15.5", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.1", GitCommit:"206bcadf021e76c27513500ca24182692aabd17e", GitTreeState:"clean", BuildDate:"2020-09-14T07:30:52Z", GoVersion:"go1.15", Compiler:"gc", Platform:"linux/amd64"}
```
</div>
Par défaut, `kubectl` va tenter de contacter le port local 2375, `kind` aura
pris soin de l'exposer pour vous au moment de la création du cluster.
Passez ensuite à la section 2 si vous avez réussi à mettre en place `kind`.
Play With Kubernetes
--------------------
@ -135,12 +169,12 @@ kubectl apply -n kube-system -f \
Minikube, Docker for Mac/Windows, MicroK8s, ...
-----------------------------------------------
Si les solutions précédentes ne sont pas adaptés à votre usage, de nombreuses
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
complet, facilement.
Vous pouvez tenter d'utiliser
[minikube](https://kubernetes.io/docs/setup/learning-environment/minikube/),
[microk8s](https://microk8s.io/), ... Notez également que *Docker for Mac* et
*Docker for Windows* intègrent également Kubernetes depuis quelques versions ;
*Docker for Windows* intègrent aussi Kubernetes depuis quelques versions ;
il convient de l'activer dans les préférences de l'application.

View File

@ -0,0 +1,15 @@
---
title: Ελαφριά εικονικοποίηση -- Πρακτική δουλειά αριθμός 6
subtitle: κυβερνήτης
author: Πιέρ-Ολιβιέ *νεμυναιρε* [ῥαφοπώλης]{.smallcaps}
institute: ΣΠκΠΤ
date: Πέμπτη 19 Νοεμβρίου 2020
abstract: |
Ο στόχος αυτού του τελευταίου εργαστηρίου είναι να κατανοήσει το κυβερνήτης και την ενορχήστρωση εμπορευματοκιβωτίων.
\vspace{1em}
Οι ασκήσεις για αυτό το πρακτικό έργο μπορούν να επιστραφούν στη διεύθυνση <ανδροππήςρε@nemunai.re> το αργότερο την Πέμπτη 26 Νοεμβρίου 2020 στις 11:42 μ.μ., οι ερωτήσεις των μαθημάτων πρέπει επίσης να ολοκληρωθούν πριν από αυτήν την ημερομηνία. Δείτε το τελευταίο μέρος αυτού του εργαστηρίου για λεπτομέρειες.
Καθώς οι άνθρωποι γνωρίζουν την ασφάλεια των ηλεκτρονικών ανταλλαγών, πρέπει να μου στείλετε τις υπογεγραμμένες αποδόσεις σας με το κλειδί PGP. Θυμηθείτε να [με](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re) υπογράψετε το κλειδί σας και μην διστάσετε [να υπογράψετε το δικό σας](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
...

View File

@ -1,24 +1,23 @@
---
title: Virtualisation légère -- TP n^o^ 5
title: Virtualisation légère -- TP n^o^ 6
subtitle: Kubernetes
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA
date: Mercredi 27 novembre 2019
date: Jeudi 19 novembre 2020
abstract: |
Le but de ce dernier TP est d'appréhender Kubernetes et l'orchestration de
conteneurs.
\vspace{1em}
Les exercices de ce TP peuvent être rendus à <virli@nemunai.re> au
plus tard le mercredi 11 décembre 2019 à 23 h 42, des questions de
cours sont également à compléter avant cette date sur
Epitaf. Consultez la dernière partie de ce TP pour les modalités.
Les exercices de ce TP peuvent être rendus à <virli@nemunai.re> au plus tard
le jeudi 26 novembre 2020 à 23 h 42, des questions de cours sont également à
compléter avant cette date. Consultez la dernière partie de ce TP pour les
modalités.
En tant que personnes sensibilisées à la sécurité des échanges
électroniques, vous devrez m'envoyer vos rendus signés avec votre
clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re)
faire signer votre clef et n'hésitez pas à [faire signer la
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
[me](https://keys.openpgp.org/search?q=nemunaire%40nemunai.re) faire signer
votre clef et n'hésitez pas à [faire signer la
votre](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
...