Start working on tuto 5

This commit is contained in:
nemunaire 2019-11-26 16:00:39 +01:00
parent 50132f3a8f
commit 4fe5c78d9b
10 changed files with 868 additions and 0 deletions

12
tutorial/k8s/Makefile Normal file
View File

@ -0,0 +1,12 @@
include ../pandoc-opts.mk
SOURCES_TUTO = tutorial.md setup.md intro.md overview.md discover.md run.md rendu.md
all: tutorial.pdf
tutorial.pdf: ${SOURCES_TUTO}
pandoc ${PANDOCOPTS} -o $@ $+
clean::
rm tutorial.pdf

311
tutorial/k8s/discover.md Normal file
View File

@ -0,0 +1,311 @@
\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
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
-----------------
```bash
kubectl describe type/name
kubectl describe type name
kubectl explain type
```
`get`
-----
```bash
kubectl get node
```
Plus d'infos :
```bash
kubectl get nodes -o wide
```
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` :
```bash
kubectl get no -o json | \
jq ".items[] | {name:.metadata.name} + .status.capacity"
```
### Services
```bash
kubectl get services
kubectl get svc
```
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
Jetons un œil aux conteneurs actifs :
```bash
kubectl get pods
```
Regardons maintenant les `namespaces` :
```bash
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 :
```bash
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 :
- `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
(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.
Mon premier conteneur
---------------------
Prêt à lancer notre premier 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
```bash
kubectl run pingpong --image alpine ping 1.1.1.1
```
Outre un avertissement, `kubectl` doit indiquer qu'une tâche de déploiement 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
```
#### Déploiement³
Si l'on affiche davantage d'informations, on obtient :
```
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/pingpong-7d49d9bc9-k8fpg 1/1 Running 0 123s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2m3s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/pingpong 1/1 1 1 123s
NAME DESIRED CURRENT READY AGE
replicaset.apps/pingpong-7d49d9bc9 1 1 1 123s
```
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 :
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.
Pour résumer : `kubectl run` 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
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` :
```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
```
À ce stade, comme nous ne modifions que le nombre de replicats, Kubernetes va
tout simplement propager ce nombre au *replicatset* existant. Puis, le
*replicatset* voyant un décalage entre le nombre de pods attendus et le nombre
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 ?
```bash
kubectl delete pod pingpong-yyyy
```
#### 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.
Pour arrêter nos conteneurs, il convient donc de supprimer la tâche de
déploiement :
```bash
kubectl delete deploy/pingpong
```
### Exposer son conteneur
Exposer un conteneur revient à créer un nouveau service (une *resource*
service). Un service est une adresse IP que l'on peut considérer comme stable
pour un *pod* ou un groupe de *pods*.
Il est nécessaire de créer un service si l'on veut pouvoir se connecter à un
*pod*.
Une fois le service créé, le serveur DNS interne va permettre de résoudre le
nom du *pod* depuis les autres conteneurs.
#### Types de services
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.
- `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.
- `ExternalName` : une entrée DNS est créée pour avoir un alias.
#### Le retour de `youp0m`
```bash
kubectl create deployment youp0m --image=nemunaire/youp0m
```
Commençons par créer un service `ClusterIP` :
```bash
kubectl expose deployment youp0m --port 8080
```
Ce qui donne :
```
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
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.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

87
tutorial/k8s/intro.md Normal file
View File

@ -0,0 +1,87 @@
\newpage
Introduction
============
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 !
![ChocoMiner](dockercoins-diagram.svg)
Fier de respecter le paradigme des micro-services, notre ChocoMiner fonctionne
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,
* si le condensat respecte les contraintes pour obtenir une pépite, on est content,
* et on recommence, ainsi de suite, pour avoir le maximum de pépites.
Chaque seconde, le `worker` envoie à `influxdb` le nombre de hashs et de
pépites qu'il a ainsi pu obtenir.
Une interface graphique (`chronograf`) permet d'interroger la base de données
pour afficher des statistiques.
Obtenir l'application
---------------------
<div lang="en-US">
```shell
git clone git://git.nemunai.re/chocominer.git
```
</div>
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
services à partir de leurs noms.
Dans Kubernetes, le même principe s'applique : dans aucun cas, nous ne devrions
coder en dur des adresses IP. Il convient d'utiliser au maximum le système de
DNS, car les IP sont susceptibles de changer !
Tester avec `docker-compose`
----------------------------
`docker-compose up`
Se connecter à chronograf sur le port qui va bien
Monté en puissance
------------------
`docker-compose up -d --scale worker=2`
Ok :-)
`docker-compose up -d --scale worker=10`
Argh :-(
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.
`rng`
: `httping -c 3 localhost:8001`
`hasher`
: `httping -c 3 localhost:8002`
Il semblerait que notre application `rng` nécessite d'être exécuté en parallèle
! Mais on ne peut pas faire de répartition de charge facilement avec
`docker-compose` !

BIN
tutorial/k8s/k8s-archi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

143
tutorial/k8s/overview.md Normal file
View File

@ -0,0 +1,143 @@
\newpage
Vue d'ensemble de Kubernetes
============================
*Kubernetes* 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é.
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
*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
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, ...
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*.
Sur le master, on retrouve les composants suivants :
API HTTP
: On distingue plusieurs API, elles sont toutes utilisées pour communiquer avec
le cluster, pour son administration.
L'ordonnanceur
: Il a la responsabilité de monitorer les ressources utilisées sur chaque nœud
et de répartir les conteneurs en fonction des ressources disponibles.
Le contrôleur
: Il va contrôler l'état des applications déployées au sein du cluster, pour
s'assurer d'être dans l'état désiré.
**`etcd`**
: Il s'agit d'une base de données clef/valeur, supportant la
haute-disponibilité, que Kubernetes emploie comme système de stockage
persistant pour les objets d'API.
Chaque nœud[^minion] (généralement, le nœud *master* est également *worker*) est utilisé
via deux composants :
[^minion]: historiquement, avant de parler de *node*, on parlait de
*minion*. Vous êtes susceptibles de rencontrer encore ce terme dans
certaines documentations.
`kubelet`
: C'est l'agent qui va se charger de créer les conteneurs et les manager, afin
de répondre aux spécifications.
`kube-proxy`
: Ce programme va servir de load-balancer pour se connecter aux pods.
Sans oublier le moteur de conteneurs (généralement Docker), qui va
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
dédié au contrôle, avec un moteur de conteneur exotique (`rkt`, `ctr`, ...).
*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)
suivants :
node
: il s'agit d'une machine physique ou virtuelle, de notre cluster.
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.
service
: c'est un point de terminaison (*endpoint*), stable dans le temps, sur lequel
on peut se connecter pour accéder à un ou plusieurs
conteneurs. Historiquement, appelés portails/*portals*, on les retrouve
encore quelques fois désignés ainsi dans de vieux articles.
namespace
: à ne pas confondre avec les *namespaces* Linux. Ici il s'agit d'espaces de
noms divers, pour Kubernetes.
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
api-resources`.
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
*pods* ou les *nodes*, chacun doit pouvoir contacter n'importe quel autre
élément, sans qu'il y ait de routage.
C'est un modèle assez simpliste au premier abord, mais en raison de la
nécessité de faire un minimum de filtrage, de nombreuses extensions viennent
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.
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
configurer les routes, les règles de pare-feu, ...
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)

36
tutorial/k8s/rendu.md Normal file
View File

@ -0,0 +1,36 @@
\newpage
Rendu
=====
Modalités de rendu
------------------
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 <virli@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.
Par ailleurs, n'oubliez pas de répondre à
[l'évaluation du cours](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=309).
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-TP5/cmpns.sh
login_x-TP5/mydocker_exec.sh
login_x-TP5/myswitch_root.sh
```
</div>

107
tutorial/k8s/run.md Normal file
View File

@ -0,0 +1,107 @@
\newpage
Cookies dans Kube
=================
Maintenant que nous en savons un peu plus sur Kubernetes, nous allons commencer
à déployer notre application ChochMiner 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
-------------------------
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`.
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`,
...
Sur la route du registre auto-hébergé
-------------------------------------
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 :
```bash
kubectl create deployment registry --image=registry
kubectl expose deploy/registry --port=5000 --type=NodePort
```
Pour tester, vous pouvez :
```bash
NODEPORT=$(kubectl get svc/registry -o json | jq .spec.ports[0].nodePort)
REGISTRY=127.0.0.1:$NODEPORT
curl $REGISTRY/v2/_catalog
```
```bash
docker pull busybox
docker tag busybox $REGISTRY/busybox
docker push $REGISTRY/busybox
```
Utiliser les images du Docker Hub
---------------------------------
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`
- etc.
Lançons les images standards
----------------------------
#### `influxdb` et `chronograf`
```bash
kubectl create deployment influxdb --image=influxdb
kubectl create deployment chronograf --image=chronograf
```
#### Notre application
```bash
TAG=v0.1
for SERVICE in hasher rng worker; do
kubectl create deployment $SERVICE --image=nemunaire/$SERVICE:$TAG
done
```
#### Exposer les ports
```bash
kubectl expose deployment influxdb --port 8088
kubectl expose deployment rng --port 80
kubectl expose deployment hasher --port 80
```
```bash
kubectl create service nodeport chronograf --tcp=8888 --node-port=30001
```

146
tutorial/k8s/setup.md Normal file
View File

@ -0,0 +1,146 @@
\newpage
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.
Pour jouer aujourd'hui, deux solutions s'offrent à nous :
Kubernetes in Docker (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 :
<div lang="en-US">
```bash
curl -Lo kind https://github.com/kubernetes-sigs/kind/releases/download/v0.6.0/kind-$(uname)-amd64
chmod +x kind
```
</div>
Placez-le 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
master et 2 workers. Avant de lancer leur création.
<div lang="en-US">
```bash
cat > my-cluster.yml <<EOF
kind: Cluster
apiVersion: kind.sigs.k8s.io/v1alpha3
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
kind create cluster --config my-cluster.yml
```
</div>
La création du cluster peut prendre quelques minutes.
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
chmod +x kubectl
```
</div>
C'est via cette commande que nous interagirons principalement avec l'API de
Kubernetes.
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"}
```
</div>
Play With Kubernetes
--------------------
De la même manière que pour les TP 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.
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 :
<div lang="en-US">
```bash
kubeadm init --apiserver-advertise-address $(hostname -i)
```
</div>
Cette action peut prendre quelques minutes, et devrait se finir, si tout se
passe bien, par :
<div lang="en-US">
```
Your Kubernetes master has initialized successfully!
To start using your cluster, you need to run (as a regular user):
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
http://kubernetes.io/docs/admin/addons/
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
```
</div>
Recopions ensuite la commande `kubeadm join ...` donnée dans le terminal, dans
nos deux autres instances. Cela permettra aux machines de se connecter au
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) :
<div lang="en-US">
```bash
kubectl apply -n kube-system -f \
"https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 |tr -d '\n')"
```
</div>
Minikube, Docker for Mac/Windows, MicroK8s, ...
-----------------------------------------------
Si les solutions précédentes ne sont pas adaptés à 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 ;
il convient de l'activer dans les préférences de l'application.

24
tutorial/k8s/tutorial.md Normal file
View File

@ -0,0 +1,24 @@
---
title: Virtualisation légère -- TP n^o^ 5
subtitle: Kubernetes
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
institute: EPITA
date: Mercredi 27 novembre 2019
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.
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/).
...