Temps de lecture estimé: 9 minutes
Je suis en train de faire évoluer la manière dont je gère mes environnements de développement et de prod.
J’ai actuellement un Hyperviseur Vmware Esxi qui fait tourner une machine virtuelle Linux (Ubuntu). C’est mon serveur principal et tous mes services, applications et site web sont sur ce même serveur de façon un peu monolithique.
MySql, apache, PostgreSQL, mon instance Gitlab, mon site CV, ce blog WordPress quelques autres services tournent sur le même serveur, côte à côte, et non dissociés.
J’ai envie de scinder tout ça et au passage de faire joujou d’améliorer la façon dont je déploie mes projets en y ajoutant un peu d’intégration et de développement continu (CI/CD) avec Gitlab, de la conteneurisation Docker et … pourquoi pas de l’orchestration et du clustering Kubernetes!!
L’orchestration et le clustering étant à la base de cette pile, je te propose aujourd’hui la première brique, comment installer un cluster Kubernetes sur Ubuntu 22.04 fraichement installé.
De mon côté, le cluster sera physiquement sur une seule machine. Pas trop davantage d’avoir un cluster…. Si la machine tombe, le cluster tombe!! Mais bon ça permet de tester (et ça permet d’avoir l’architecture déjà en place donc le jour où j’ai envie de scaler, ça sera « plus simple »).
Donc après avoir fait 2 nouvelles machines virtuelles avec une installation fraiche de la dernière version Ubuntu LTS, la 22.04 Jammy Jellyfish sur chacune des VMs, place à Kubernetes. La plupart des étapes suivantes sont à faire sur les 2 machines. Il n’y aura que la déclaration du master d’un côté et la demande de rejoindre le cluster sur le worker de l’autre côté qui seront à faire en fonction des machines.
prérequis système et Vérification des ports
Avant de se lancer dans l’installation de Kubernetes, il y a quelques prérequis à vérifier.
Réseaux pontés
Déjà, il faut s’assurer que le système peut avoir des réseaux bridge. Pour ça il faut vérifier que le noyau Linux a bien le module br_netfilter chargé.
Un petit
lsmod | grep br_netfilter
Ça permet de vérifier. s’il n’y a pas de résultat, il faut alors l’activer avec
sudo modprobe br_netfilter
Je vérifie ensuite que le firewall Iptables peut voir ce trafic bridgé
sysctl net.bridge.bridge-nf-call-iptables
Si ce n’est pas le cas, je vais créer un fichier /etc/sysctl.d/k8s.conf pour charger les bons paramètres au démarrage
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
Et je l’applique directement
sudo sysctl --system
Désactiver le swap
Pour faire fonctionner Kubernetes (kubelet), il faut désactiver le swap. Pour le faire immédiatement
sudo swapoff -a
Maintenant pour le désactiver au démarrage, il faut éditer le fichier des partitions /etc/fstab donc
sudo nano /etc/fstab
Pour commenter la ligne de swap. Dans mon cas
#/swap.img none swap sw 0 0
Vérifier les ports par défaut
Une petite vérification pour savoir si tous les ports par défaut listés ne sont pas utilisés par d’autres applications
sudo netstat -lnp | grep 6443
Dans mon cas, j’ai eu la bonne idée d’installer MicroK8s par défaut sur une des VM. du coup des ports étaient utilisés. Pour repartir sans microK8s
microk8s.disable dashboard dns
sudo snap remove microk8s
définir les noms d’hôtes
Je vais avoir besoin, minimum, d’un nœud Master et d’un nœud Worker. Donc sur chaque machine je définis son petit hostname
#sur la machine virtuelle Master
sudo hostnamectl k8s-master.anthony-jacob.com
#sur la machine virtuelle Worker
sudo hostnamectl k8s-worker.anthony-jacob.com
Sur chaque machine j’ai aussi édité le fichier /etc/hosts en fonction de la machine
sudo nano /etc/hosts
127.0.0.1 localhost
127.0.1.1 k8s-workernode k8s-workernode.anthony-jacob.com
#IP Master
192.168.8.89 k8s-masternode k8s-masternode.anthony-jacob.com</p>
#IP Worker
192.168.8.88 k8s-workernode k8s-workernode.anthony-jacob.com
Installation du container runtime – Docker.
Kubernetes peut utiliser différents environnements de conteneurisation. Dans mon cas je souhaite utiliser Docker.
Depuis la version 1.24 de Kubernetes, l’intégration de Docker via dockershim n’est plus disponible. Il faut maintenant passer par cri-dockerd. Dans le cas d’une mise à jour, il y a toute une procédure disponible. Dans mon cas, c’est une installation from scratch donc pas de problème de migration (juste des problèmes d’installations !!! )
Installation de Docker
Avant d’installer l’interface cri-dockerd qui fera le lien entre Kubernetes et Docker, il faut avant tout installer Docker.
Je commence par ajouter la clé GPG du dépôt Docker. Les clés ne s’ajoutent plus avec apt-key, qui est déprécié. Il faut maintenant gérer les clés manuellement dans /etc/apt/trusted.gpg.d/ . Donc je la télécharge la clé
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg
Et j’ajoute le dépôt dans la liste des sources d’apt
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Je peux maintenant mettre à jour les dépôts disponibles et installer Docker
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Utiliser systemd
Pour la gestion des droits de Kubernetes, il est conseillé d’utiliser systemd au lieu de cgroupfs . Par conséquent, Docker aussi devrait utiliser systemd. Pour le vérifier
docker info
Devrait donner
Cgroup Driver: systemd
Cgroup Version: 2
Si ce n’est pas le cas, il faut spécifier des paramètres au lancement du daemon Docker.
Pour ça il faut créer (ou éditer si déjà présent) le fichier /etc/docker/daemon.json , donc
nano /etc/docker/daemon.json
Pour y mettre les options d’exécutions
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
Un petit reload de tout ça
sudo systemctl daemon-reload
sudo systemctl reload docker
et voilà, je vérifie que le service tourne
systemctl status docker
Ajout de mon utilisateur au groupe docker
Au passage j’en profite pour rajouter mon utilisateur au groupe docker
sudo usermod -aG docker $USER
newgrp docker
Installation de Mirantis Cri-Dockerd
Pour installer Cri-dockerd, l’interface entre Kubernetes et Docker, il faut Go.
wget https://storage.googleapis.com/golang/getgo/installer_linux
chmod +x ./installer_linux
./installer_linux
source ~/.bash_profile
Si tout est OK, go est installé
go version
devrait donner
go version go1.18.3 linux/amd64
Ensuite dans un répertoire de travail, je clone le repository git,
je compile cri-dockerd,
je le copie dans les bons répertoires,
j’installe et j’active les services
git clone https://github.com/Mirantis/cri-dockerd.git
cd cri-dockerd
mkdir bin
go get && go build -o bin/cri-dockerd
mkdir -p /usr/local/bin
sudo install -o root -g root -m 0755 bin/cri-dockerd /usr/local/bin/cri-dockerd
sudo cp -a packaging/systemd/* /etc/systemd/system
sudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service
sudo systemctl daemon-reload
sudo systemctl enable cri-docker.service
sudo systemctl enable --now cri-docker.socket
systemctl status cri-docker.socket
Installation de Kubernetes
Maintenant que les prérequis à Kubernetes sont là, je vais pouvoir passer à l’installation de Kubernetes. Je télécharge la clé gpg du dépôt
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/google-k8s.gpg
Et j’ajoute Kubernetes à la liste des dépôts en créant le fichier /etc/apt/sources.list.d/k8s.list
sudo nano /etc/apt/sources.list.d/k8s.list
j’y met le dépôt en spécifiant la clé
deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/google-k8s.gpg] http://apt.kubernetes.io/ kubernetes-xenial main
# deb-src http://apt.kubernetes.io/ kubernetes-xenial main
Je peux maintenant mettre à jour les dépôts disponibles et installer Kubernetes
sudo apt update && sudo apt install kubeadm kubelet kubectl kubernetes-cni
Configuration et déclaration du Master Kubernetes
Toutes les étapes précédentes étaient à faire sur les 2 VMs, la machine qui sera le master et la machine qui sera le worker du cluster Kubernetes. Ici, j’initialise le master.
l’adresse IP du master est 192.168.8.89
j’utilise docker au travers de cri-dockerd.
systemctl status cri-docker.socket
Me permet de voir que le socket d’écoute est unix:///run/cri-dockerd.sock
Et je vais devoir par la suite devoir installer un pod réseaux. Dans mon cas je choisirais Flannel, par défaut Flannel utilisera adressage CIDR 10.244.0.0/16 pour les pods
Avec toutes ces informations, je peux lancer la commande
sudo kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket=unix:///run/cri-dockerd.sock \
--apiserver-advertise-address=192.168.8.89
Si tout se passe comme prévu, kubeadm devrait arriver à la fin de la configuration et indiquer quelque chose comme
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following 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 e of the options listed at:
/docs/concepts/cluster-administration/addons/
You can now join any number of machines by running the following on each node
as root:
kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Il faut mettre de côté la commande
kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
qui nous servira pour le worker
Mis à par ça, comme conseillé je copie les préférences dans mon dossier personnel
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Installation du pod Réseau
Comme annoncé plus haut, je déploie un pod réseau.
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
Quelques secondes après, je lance
kubectl get pods -n kube-system
Pour vérifier que tous mes pods de base (Flannel inclus) sont lancés
NAME READY STATUS RESTARTS AGE
coredns-6d4b75cb6d-rn2cv 1/1 Running 3(4d7h ago) 4d8h
coredns-6d4b75cb6d-zkftf 1/1 Running 3(4d7h ago) 4d8h
etcd-k8s-masternode.anthony-jacob.com 1/1 Running 3(4d7h ago) 4d8h
kube-apiserver-k8s-masternode.anthony-jacob.com 1/1 Running 3(4d7h ago) 4d8h
kube-controller-manager-k8s-masternode.anthony-jacob.com 1/1 Running 4(4d7h ago) 4d8h
kube-flannel-ds-hntr4 1/1 Running 0 4d7h
kube-flannel-ds-s8n5h 1/1 Running 3(4d7h ago) 4d8h
kube-proxy-fmzl2 1/1 Running 3(4d7h ago) 4d8h
kube-proxy-zrb4p 1/1 Running 0 4d7h
kube-scheduler-k8s-masternode.anthony-jacob.com 1/1 Running 5(4d7h ago) 4d8h
Optionnellement, pour isoler le control plane pour un cluster Kubernetes mono-machine pour le développement, exécutez:
kubectl taint nodes --all node-role.kubernetes.io/master-
Déclarer le Worker et rejoindre le master
Depuis la machine worker maintenant, je vais rejoindre le cluster et déclarer la machine au master avec la commande que m’a précédemment donnée l’initialisation du master
kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Il est possible de régénérer cette commande, depuis le master, avec
kubeadm token create --print-join-command
ça donnera tout ce qu’il faut
kubeadm join 192.168.8.88:6443 --token fepq6o.am5wzzq75utqzzyy --discovery-token-ca-cert-hash sha256:c9f7798ed7a6ccf03b5590cddedecb3e250ea9427103e22ed10b30e3b43a2cfc --cri-socket=unix:///run/cri-dockerd.sock
Je vérifie que tout est bon
kubectl get nodes -A -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-masternode.anthony-jacob.com Ready control-plane 4d9h v1.24.1 192.168.8.89 <none> Ubuntu 22.04 LTS 5.15.0-37-generic docker://20.10.17
k8s-workernode.anthony-jacob.com Ready <none> 4d7h v1.24.1 192.168.8.88 <none> Ubuntu 22.04 LTS 5.15.0-37-generic docker://20.10.17
Autocomplétion
Le panel de commande de Kubernetes à l’air sssuuuuper large, donc pour aller plus loin j’ai aussi mis en place l’autocomplétion sur le système. Donc si ce n’est pas déjà fait
apt-get install bash-completion
Et ensuite
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
Installer Helm Gestionnaire de paquet Kubernetes
Par la suite je pourrai avoir besoin de helm, le gestionnaire de paquet Kubernetes. Assez simple, on ajoute la bonne clé, le dépôt dans la liste des sources et il suffit de l’installer avec apt
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm
Voilà, l’installation sommaire d’un cluster Kubernetes est faite de mon côté. Je n’ai plus qu’à approfondir son utilisation.
J’ai fait 2 autres articles sur l’installation d’interfaces pour gérer le cluster ou au moins avoir les informations essentielles. un article pour installer Kubernetes Dashboard et un autre pour installer Portainer.io
Dis moi ce que tu en penses et si ça a pu te servir ! En attendant, je te dis à bientôt pour de nouvelles aventures!!
Holà !
J’espère que tu vas bien.
Merci énormément pour le temps que tu as pris à tester puis rassembler les infos pour les partager.
J’ai un petit soucis de connexion entre mon worker et mon master, lorsque je veux faire une cmd kubectl depuis le worker (en sudo ou non) je reçois cette erreur :
The connection to the server localhost:8080 was refused – did you specify the right host or port?
J’ai lu sur plusieurs forums comme quoi ça pouvait venir de la partie attribution des droits des fichiers de config après l’initialisation mais pourtant je les ai bien faites (et refaites) sur le master.
Si jamais t’as déjà rencontré ce problème, je serais preneur d’un coup de main 😉
Encore merci pour ton tuto en tout cas !
Petit edit :
J’ai trouvé la solution mais maintenant je galère à accéder au dashboard depuis l’extérieur avec mes VMs NATées mais bon on avance tranquillement.
Bonne soirée à toi !
Salut Maxime,
merci pour ton message!
oui ton premier souci ressemblait à un manque ou une mauvaise config du fichier ./kube/config dans ton dossier utilisateur?!
Comment tu l’as résolu?
Pour l’accès au dashboard, là comme ça je ne peux pas t’aiguiller.
si ton service fonctionne bien et que tu y as accès depuis ton worker
https://blog.anthony-jacob.com/comment-installer-kubernetes-dashboard/#premier-test
je dirai que ça se passe au niveau d’une translation d’adresse ou un forward quelque part.
j’ai aussi eu des problèmes réseau et DNS que j’ai résolu par la suite, je prépare un petit mémo là-dessus
idem , je serai curieux de savoir comment tu as résolu ce problème si tu as avancé dessus.
bonne journée!
Holà
Effectivement ma première erreur était liée au fichier .kube/config sur le worker qui n’était pas défini, du coup il tapait sur rien quand je faisais une cmd kubectl. J’ai copié celui du master et ça fonctionne niquel
Pour le dashboard je suis toujours bloqué, j’ai bien l’erreur 200 lorsque je fais le curl en localhost mais depuis mon browser j’ai une erreur de certificat. En même temps, le certificat a été créé sur le Master et là on essaye d’y accéder via le worker donc je sais pas si c’est à cause de ça, je creuse le problème ce soir tranquillement 😉
Bonne journée à toi aussi et bon week-end !
Merci pour ce tuto,
petit correctif si on veut faire du copier/coller « aveugle »
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
ou bien mettre le \n manquant