La traduction de l'article a été préparée en prévision du lancement du cours .

Si vous lisez ceci, vous avez probablement entendu parler de Kubernetes (et si ce nâest pas le cas, comment ĂȘtes-vous ici ?) Mais qu'est-ce que Kubernetes, en rĂ©alitĂ© ? C'est ? ĐлО ? ЧŃĐŸ ĐČĐŸĐŸĐ±ŃĐ” ŃŃĐŸ Đ·ĐœĐ°ŃĐžŃ?
HonnĂȘtement, je ne suis pas sĂ»r Ă 100 %. Mais je pense qu'il est intĂ©ressant d'explorer et de voir ce qui se passe rĂ©ellement dans Kubernetes sous ses nombreux niveaux d'abstraction. Donc, par curiositĂ©, voyons Ă quoi ressemble rĂ©ellement un "cluster Kubernetes" minimal. (C'est bien plus simple que .)
Je suppose que vous avez des connaissances de base en Kubernetes, Linux et en conteneurs. Tout ce dont nous allons parler ici est destiné uniquement à des fins d'exploration / d'étude, ne lancez rien de cela en production !
Aperçu
Kubernetes contient de nombreux composants. Selon , l'architecture apparaĂźt comme suit :

Ici, au moins huit composants sont montrés, mais nous en ignorerons la plupart. Je tiens à déclarer que la chose minimale que l'on peut raisonnablement qualifier de Kubernetes est composée de trois composants principaux :
- kubelet
- kube-apiserver (qui dĂ©pend d'etcd â sa base de donnĂ©es)
- l'environnement d'exécution des conteneurs (dans ce cas, Docker)
Voyons ce que dit la documentation Ă leur sujet (., .). D'abord kubelet:
Un agent s'exĂ©cutant sur chaque nĆud du cluster. Il veille Ă ce que les conteneurs soient lancĂ©s dans un pod.
Cela semble suffisamment simple. Qu'en est-il de l'environnement d'exécution des conteneurs ? (container runtime) ?
L'environnement d'exécution des conteneurs est un programme conçu pour exécuter des conteneurs.
TrĂšs informatif. Mais si vous ĂȘtes familier avec Docker, vous devriez avoir une idĂ©e gĂ©nĂ©rale de ce qu'il fait. (Les dĂ©tails de la sĂ©paration des responsabilitĂ©s entre l'environnement d'exĂ©cution des conteneurs et kubelet sont en rĂ©alitĂ© assez dĂ©licats et je ne m'y attarderai pas ici.)
Et API-server?
Le serveur API est le composant du tableau de bord Kubernetes qui expose l'API Kubernetes. Le serveur API est la partie cliente du tableau de bord Kubernetes.
Quiconque ayant dĂ©jĂ utilisĂ© Kubernetes a dĂ» interagir avec l'API, que ce soit directement ou via kubectl. C'est le cĆur mĂȘme de ce qui fait de Kubernetes un Kubernetes â le cerveau qui transforme les montagnes de YAML, que nous connaissons et aimons tous (?), en une infrastructure fonctionnelle. Il semble Ă©vident que l'API doit ĂȘtre prĂ©sente dans notre configuration minimale.
Conditions préalables
- Une machine virtuelle ou physique Linux avec accĂšs root (j'utilise Ubuntu 18.04 sur une machine virtuelle).
- Et c'est tout !
Installation ennuyeuse
Docker doit ĂȘtre installĂ© sur la machine que nous allons utiliser. (Je ne vais pas expliquer en dĂ©tail comment fonctionne Docker et les conteneurs ; si cela vous intĂ©resse, il y a ). Installons-le simplement avec apt:
$ sudo apt install docker.io
$ sudo systemctl start docker AprÚs cela, nous devons obtenir les binaires de Kubernetes. En réalité, pour le démarrage initial de notre "cluster", nous avons seulement besoin de kubelet, car pour exécuter les autres composants serveur, nous pourrons utiliser kubelet. Pour interagir avec notre cluster une fois qu'il sera opérationnel, nous utiliserons également kubectl.
$ curl -L https://dl.k8s.io/v1.18.5/kubernetes-server-linux-amd64.tar.gz > server.tar.gz
$ tar xzvf server.tar.gz
$ cp kubernetes/server/bin/kubelet .
$ cp kubernetes/server/bin/kubectl .
$ ./kubelet --version
Kubernetes v1.18.5 Que se passera-t-il si nous exécutons simplement kubelet?
$ ./kubelet
F0609 04:03:29.105194 4583 server.go:254] mkdir /var/lib/kubelet: permission denied kubelet doit fonctionner en tant que root. C'est assez logique, car il doit gĂ©rer tout le nĆud. Regardons ses paramĂštres :
$ ./kubelet -h
$ ./kubelet -h | wc -l
284Wow, tant d'options ! Heureusement, nous n'en aurons besoin que de quelques-unes. Voici l'un des paramÚtres qui nous intéresse :
--pod-manifest-path stringLe chemin vers le rĂ©pertoire contenant les fichiers pour les pods statiques, ou le chemin vers un fichier dĂ©crivant des pods statiques. Les fichiers commençant par un point sont ignorĂ©s. (OBSOLETE : ce paramĂštre devrait ĂȘtre dĂ©fini dans le fichier de configuration passĂ© Ă Kubelet via l'option âconfig. Pour plus d'informations, consultez .)
Ce paramĂštre nous permet de lancer â des pods qui ne sont pas contrĂŽlĂ©s par l'API Kubernetes. Les pods statiques sont rarement utilisĂ©s, mais ils sont trĂšs pratiques pour le dĂ©marrage rapide d'un cluster, justement ce dont nous avons besoin. Nous allons ignorer cet avertissement bruyant (une fois de plus, ne faites pas cela en production !) et voir si nous pouvons lancer le pod.
Tout d'abord, nous allons créer un répertoire pour les pods statiques et lancer kubelet:
$ mkdir pods
$ sudo ./kubelet --pod-manifest-path=podsEnsuite, dans un autre terminal/une autre fenĂȘtre tmux/de quelque part d'autre, nous allons crĂ©er le manifeste du pod :
$ cat < pods/hello.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello
spec:
containers:
- image: busybox
name: hello
command: ["echo", "hello world!"]
EOF kubelet commence à écrire quelques avertissements et semble que rien ne se passe. Mais ce n'est pas vrai ! Voyons cela chez Docker :
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c8a35e26663 busybox "echo 'hello world!'" 36 seconds ago Exited (0) 36 seconds ago k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
68f670c3c85f k8s.gcr.io/pause:3.2 "/pause" 2 minutes ago Up 2 minutes k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0
$ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
hello world! kubelet a lu le manifeste du pod et a donnĂ© Ă Docker l'ordre de lancer quelques conteneurs selon notre spĂ©cification. (Si vous ĂȘtes curieux d'en savoir plus sur le conteneur "pause", c'est un truc de Kubernetes â plus de dĂ©tails dans .) Kubelet lancera notre conteneur busybox avec la commande spĂ©cifiĂ©e et le redĂ©marrera indĂ©finiment tant que le pod statique ne sera pas supprimĂ©.
Félicitez-vous. Nous venons d'inventer l'une des maniÚres les plus compliquées d'afficher du texte dans le terminal !
Lançons etcd
Notre objectif final est de lancer l'API Kubernetes, mais pour cela, nous devons d'abord lancer . Créons un cluster etcd minimal en plaçant ses configurations dans le répertoire pods (par exemple, pods/etcd.yaml):
apiVersion: v1
kind: Pod
metadata:
name: etcd
namespace: kube-system
spec:
containers:
- name: etcd
command:
- etcd
- --data-dir=/var/lib/etcd
image: k8s.gcr.io/etcd:3.4.3-0
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
hostNetwork: true
volumes:
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-dataSi vous avez dĂ©jĂ travaillĂ© avec Kubernetes, de tels fichiers YAML devraient vous ĂȘtre familiers. Il convient de noter seulement deux points :
Nous avons montĂ© le dossier hĂŽte /var/lib/etcd dans le pod, pour que les donnĂ©es etcd soient conservĂ©es aprĂšs le redĂ©marrage (si cela n'est pas fait, l'Ă©tat du cluster sera effacĂ© Ă chaque redĂ©marrage du pod, ce qui n'est pas souhaitable mĂȘme pour une installation minimale de Kubernetes).
Nous avons installé hostNetwork: true. Ce paramÚtre, ce qui n'est pas surprenant, configure etcd pour utiliser le réseau hÎte au lieu du réseau interne du pod (cela facilitera la recherche du cluster etcd par l'API serveur).
Une simple vérification montre qu'etcd fonctionne bien sur localhost et sauvegarde les données sur disque :
$ curl localhost:2379/version
{"etcdserver":"3.4.3","etcdcluster":"3.4.0"}
$ sudo tree /var/lib/etcd/
/var/lib/etcd/
âââ member
âââ snap
â âââ db
âââ wal
âââ 0.tmp
âââ 0000000000000000-0000000000000000.walDĂ©marrer l'API serveur
Démarrer l'API serveur Kubernetes est encore plus simple. Le seul paramÚtre à passer est --etcd-servers, qui fait ce à quoi vous vous attendez :
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --etcd-servers=http://127.0.0.1:2379
image: k8s.gcr.io/kube-apiserver:v1.18.5
hostNetwork: true Placez ce fichier YAML dans le rĂ©pertoire pods, et l'API serveur dĂ©marrera. Une vĂ©rification avec curl montre que l'API Kubernetes Ă©coute sur le port 8080 avec un accĂšs totalement libre â aucune authentification n'est requise !
$ curl localhost:8080/healthz
ok
$ curl localhost:8080/api/v1/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/pods",
"resourceVersion": "59"
},
"items": []
}(Encore une fois, ne lancez pas cela en production ! J'ai été un peu surpris que la configuration par défaut soit si peu sécurisée. Mais je suppose que c'est fait pour faciliter le développement et les tests.)
Et, agréable surprise, kubectl fonctionne hors de la boßte sans aucune configuration supplémentaire !
$ ./kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:47:41Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:39:24Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
$ ./kubectl get pod
No resources found in default namespace.Le problĂšme
Mais si l'on creuse un peu plus, il semble que quelque chose ne va pas :
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.Les pods statiques que nous avons créés ont disparu ! En rĂ©alitĂ©, notre nĆud kubelet n'est mĂȘme pas dĂ©tectĂ© :
$ ./kubectl get nodes
No resources found in default namespace.Quel est le problÚme ? Si vous vous souvenez, il y a quelques paragraphes, nous avons lancé kubelet avec un ensemble de paramÚtres de ligne de commande trÚs simple, donc kubelet ne sait pas comment se connecter au serveur API et l'informer de son état. En consultant la documentation, nous trouvons le drapeau approprié :
--kubeconfig string
Chemin vers le fichier kubeconfig, qui indique comment se connecter au serveur API. La présence de --kubeconfig active le mode serveur API, alors que son absence --kubeconfig active le mode autonome.
Tout ce temps, sans le savoir, nous avons exécuté kubelet en mode « autonome ». (Si nous étions minutieux, nous pourrions considérer le mode autonome de kubelet comme un « Kubernetes minimal viable », mais ce serait trÚs ennuyeux). Pour obtenir une configuration « réelle », nous devons passer le fichier kubeconfig à kubelet, afin qu'il sache comment communiquer avec le serveur API. Heureusement, c'est assez simple (étant donné que nous n'avons pas de problÚmes d'authentification ou de certificats) :
apiVersion: v1
kind: Config
clusters:
- cluster:
server: http://127.0.0.1:8080
name: mink8s
contexts:
- context:
cluster: mink8s
name: mink8s
current-context: mink8s Enregistrez cela sous kubeconfig.yaml, tuez le processus kubelet et redémarrez avec les paramÚtres nécessaires :
$ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml(Au fait, si vous essayez d'accĂ©der Ă l'API via curl lorsque kubelet ne fonctionne pas, vous constaterez qu'il fonctionne toujours ! Kubelet n'est pas le « parent » de ses pods, comme Docker, il est plus semblable Ă un âdĂ©mon de gestionâ. Les conteneurs gĂ©rĂ©s par kubelet fonctionneront tant que kubelet ne les arrĂȘte pas.)
Dans quelques minutes, kubectl devrait nous montrer les pods et les nĆuds, comme nous nous y attendions :
$ ./kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
default hello-mink8s 0/1 CrashLoopBackOff 261 21h
kube-system etcd-mink8s 1/1 Running 0 21h
kube-system kube-apiserver-mink8s 1/1 Running 0 21h
$ ./kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
mink8s Ready 21h v1.18.5 10.70.10.228 Ubuntu 18.04.4 LTS 4.15.0-109-generic docker://19.3.6Cette fois, fĂ©licitons-nous vraiment (je sais que je l'ai dĂ©jĂ fait) â nous avons rĂ©ussi Ă crĂ©er un « cluster » Kubernetes minimal avec une API fonctionnelle !
Lançons un pod
Voyons maintenant ce que l'API peut faire. Commençons par un pod nginx :
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginxIci, nous allons recevoir une erreur assez intéressante :
$ ./kubectl apply -f nginx.yaml
Erreur du serveur (Interdit) : erreur lors de la création de "nginx.yaml" : les pods "nginx" sont
interdits : erreur lors de la recherche du compte de service default/default : le compte de service
"default" est introuvable
$ ./kubectl get serviceaccounts
Aucune ressource trouvée dans l'espace de noms par défaut.Ici, nous voyons à quel point notre environnement Kubernetes est désespérément incomplet - nous n'avons pas de comptes de service. Essayons encore une fois, en créant un compte de service à la main, et voyons ce qui se passe :
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
EOS
serviceaccount/default créé
$ ./kubectl apply -f nginx.yaml
Erreur du serveur (ServerTimeout) : erreur lors de la création de "nginx.yaml" : Aucun jeton API
trouvé pour le compte de service "default", réessayez aprÚs que le jeton soit
automatiquement créé et ajoutĂ© au compte de service.MĂȘme lorsque nous avons créé le compte de service manuellement, le jeton d'authentification n'est pas gĂ©nĂ©rĂ©. En continuant Ă expĂ©rimenter avec notre "cluster" minimaliste, nous dĂ©couvrirons que la plupart des choses utiles qui se produisent gĂ©nĂ©ralement automatiquement seront absentes. Le serveur API Kubernetes est assez minimaliste, la plupart des configurations lourdes automatiques se produisent dans divers contrĂŽleurs et tĂąches d'arriĂšre-plan qui ne sont pas encore exĂ©cutĂ©es.
Nous pouvons contourner ce problÚme en définissant l'option automountServiceAccountToken pour le compte de service (puisque nous n'avons pas besoin de l'utiliser) :
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
automountServiceAccountToken: false
EOS
serviceaccount/default configuré
$ ./kubectl apply -f nginx.yaml
pod/nginx créé
$ ./kubectl get pods
NOM PRĂT STATUT RESTARTS ĂGE
nginx 0/1 En attente 0 13mEnfin, le pod est apparu ! Mais en fait, il ne dĂ©marrera pas, car nous n'avons pas de (scheduler) - un autre composant important de Kubernetes. Encore une fois, nous voyons que l'API Kubernetes est Ă©tonnamment « bĂȘte » - lorsque vous crĂ©ez un pod dans l'API, il l'enregistre, mais n'essaie pas de dĂ©terminer sur quel nĆud le lancer.
En rĂ©alitĂ©, pour exĂ©cuter un pod, le planificateur n'est pas nĂ©cessaire. Vous pouvez ajouter manuellement le nĆud dans le manifeste en utilisant le paramĂštre nodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeName: mink8s
(Remplacez mink8s par le nom du nĆud.) AprĂšs suppression et application, nous voyons que nginx a dĂ©marrĂ© et Ă©coute l'adresse IP interne :
$ ./kubectl delete pod nginx
pod "nginx" supprimé
$ ./kubectl apply -f nginx.yaml
pod/nginx créé
$ ./kubectl get pods -owide
NOM PRÊT ÉTAT REDÉMARRAGES ÂGE IP NŒUD NŒUD NOMMÉ PORTES DE PRÊT
nginx 1/1 En cours d'exécution 0 30s 172.17.0.2 mink8s <none> <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Bienvenue sur nginx!</title>Pour s'assurer que le réseau entre les pods fonctionne correctement, nous pouvons exécuter curl depuis un autre pod :
$ chat <<EOS | .\/kubectl apply -f -\napiversion: v1\nkind: Pod\nmetadata:\n name: curl\nspec:\n containers:\n - image: curlimages\/curl\n name: curl\n command: ["curl", "172.17.0.2"]\n nodeName: mink8s\nEOS\npod\/curl créé\n$ .\/kubectl logs curl | head -6\n % Total % Reçu % Transf. Vitesse Moyenne Temps Temps Temps Actuel\n Dload Upload Total Dépensé Restant Vitesse
<!DOCTYPE html>
<html>
<head>
<title>Bienvenue sur nginx!</title>C'est assez intéressant d'explorer cet environnement et de voir ce qui fonctionne et ce qui ne fonctionne pas. J'ai découvert que ConfigMap et Secret fonctionnent comme prévu, mais Service et Deployment ne fonctionnent pas.
SuccĂšs !
Ce post devient long, donc je vais annoncer le gagnant et dĂ©clarer que c'est une configuration viable qui peut ĂȘtre appelĂ©e "Kubernetes". En rĂ©sumĂ© : quatre fichiers binaires, cinq paramĂštres de ligne de commande et "juste" 45 lignes YAML (pas tant que ça par rapport aux normes de Kubernetes) et nous avons beaucoup de choses qui fonctionnent :
- Les pods sont gérés via l'API Kubernetes standard (avec quelques hacks)
- On peut charger des images de conteneurs publiques et les gérer
- Les pods restent actifs et redémarrent automatiquement
- Le rĂ©seau entre les pods sur un mĂȘme nĆud fonctionne assez bien
- ConfigMap, Secret et le montage de stockage le plus simple fonctionnent comme prévu
Mais la grande partie de ce qui rend Kubernetes vraiment utile est toujours absente, par exemple :
- Le planificateur de pods
- Authentification / autorisation
- Plusieurs nĆuds
- Réseau de services
- DNS interne de cluster
- ContrÎleurs pour les comptes de service, les déploiements, l'intégration avec les fournisseurs de cloud et la plupart des autres "bonus" que Kubernetes apporte
Alors, qu'avons-nous rĂ©ellement obtenu ? L'API Kubernetes, fonctionnant indĂ©pendamment, est en fait juste une plateforme pour l'automatisation des conteneurs. Elle ne fait pas beaucoup â c'est le travail de divers contrĂŽleurs et opĂ©rateurs utilisant l'API â mais elle fournit un environnement cohĂ©rent pour l'automatisation.
Lire plus :
Source : habr.com
