Nous arrivons maintenant à une étape
importante et conséquente : la création du cluster Kubernetes.
Encore une fois je vais m’inspirer du tutorial trouvable ici
mais je vais m’en éloigner quelque peu.
Je vais essayer de déployer Kubernetes en préparant l'intégration de la notion de « CNS » soit « Cloud Native Storage » que je configurerais à l'étape suivante. Il s’agit de permettre une communication entre vSphere et Kubernetes pour avoir un provisionnement automatique du stockage. Le tutorial semble utiliser VCP soit « vSphere Storage for Kubernetes », une autre solution toujours utilisée, mais dont il est maintenant conseillé de se détacher pour exploiter « CNS ». Si le sujet vous intéresse, je vous conseille la lecture de cet l’article.
Je vais donc également m’inspirer du tutorial suivant mais en essayant d’utiliser une version plus récente de KubernetesAfin de permettre à Kubernetes d’interagir avec vSphere il est nécessaire de créer un compte de service que l’on va déclarer dans l’interface d’un ou des vCenter. De mon côté j’ai choisi la facilité en lui attribuant les droits admin sur toute mon infrastructure de POC.
Comme vu précedemment, HAproxy s'installe très facilement via le packet fourni dans le repo de photonOS. Si ce n'est pas déja fait utiliser la commande
tdnf install haproxy
Il va juste être nécessaire de positionner la bonne configuration HAproxy. Pour cela il faut éditer le fichier de configuration /etc/haproxy/haproxy.cfg et ajouter les éléments de configuration suivant:
global
defaults
timeout
client 30s
timeout
server 30s
timeout
connect 30s
frontend k8s_mst
bind
192.168.10.45:6443
default_backend
backend k8s_nodes_master
mode
tcp
option tcp-check
server
prdk8smst501 192.168.10.56:6443 check
Pour l'instant on ne va configurer que l'accès à l'API de kubernetes, la configuration ci-dessus permet donc d'accéder depuis une "vip" au noeud master du cluster. Dans mon cas pour l'instant, il n'y en a qu'un, donc c'est un peu inutile. Mais cela s'avèrera nécessaire quand on ajoutera des noeuds master au cluster, donc autant préparer la configuration dès maintenant
Sous photonOS, il faut utiliser la commande suivante
tdnf install kubernetes-kubeadm
Cette commande est à taper sur chaque noeud du cluster. Non seulement elle va installer kubeadm mais également les binaires kubelet. À noter que photonOS arrive avec des repos Kubernetes déjà paramétrés. Il s'agit de binaire proposé par vmware et non des repos par défaut de Kubernetes. Il ne s'agit donc pas de la dernière version de l'écosystème K8S, mais il est préférable de retenir la version proposée par photonOS car elle assure une certaine stabilité. Maintenant rien ne vous empêche d'intégrer de nouveaux repos pour avoir la dernière release de K8S à disposition.
Son contenu va être le suivant
---
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubeletExtraArgs:
cloud-provider: external
kubernetesVersion: 1.19.7
networking:
podSubnet: "10.1.0.0/16"
serviceSubnet: "10.2.0.0/16"
controlPlaneEndpoint: "kube.coolcorp.priv:6443"
clusterName: "prdk8sclu"
apiServer:
certSANs:
- 192.168.10.45
- kube.coolcorp.priv
Les éléments en rouge correspondent à l'accès à l'api de mon cluster:
- 192.168.10.45 : c’est l’IP de ma VIP gérer par mon loadbalancer HAproxy
- kube.coolcorp.priv : C’est le nom DNS associé à ma VIP qui va pointer vers mon serveur HAProxy
-1.19.7: c’est la version de
Kubernetes que je vais déployer.
Le podSubnet
correspond au réseau IP qui va être associé à mes conteneurs dans mes
pods. Cela implique dans mon cas, que chaque conteneur aura une IP
interne en 10.1.0.0/16. Attention de choisir une plage disponible, car
il existera sur chaque noeud une "gateway" virtuelle liée au driver
réseau antrea (que je déploierais plus tard), il faut donc retenir un
réseau libre sur son infrastructure pour éviter tout conflit de
routage.
Le serviceSubnet sera quant à lui un réseau utilisé par mes objets de type "Service" au sein de mon cluster. De la même manière il est préférable choisir une plage disponible.
Je vais maintenant pouvoir créer mon cluster depuis une session root sur mon premier noeud master.
Je lance la commande suivantekubeadm init --config /etc/kubernetes/kubeadm.conf --upload-certs --v=5
(n’oubliez pas –v=5, c’est très pratique en cas d’échec afin d’avoir les détails de l’erreur)Au bout de quelques minutes, le premier nœud est initialisé et j’obtiens en sortie les commandes nécessaires à passer sur les autres nœuds pour les ajouter au cluster (ne tenez pas compte du nom de serveur issu de mon ancienne installation).
Arriver à ce stade, il serait possible d'ajouter des noeuds master via la commande suivante
Néanmoins comme déjà expliqué, je ferais cela plus tard dans un article dédié au sujet. Je vais donc me contenter d'ajouter mes noeuds worker. Pour cela, sur chacun d'eux, je tape la commande suivante rapportée par ma sortie de kubeadm.
kubeadm join kube.coolcorp.priv:6443 --token y7yaev.9dvwxx6ny4ef8vlq \
--discovery-token-ca-cert-hash sha256:345ae585ca3cdb56fdeb202b2a659b3a233aef4a75559a29889ca0f5926dd003 \
--control-plane --certificate-key d0727fe87d624010af8ad0b874023139979dfd37cc34e9092002fae93603b8f3
kubeadm join kube.coolcorp.priv:6443 --token y7yaev.9dvwxx6ny4ef8vlq \
--discovery-token-ca-cert-hash sha256:345ae585ca3cdb56fdeb202b2a659b3a233aef4a75559a29889ca0f5926dd003
J’obtiens également les commandes nécessaires à la récupération de la configuration de "kubctl" qui va me permettre de piloter mon cluster.
À noter qu’il vous suffira de récupérer le binaire windows "kubectl" et de copier le dossier .kube du noeud K8S dans votre profil utilisateur pour pouvoir piloter votre cluster depuis un poste externe sous Windows.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
On peut d’ailleurs vérifier le
statut du cluster avec la commande kubectl get node
Le noeud est “NotReady”, c’est normal pour l’instant (ne tenez pas
compte de la version et du nom de serveur, c'est une capture issue de ma
précédente installation).
Je vais maintenant ajouter mes autres noeuds en reprenant les commandes
précédents générées à la fin de l’initialisation du cluster.
Attention, les commandes sont a passer dans un context root
Une fois terminé, si je vérifie l’état de mes noeuds j’arrive au
résultat suivant (ne tenez pas compte de la version, ni du nom des
noeuds, la capture est issue de l'ancienne version de mon tutorial)
Tous les noeuds sont dans un état “NotReady”. Ce qui est normal, car je
n’ai pas encore déployé un add-on network. En effet pour que la
résolution DNS interne au cluster fonctionne et que les pods puissent
dialoguer sur l’ensemble du cluster il est nécessaire d’implémenter une
couche réseau. Il en existe plusieurs qui présentent des
caractéristiques différentes et des fonctionnalités spécifiques. C’est à
chacun de choisir ce qui lui semble le plus adapté à ses besoins. Pour
en savoir plus je vous invite à lire l’excellent article suivant
qui détaille les principaux add-on possibles.
Par contre attention, le choix de l’add-on peut avoir des conséquences
sur le déploiement du cluster, notamment sur l’option “podSubnet:” du
fichier de configuration utilisé par kubeadm. De même il peut y’avoir
certains prérequis propres à chaque solution. C’est donc un choix à
faire en amont du déploiement du cluster.
De mon côté, j'utilise une solution OPNsense pour filtrer mes zones réseau. Voici les flux que j'ai dû autoriser.
Sens | Source | Destination | Port et protocole | Raison |
LAN vers DMZ | Noeud master | Noeud Worker en DMZ | TCP 10250 | Dialogue avec les kubelet depuis le master |
LAN vers DMZ | Noeud master | Noeud Worker en DMZ | UDP 6081 | Encapsulation Geneve (réseau virtuel) |
DMZ vers LAN | Noeud Worker en DMZ | Noeud Master en LAN et VIP HaProxy Master | TCP 6443 | Interrogation de l'API depuis les noeuds en DMZ |
DMZ vers LAN | Noeud Worker en DMZ | Noeud Master en LAN | TCP 10349 | Interrogation du controleur Antrea |
DMZ vers LAN | Noeud Worker en DMZ | Noeud Master en LAN | UDP 6081 | Encapsulation Geneve (réseau virtuel) |
DMZ vers LAN | Noeud Worker en DMZ | NAS | TCP 2049 TCP/UDP 111 TCP/UDP 892 |
Accès au storage NFS |
Dans mon cas, j’avais débuté par flannel, puis j'avais basculé sur calico pour finalement retenir aujourd'hui antrea.
Antrea est un projet OpenSource maintenu par VMware connaissant de plus en plus d'adeptes. Etant basé sur OpenVswitch, il est cross plateforme Linux/Windows (ce qui pourrait faciliter la mise en place de cluster hybride), il peut tirer parti des fonctionnalités d'accélération hardware de certaines cartes réseau et il fonctionne sur la couche L3 et L4. Il est compatible avec les network policie de Kubernetes et peut être complété d'une CLI et de dashboard sous ELK. Bref, il me convient très bien au vu de ma faible experience sur le sujet.
Le déploiement se fait simplement avec la commande
kubectl apply -f https://raw.githubusercontent.com/vmware-tanzu/antrea/main/build/yamls/antrea.yml
Si je refais un relevé de l’état de mes nodes ils sont maintenant tous à "Ready" (ne tenez pas compte du nom de serveurs et de la version, c'est une capture issue de l'ancienne version du tutorial)
Je vérifie également que tous les pods dans le namespace "kube-system"
sont bien démarrés, en particulier les pod "coredns" avec la commande kubectl
get pod -n kube-system
La notion de label est très importante dans Kubernetes. Par défaut les noeuds master ont bien un label master mais les worker ne sont associé à aucun label pour leur role.
On va donc les marquer comme "worker". On va utiliser les commandes suivantes:
kubectl label nodes prdk8swok501 node-role.kubernetes.io/worker=Pour éviter de voir un pod s'exécuter sur un noeud particulier, comme par exemple éviter qu'un pod lié à une application du LAN tourne sur un noeud en DMZ, on peut utiliser le principe de "Taint".
Ce revient à appliquer une "contrainte" sur un noeud de maniere à ce qu'uniquement un pod qui "tolère" cette contrainte puisse s'exécuter sur ce noeud.
Voici une petite illustration en provenance de cette article de BanzaiCloud qui explique très bien le principe:
On va indiquer qu'un pod qui ne supporte pas l'association "zone=dmz" ne peut pas etre "schedulé" sur le noeud en DMZ. Pour cela on applique la commande suivante sur le noeud en DMZ
kubectl taint nodes prdk8swok511 zone=dmz:NoSchedule
Ainsi on a un cluster avec le rôle des nodes bien identifié (utiliser la commande kubectl get nodes --show-labels)
La dernière partie de cette étape va être de mettre en oeuvre les dashboards optionnels qui permettent d’avoir une vision un peu plus graphique et sympathique de son cluster.
Je vais m’inspirer du tutorial suivant
Les dashboard font partie pour moi d'une application "systeme" de "production" qui tourne sur le lan. Je vais donc créer mon namespace nommé "prdsyslan" pour les déployer.
kubectl create namespace prdsyslanCes objets sont définis au sein de l'API de K8S. Créer un objet revient donc à soumettre un fichier de configuration à l'API de kubernetes en respectant une syntaxe spécifique au sein d'un fichier yaml.
apiVersion:
"version et chemin de l'API appelé"
kind: "type d'objet"
metadata: "éléments complémentaire, mais non obligatoire servant à
identifier l'objet"
spec: "attributs spécifique de l'objet, peut parfois être omis si la
définition de l'objet l'autorise"
Je vais récupérer le fichier de déploiement founir par les developpeurs de kubernetes à cette adresse
Je ne vais pas décrire tous les objets contenus dans ce yaml, je vais juste me contenter de remplacer le namespace "kubernetes-dashboard" par le namespace "prdsyslan", afin de correspondre à mon déploiement. J'enregistre mes modifications dans un fichier all-objects-dashboard (attention, à remplacer le nom du namespace partout il figure, y compris dans les arguments passés en parametre du conteneur)
J'applique mon fichier avec la commande kubectl apply -f all-objects-dashboard.
Je vérifie le bon déploiement de l’ensemble avec la commande
kubectl get all --namespace=prdsyslan
j’obtiens la liste de tous les objets associés aux dashboard (ne tenez pas compte des autres objets, j'ai fait la capture après avoir déployer d'autres composants)
L’authentification pour l’accès au dashboard se fait par un token associé au compte de service.
Je peux me servir de la commande powershell suivante depuis mon poste de travail pour récupérer le token
kubectl -n prdsyslan describe secret
$(kubectl -n prdsyslan get secret | sls dashboard-user |
ForEach-Object { $_ -Split '\s+' } | Select -First 1)
Les dashboards ne sont pas accessibles par défaut en dehors du cluster.
Je dois donc utiliser la commenda kubectl proxy qui va me
permettre, depuis mon poste de travail, d’encapsuler ma requête sur l’ip
local de ce dernier vers le cluster. L’accès ne sera donc que possible
que depuis mon poste et uniquement le temps que la commande kubectl
proxy reste active.
Je peux ensuite accéder au dasboard via l’url : http://localhost:8001/api/v1/namespaces/prdsyslan/services/https:kubernetes-dashboard:/proxy/#/login
J’utilise le token récupéré précédemment
Je peux enfin exploiter les dashboards pour connaitre l’état de mon
cluster (ne pas tenir compte des noms des serveurs, c'est une capture
issue de mon précedent tutorial)
Cela me permet de m’assurer que mon cluster est opérationnel et prêt
pour la suite.
Kubernetes est un écosystème extrêmement vivant et ce qui est vrai un jour ne l'est pas forcément le lendemain. Il est donc important de rester en veille sur le sujet. Beaucoup de gens craignent le déploiement d'un cluster sur une infrastructure "OnPrem" à cause des difficultés potentielles que cela représente. Ce tutoriel est là pour démontrer que dans les faits, on peut très bien disposer de sa propre infrastructure dès lors qu'on accepte de se former et de la maintenir....un peu comme tout le reste.
Pour moi, le problème majeur reste les changements permanents qui sont opérés autour de l'écosystème k8s, c'est parfois un peu "fatiguant" de s'entendre dire que ce que l'on a pris du temps à maitriser et maintenant devenu obsolète...mais c'est malheureusement le mal de l'IT d'aujourd'hui ou tout doit aller vite...il faut que ça bouge.....mais parfois on ne comprend pas très bien pourquoi....hormis forcer à la prestation de service et à l'usage du cloud public....
Je ne dis pas que les services managés Kubernetes offerts par les principaux cloud provider ne sont pas intéressants. Bien au contraire, ils permettent de se focaliser sur le déploiement de ses applications plutôt que sur l'administration du cluster. Mais tout cela n'est pas gratuit et il faut s'accommoder de la plateforme retenue. Personnellement, j'estime que l'avenir de Kubernetes est à l'image de l'hybridation des infrastructures. Grâce aux offres packagées des fournisseurs historiques comme vmware ou redhat, il va devenir de plus en plus simple d'intégrer des clusters kubernetes dans son infrastructure traditionnelle, et celle-ci pourra être complétée et étendue via des offres managées en cloud public. C'est justement l'une des grandes forces de Kubernetes associé à la conteneurisation, son interopérabilité!
Mais attention, tout n'est pas magique ! Kubernetes ne résout pas tous les problèmes et n'est pas forcément la réponse à tous les "uses cases". C'est avant tout la qualité des applications et le sérieux du suivi des infrastructures associées qui font le succès d'un IT... Et ça, c'est notre boulot !