diff --git a/tutorial/k8s/Makefile b/tutorial/k8s/Makefile new file mode 100644 index 0000000..2ac0da8 --- /dev/null +++ b/tutorial/k8s/Makefile @@ -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 diff --git a/tutorial/k8s/discover.md b/tutorial/k8s/discover.md new file mode 100644 index 0000000..49adb3d --- /dev/null +++ b/tutorial/k8s/discover.md @@ -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 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 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. diff --git a/tutorial/k8s/dockercoins-diagram.svg b/tutorial/k8s/dockercoins-diagram.svg new file mode 100644 index 0000000..ac05fe9 --- /dev/null +++ b/tutorial/k8s/dockercoins-diagram.svg @@ -0,0 +1,2 @@ + +
worker
worker
rng
rng
hasher
hasher
redis
redis
webui
webui
GET
GET
POST
POST
TCP
TCP
TCP
TCP
user
user
GET
GET
DockerCoins application
(five containers)
DockerCoins application<br>(five containers)<br>
\ No newline at end of file diff --git a/tutorial/k8s/intro.md b/tutorial/k8s/intro.md new file mode 100644 index 0000000..2281d16 --- /dev/null +++ b/tutorial/k8s/intro.md @@ -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 +--------------------- + +
+```shell +git clone git://git.nemunai.re/chocominer.git +``` +
+ + +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` ! diff --git a/tutorial/k8s/k8s-archi.png b/tutorial/k8s/k8s-archi.png new file mode 100644 index 0000000..6bb3847 Binary files /dev/null and b/tutorial/k8s/k8s-archi.png differ diff --git a/tutorial/k8s/overview.md b/tutorial/k8s/overview.md new file mode 100644 index 0000000..426baf9 --- /dev/null +++ b/tutorial/k8s/overview.md @@ -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) diff --git a/tutorial/k8s/rendu.md b/tutorial/k8s/rendu.md new file mode 100644 index 0000000..83780ba --- /dev/null +++ b/tutorial/k8s/rendu.md @@ -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 . 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 : + +
+``` +login_x-TP5/cmpns.sh +login_x-TP5/mydocker_exec.sh +login_x-TP5/myswitch_root.sh +``` +
diff --git a/tutorial/k8s/run.md b/tutorial/k8s/run.md new file mode 100644 index 0000000..5aa825f --- /dev/null +++ b/tutorial/k8s/run.md @@ -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 +``` diff --git a/tutorial/k8s/setup.md b/tutorial/k8s/setup.md new file mode 100644 index 0000000..c29551a --- /dev/null +++ b/tutorial/k8s/setup.md @@ -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 : + +
+```bash +curl -Lo kind https://github.com/kubernetes-sigs/kind/releases/download/v0.6.0/kind-$(uname)-amd64 +chmod +x kind +``` +
+ +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. + +
+```bash +cat > 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.16.3/bin/linux/amd64/kubectl +chmod +x kubectl +``` +
+ +C'est via cette commande que nous interagirons principalement avec l'API de +Kubernetes. + +Une fois que tout sera opérationnel, nous devrions obtenir : + +
+``` +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"} +``` +
+ + +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 : + +
+```bash +kubeadm init --apiserver-advertise-address $(hostname -i) +``` +
+ +Cette action peut prendre quelques minutes, et devrait se finir, si tout se +passe bien, par : + +
+``` +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 +``` +
+ +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) : + +
+```bash +kubectl apply -n kube-system -f \ + "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 |tr -d '\n')" +``` +
+ + +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. diff --git a/tutorial/k8s/tutorial.md b/tutorial/k8s/tutorial.md new file mode 100644 index 0000000..502bddc --- /dev/null +++ b/tutorial/k8s/tutorial.md @@ -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 à 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/). +...