Ubuntu 22 : Kubernetes master et nodes
Edit 06/10/23 : ajout de la metrics api
Bonjour,
Aujourd'hui, un billet portant sur la mise en place d'un cluster kubernetes avec 1 master et 2 nodes worker sous Ubuntu 22.04.
Ces VMs tournent sur un cluster proxmox hébergé sur des Lenovo m910q.
Partie commune au master et aux nodes
Common packages
On a besoin de quelques packages :
apt update
apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent
Renseignement du fichier hosts
Il faut renseigner le fichier avec les IPs des différents noeuds :
192.168.0.23 k8s-master.adm.securmail.fr
192.168.0.24 k8s-node1.adm.securmail.fr
192.168.0.25 k8s-node2.adm.securmail.fr
Mise en place des différents repositories
Clés gpg docker et kubernetes :
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /etc/apt/keyrings/kubernetes.gpg
Ajout des fichiers de repo :
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/kubernetes.gpg] http://apt.kubernetes.io/ kubernetes-xenial main" | \
tee /etc/apt/sources.list.d/kubernetes.list > /dev/null
Paramètres spécifiques
Kernel 5.15 :
Ce kernel apporte une modification côté nf_conntrack, il faut donc en augmenter le nombre maxi (issue github : https://github.com/kubernetes-sigs/kind/issues/2240 ) sinon les pods nécessaires à kubernetes n'arrivent pas à se déployer correctement et ils restart en boucle.
Créer ce fichier /etc/sysctl.d/99-kube.conf :
net.netfilter.nf_conntrack_max = 524288
Désactivation du swap :
swapoff -a
Editer le fichier fstab pour désactiver le swap.
Vérifier que les modules br_netfilter et overlay sont bien chargés :
root@k8s-master:~# lsmod | grep -E 'br_netfilter|overlay'
br_netfilter 32768 0
bridge 307200 1 br_netfilter
overlay 151552 16
Si le module n'est pas chargé :
modprobe br_netfilter
sysctl net.bridge.bridge-nf-call-iptables=1
Docker installation
Installation de docker engine :
apt install docker-ce docker-ce-cli containerd.io
On supprime le fichier de conf de containerd livré par défaut et on le regénère :
rm /etc/containerd/config.toml
containerd config default > /etc/containerd/config.toml
Editer le fichier config.toml de containerd pour utiliser systemd:
version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
L'option est à false de base, puis restart :
systemctl restart containerd
Création du fichier de configuration des logs docker :
mkdir /etc/docker
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
On le restart :
systemctl restart docker
On vérifie le status de docker :
root@k8s-master:~# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2023-08-31 15:18:04 CEST; 6s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 5628 (dockerd)
Tasks: 9
Memory: 27.1M
CPU: 293ms
CGroup: /system.slice/docker.service
└─5628 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Aug 31 15:18:03 k8s-master.adm.securmail.fr systemd[1]: Starting Docker Application Container Engine...
Aug 31 15:18:03 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:03.676910806+02:00" level=info msg="Starting up"
Aug 31 15:18:03 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:03.677771093+02:00" level=info msg="detected 127.0.0.53 nameserver, assuming systemd-resolved, so using res>
Aug 31 15:18:03 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:03.772179479+02:00" level=info msg="Loading containers: start."
Aug 31 15:18:04 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:04.078420260+02:00" level=info msg="Loading containers: done."
Aug 31 15:18:04 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:04.105389402+02:00" level=info msg="Docker daemon" commit=a61e2b4 graphdriver=overlay2 version=24.0.5
Aug 31 15:18:04 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:04.105701369+02:00" level=info msg="Daemon has completed initialization"
Aug 31 15:18:04 k8s-master.adm.securmail.fr dockerd[5628]: time="2023-08-31T15:18:04.166018271+02:00" level=info msg="API listen on /run/docker.sock"
Aug 31 15:18:04 k8s-master.adm.securmail.fr systemd[1]: Started Docker Application Container Engine.
Kubernetes installation
Installer les composants kubernetes :
VERSION='1.27.0-00'
apt install -y kubelet=$VERSION kubeadm=$VERSION kubectl=$VERSION kubernetes-cni
Il est possible de figer la version des packages en utilisant apt :
root@k8s-master:~# apt-mark hold kubelet kubeadm kubectl kubernetes-cni
kubelet set on hold.
kubeadm set on hold.
kubectl set on hold.
kubernetes-cni set on hold.
Tour rapide des différentes cli :
- kubeadm: permet de créer le cluster et d'ajouter des nodes.
- kubelet: agent qui tourne sur chaques noeuds, qui permet notamment l'ajout et le démarrage des pods.
- kubectl: permet d'intéragir avec le cluster.
Changement à chaud du nombre de nf_conntrack max :
root@k8s-node2:~# sysctl net.netfilter.nf_conntrack_max=524288
net.netfilter.nf_conntrack_max = 524288
On disable apparmor et on s'assure que docker est bien enable :
systemctl enable docker
systemctl enable kubelet
systemctl daemon-reload
systemctl stop apparmor
systemctl disable apparmor
UNIQUEMENT SUR LE MASTER
Init kubernetes conf sur le master :
kubeadm init --v=5 \
--upload-certs \
--control-plane-endpoint k8s-master.adm.securmail.fr:6443 \
--pod-network-cidr=10.244.0.0/16 \
--ignore-preflight-errors=NumCPU
Configuration de kubectl :
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
C'est valable également si vous voulez utilisez kubectl depuis un autre ordinateur, il suffit de créer le dossier .kube et d'y copier le fichier config.
On vérifie si tout est OK :
root@k8s-master:~# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master.adm.securmail.fr NotReady control-plane 46s v1.27.0 192.168.0.23 <none> Ubuntu 22.04.3 LTS 5.15.0-82-generic containerd://1.6.2
Le status NotReady est normal car il manque un composant réseau.
Installation de Flannel qui est un network fabric basic :
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
root@k8s-master:~# kubectl get pods -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel kube-flannel-ds-gmmn4 1/1 Running 0 38s 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system coredns-5d78c9869d-dfg4j 1/1 Running 0 74s 10.244.0.35 k8s-master.adm.securmail.fr <none> <none>
kube-system coredns-5d78c9869d-q6qjd 1/1 Running 0 74s 10.244.0.34 k8s-master.adm.securmail.fr <none> <none>
kube-system etcd-k8s-master.adm.securmail.fr 1/1 Running 0 88s 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-apiserver-k8s-master.adm.securmail.fr 1/1 Running 0 88s 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-controller-manager-k8s-master.adm.securmail.fr 1/1 Running 0 88s 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-proxy-h2bn9 1/1 Running 0 74s 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-scheduler-k8s-master.adm.securmail.fr 1/1 Running 0 88s 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
root@k8s-master:~# kubectl get componentstatus
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy ok
Installation de la metrics API afin de pouvoir avoir une visualisation de la consommation des ressources. Il faut pour ça déjà télécharger le yaml :
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Puis le modifier en ajoutant --kubelet-insecure-tls au bloc arg pour avoir ce résultat :
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls
Ensuite, on peut faire l'installation :
root@k8s-master:~# kubectl apply -f components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
Le pod metrics est bien créé (il met quelques secondes à démarrer) :
root@k8s-master:~# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5d78c9869d-dfg4j 1/1 Running 2 (3d23h ago) 31d
coredns-5d78c9869d-q6qjd 1/1 Running 2 (3d23h ago) 31d
etcd-k8s-master.adm.securmail.fr 1/1 Running 2 (3d23h ago) 31d
kube-apiserver-k8s-master.adm.securmail.fr 1/1 Running 2 (3d23h ago) 31d
kube-controller-manager-k8s-master.adm.securmail.fr 1/1 Running 2 (3d23h ago) 31d
kube-proxy-bh789 1/1 Running 2 (3d23h ago) 31d
kube-proxy-h2bn9 1/1 Running 2 (3d23h ago) 31d
kube-proxy-srdbf 1/1 Running 2 (3d23h ago) 31d
kube-scheduler-k8s-master.adm.securmail.fr 1/1 Running 2 (3d23h ago) 31d
metrics-server-75f45b4dd4-qfxjr 1/1 Running 0 116s
openebs-lvm-controller-0 5/5 Running 2 (3d23h ago) 3d23h
On peut aller voir par exemple les ressources des différents nodes :
root@k8s-master:~# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master.adm.securmail.fr 82m 4% 2475Mi 64%
k8s-node1.adm.securmail.fr 28m 1% 1769Mi 46%
k8s-node2.adm.securmail.fr 29m 1% 1867Mi 48%
AJOUTER UN NODE
Sur le master pour récupérer la commande d'ajout d'un node :
root@k8s-master:~# kubeadm token create --print-join-command
kubeadm join k8s-master.adm.securmail.fr:6443 --token boXXXXXX.8v16XXXXXXXXXXXX --discovery-token-ca-cert-hash sha256:7d06424XXXXXXXXXXXXXXXXXXXX
Sur le node à ajouter:
root@k8s-node1:~# kubeadm join k8s-master.adm.securmail.fr:6443 --token boXXXXXX.8v16XXXXXXXXXXXX --discovery-token-ca-cert-hash sha256:7d06424XXXXXXXXXXXXXXXXXXX
Pour vérifier, on peut vérifier la liste des nodes :
root@k8s-master:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master.adm.securmail.fr Ready control-plane 24h v1.28.1
k8s-node1.adm.securmail.fr Ready <none> 23h v1.28.1
k8s-node2.adm.securmail.fr Ready <none> 23h v1.28.1
Le ready peut mettre quelques secondes à arriver.
Ajout d'un nginx juste pour le test :
root@k8s-master:~# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
root@k8s-master:~# kubectl create service nodeport nginx --tcp=80:80
service/nginx created
Listing des services pour faire apparaitre celui de nginx :
root@k8s-master:~# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24h
nginx NodePort 10.101.35.44 <none> 80:32443/TCP 20s
Listing des pods :
root@k8s-master:~# kubectl get pods --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
default nginx-7854ff8877-kj8hp 1/1 Running 0 3m14s 10.244.1.2 k8s-node1.adm.securmail.fr <none> <none>
kube-flannel kube-flannel-ds-2l7j4 1/1 Running 17 (23h ago) 24h 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-flannel kube-flannel-ds-5mvbk 1/1 Running 0 23h 192.168.0.25 k8s-node2.adm.securmail.fr <none> <none>
kube-flannel kube-flannel-ds-lmk69 1/1 Running 0 23h 192.168.0.24 k8s-node1.adm.securmail.fr <none> <none>
kube-system coredns-5dd5756b68-tj8hw 1/1 Running 15 (23h ago) 24h 10.244.0.32 k8s-master.adm.securmail.fr <none> <none>
kube-system coredns-5dd5756b68-zzkxr 1/1 Running 14 (23h ago) 24h 10.244.0.33 k8s-master.adm.securmail.fr <none> <none>
kube-system etcd-k8s-master.adm.securmail.fr 1/1 Running 22 (23h ago) 24h 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-apiserver-k8s-master.adm.securmail.fr 1/1 Running 22 (23h ago) 24h 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-controller-manager-k8s-master.adm.securmail.fr 1/1 Running 28 (23h ago) 24h 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-proxy-6v7tf 1/1 Running 18 (23h ago) 24h 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
kube-system kube-proxy-bswgg 1/1 Running 0 23h 192.168.0.24 k8s-node1.adm.securmail.fr <none> <none>
kube-system kube-proxy-hnwmv 1/1 Running 0 23h 192.168.0.25 k8s-node2.adm.securmail.fr <none> <none>
kube-system kube-scheduler-k8s-master.adm.securmail.fr 1/1 Running 25 (23h ago) 24h 192.168.0.23 k8s-master.adm.securmail.fr <none> <none>
Le pod nginx apparait bien et le node sur lequel il est exécuté.
On vérifie l'accès (valable aussi depuis un navigateur) :
root@k8s-master:~# curl 192.168.0.23:32443
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Différentes erreurs
Erreur de CRI au join/init :
rm /etc/containerd/config.toml
containerd config default > /etc/containerd/config.toml
systemctl restart containerd
Si connection refused après avoir créé un service port :
kubectl patch node kubsworker -p '{"spec":{"podCIDR":"192.168.200.0/24"}}'
Si besoin de réinitialiser le cluster :
kubeadm reset
Normalement, vous avez un cluster kubernetes basic fonctionnel.
Have fun.