L’étape suivante consiste à préparer les serveurs pour l’installation de Kubernetes.
Je ne vais pas détailler la mise en oeuvre d’une VM sous vSphere, mais uniquement m’attacher à préciser quelques points et éléments de configuration nécessaires au bon fonctionnement de Kubernetes sur une plateforme vmware.
Je précise que je me suis basé sur le tutoriel suivant.
Je ne vais pas le suivre à la lettre et m’en détacher par la suite surtout au niveau de l’étape suivante qui consistera à l’installation de Kubernetes. Mais dans un premier temps, les prérequis proposés sont à mettre en oeuvre.
Il est de bon ton dans l’IT actuelle de ne plus prêter attention à la nomenclature de ses serveurs. À l’heure des microservices ou les ressources sont éphémères et en changement permanent, il n’est plus nécessaire de faire un brainstorming pour choisir le petit nom de ses machines (on passe du temps sur les tags maintenant 😊). Néanmoins s’accorder sur une nomenclature pour ses noeuds Kubernetes reste une bonne idée.
Voici les VMs que je vais déployer. Il s'agit de l'infrastructure de base, elle pourra être complétée par la suite avec des noeuds complémentaires
VMs |
Size |
Role |
IP |
prdinfhap501 |
1vCPU, 1GB Ram, 30 GB Disque |
LoadBalancer HA Proxy LAN |
192.168.10.45 |
prdk8smst501 |
2vCPU, 4GB Ram, 30 GB Disque |
Master Kubernetes 01 |
192.168.10.56 |
prdk8swok501 |
4vCPU, 4GB Ram, 30 GB Disque |
Worker LAN Kubernetes 01 |
192.168.10.57 |
prdk8swok502 |
4vCPU, 4GB Ram, 30 GB Disque |
Worker LAN Kubernetes 01 |
192.168.10.58 |
prdinfhap511 |
1vCPU, 1GB Ram, 30 GB Disque |
LoadBalancer HA Proxy DMZ |
192.168.5.57 |
prdk8swok511 |
4vCPU, 4GB Ram, 60 GB Disque |
Worker DMZ Kubernetes 01 |
192.168.5.57 |
prdk8swok512 |
4vCPU, 4GB Ram, 60 GB Disque |
Worker DMZ Kubernetes 01 |
192.168.5.58 |
Un premier point très important : j'ai utilisé des noms de VMs en minuscule pour les serveurs K8S. Qu'il s'agisse des noms dans l'inventaire vCenter ou des hostnames au niveau OS, il est primordial d'avoir une cohérence dans les noms pour les échanges Kubernetes/vSphere. Il faut avoir une correspondance entre le nom dans le vCenter, le hostname et le nom du node dans Kubernetes. Le plus simple est de tout mettre en minuscule.
L’UUID pour « Universal Unique Identifier » est une suite de caractères alphanumériques qui permet d’identifier de façon certaine chaque périphérique de stockage et de partition. Il est calculé automatiquement fonction de la configuration du serveur hôte au moment de la création ou du formatage de la partition. Dans le cas de VMWARE, cette option permet de présenter un UUID cohérent pour éviter tout problème de montage des volumes.
Il faut donc procéder aux opérations suivantes
"PhotonOS" ne présente pas de difficultés particulières pour son installation. Il suffit de récupérer l'ISO, de booter dessus et de suivre l'assistant. Il y'a très peu d'éléments à renseigner. Pour le stockage, on peut rester sur la configuration par défaut. Concernant le réseau, il est conseillé d'appliquer directement l'IP de manière statique, même si on la reconfigurera après. Le profil retenu est "Photon minimal" et le kernel choisi est "VMware Hypervisor optimized".
Pour plus de détail, je vous invite à suivre la documentation d'installation sur le site officiel.
Les éléments suivants sont des éléments de configuration complémentaire, non obligatoire, mais que j'ai souhaité mettre en oeuvre pour plus de praticités.
PhotonOS utilise comme gestionnaire de package une version allégée de l'outil de RedHat 8 nommée ici "tdnf". Pour ceux qui le souhaitent, "yum" peut aussi être déployé et utilisé.
Par défaut, seul l'utilisateur root est disponible et l'accès SSH n'est pas possible. Je vais donc créer un utilisateur dédié à l'accès distant.
useradd mon_user
passwd mon_user
Certains vont sans doute crier au scandale pour des questions de sécurité (et ils n'auraient pas tort) mais je vais désactiver l'expiration des mots de passe configurée par défaut pour l'utilisateur root et mon user.
chage -I -1 -m 0 -M 99999 -E -1 mon_user
chage -I -1 -m 0 -M 99999 -E -1 root
C'est toujours mieux de travailler avec le bon mappage de clavier et les bons paramètres régionaux.
tdnf install kbd -y
tdnf install glibc-i18n -y
Il faut éditer le fichier "/etc/locale-gen.con" pour ajouter "fr_FR.UTF-8 UTF-8"
echo "fr_FR.UTF-8 UTF-8" >>
/etc/locale-gen.conf
locale-gen.sh
localectl set-locale LANG="fr_FR.UTF-8" LC_CTYPE="fr_FR.UTF-8"
La gestion du temps est toujours primordiale sur les serveurs. Je ne saurais trop vous conseiller d'utiliser un serveur NTP comme source de référence. Me concernant, c'est mon contrôleur de domaine, lui-même synchronisé sur internet qui fournit ce service.
Il faut éditer le fichier "/etc/systemd/timesyncd.conf" et ajouter son serveur NTP
systemctl restart systemd-timesyncd
Si vous disposez d'une ou plusieurs PKI internes, il est préférable d'ajouter leurs certificats a la base des certificats de confiance de l'OS.
tdnf install openssl-c_rehash
Ajoutez vos certificats dans "/etc/ssl/certs"
Puis il faut lancer la commande suivante qui est founie dans le package
openssl-c_rehash
rehash_ca_certificates.sh
Malgré avoir positionné une IP fixe à l'installation de l'OS, il m'est arrivé, notamment après un update du système, de basculer en DHCP. Pour éviter ce problème, je refixe mon IP via un fichier de configuration "10-static-en.network".
cat > /etc/systemd/network/10-static-en.network << "EOF"
[Match]
Name=eth0
[Network]
Address=mon_ip/mask
Gateway=ip_gateway
DNS=ip_dns
EOF
Ne pas oublier d'appliquer les bon droits
chmod 644 /etc/systemd/network/10-static-en.network
Je vais avoir besoin de mapper des volumes NFS, j'installe donc le paquet nécessaire.
tdnf install nfs-utils -y
Il est conseiller de faire un update complet du système avant de continuer
tdnf distro-sync --refresh
tndf update
Pour déployer HAproxy, il suffit de taper la commande suivante
tdnf install haproxy
Nous verrons sa configuration plus tard
Les VMs qui vont servir aux noeuds Kubernetes, master comme worker doivent avoir une configuration spécifique.
Kubernetes ne supporte pas pour le moment l’usage de la swap. Si vous souhaitez savoir pourquoi n’hésiter pas à lire le topic suivant mais en gros, dans le fonctionnement de Kubernetes les pods ne devraient jamais avoir à utiliser la swap et intégrer son support est compliqué.
La commande suivante est à passer sur chaque serveur K8S sudo swapoff -v /swapfile
Il faut également commenter la référence à la swap dans le fichier fstab
Il faut installer dès à present les packets suivants
tdnf install kubernetes kubernetes-kubeadmIl est nécessaire d'adapter légèrement son système pour Kubernetes
cat <<EOF | tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward
=
1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
On force la relecture de la config
sysctl --system
Je profite de cette partie pour faire le point sur un petit sujet parfois délicat : le runtime dédié à l'exécution des conteneurs.
Au moment ou Docker est arrivé sur le marché, ce dernier s'occupait de tout, de la création des images à leur exécution (enfin pas tout à fait au tout début) en passant par la manipulation de ces dernières.
Puis, comme l'IT aime la concurrence, d'autres "moteurs" d'exécution de conteneurs sont apparus comme "rkt". Plutôt que de jouer à qui est le meilleur, les différents acteurs gravitant autour du conteneur ont créé l'Open Container Initiative afin de créer un standard concernant la manière de démarrer un conteneur. Docker qui disposait déjà de son module au sein de son écosystème a "donné" ce dernier à la communauté est c'est ainsi que "runc" est devenu la norme.
Mais, "runc" est très bas niveau et se concentre sur le lancement des conteneurs uniquement. Le reste des outils "Docker" sont restés pour la manipulation des images par exemple.....et c'est la que "containerd" fait son apparition, car il "remplace" ce que faisait également Docker avant, notamment pour fournir une API et interagir avec les conteneurs...même si on continu d'utiliser les commandes dockers....
En résumé pour l'instant on n'a
Voici une image d'illustration issue de l'article rédigé par un certain Avijit Sarkar sur Medium qui illustre parfaitement l'explication ci-dessus
Ce n’est pas fini, car maintenant on n'a aussi la problématique d'orchestration. Comme déjà évoqué, Kubernetes se focalise sur ce besoin. Il s'assure en permanence d'avoir un parc de conteneurs conforme aux souhaits des utilisateurs, mais le "moteur" en lui-même d'exécution des conteneurs n'est pas son problème. Kubernetes propose donc le Runtime Interface (CRI) qui définit les interactions entre K8S et les runtimes de conteneurs. Dès lors qu'un runtime respecte CRI, il peut être utilisé par Kubernetes.
Par contre, chose importante, depuis Kubernetes 1.20, le runtime d'origine de Docker est déprécié et ne sera plus supporté dans les versions futures. Ce qui a provoqué un certain vent de panique...sauf que si vous avez suivi, ça fait pas mal de temps que le runtime Docker n'est plus docker...mais containerd...et aujourd'hui la plupart du temps quand vous tapez vos commandes docker vous interagissez avec containerd...qui est lui est compatible "CRI" donc utilisable avec Kubernetes !
En faite, les développeurs et les administrateurs ont tellement pris l'habitude de manipuler la CLI Docker, que malgré le faite qu'une CLI containerd soit disponible, on continu d'utiliser les commandes Docker...mais le moteur en dessous à bien changé :)
Pour terminer, RedHat tente également de changer la donne avec Podman qui "permet de lancer des conteneurs rootless et daemonless, tout en gardant une compatibilité avec le CLI docker"...mais je vais m'arrêter la !
Tous ce blabla pour arriver aux élements de configurations à appliquer à containerd face à Kubernetes.
Il est necessaire de s'assurer du chargement de certains modules du kernel via le fichier " /etc/modules-load.d/containerd.conf"
cat <<EOF | tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
On passe maintenant au fichier "/etc/containerd/config.toml". Il faut qu'il dispose du conteneur suivant:
disabled_plugins = [""]
#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0
#[grpc]
# address = "/run/containerd/containerd.sock"
# uid = 0
# gid = 0
#[debug]
# address = "/run/containerd/debug.sock"
# uid = 0
# gid = 0
# level = "info"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
On redemarre le service containerd et on s'assure que docker soit lancé
au démarrage (et donc containerd...)
systemctl restart containerd
On n'oublie pas la partie docker via le fichier "/etc/docker/daemon.json"
cat <<EOF | tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
systemctl enable docker
systemctl start docker
Chaque serveur membre d'un cluster Kubernetes dispose d'un "agent" aussi appelé kubelet. Il vient avec l'installation des paquets kubernetes.
Une grosse partie des composants K8S s'exécute sous forme de conteneurs, mais "kubelet" reste sous forme de service classique, car en plus d'assurer la communication entre le master et les workers, ils sont chargés de lancer les "statics pods" soit les pods de bases chargés eux-mêmes d'exécuter le reste des composants Kubernetes....et oui le "scheduler" en charge de la planification de l'exécution des "pods" est lui même un pod...donc il faut bien qu'il soit lancé une première fois...
Pour cela les "Kubelet" surveillent le contenu d'un répertoire spécifique (habituellement /etc/kubernetes/manifest).Si celui-ci contient des yaml décrivant des pods, ils seront automatiquement exécutés.
J'ai été confronté à une erreur d'exécution des kubelets sur PhotonOS, impossible de savoir si c'est normal, mais comme le bon fonctionnement des "kubelet" est un prérequis obligatoire au déploiement du cluster, j'ai du ajouter la ligne suivante au fichier de configuration du service "/etc/sysconfig/kubelet"
echo "KUBELET_EXTRA_ARGS=--cgroup-driver=systemd" >
/etc/sysconfig/kubelet