Start working on tuto 5
This commit is contained in:
parent
50132f3a8f
commit
4fe5c78d9b
10 changed files with 868 additions and 0 deletions
311
tutorial/k8s/discover.md
Normal file
311
tutorial/k8s/discover.md
Normal 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue