Installation complète, propre et reproductible de Kubernetes 1.33 avec CRI-O sur Fedora et RHEL
Installation complète, propre et reproductible de Kubernetes 1.33 avec CRI-O sur Fedora / RHEL
(avec résolution des pièges réels rencontrés : kubelet, CNI, Flannel, CoreDNS, reset incomplet)
Ce tutoriel décrit l’intégralité du chemin correct, depuis une machine Fedora/RHEL vierge jusqu’à un cluster Kubernetes 1.33 fonctionnel, en utilisant CRI-O 1.33 comme runtime et Flannel (VXLAN) comme CNI. Il inclut les erreurs réelles rencontrées en pratique, leurs causes exactes, et les correctifs supportés.
Note de version : Kubernetes 1.30 est en fin de vie (EOL) depuis octobre 2025 et ne reçoit plus de correctifs de sécurité. Ce tutoriel cible la version 1.33 (supportée jusqu’en juin 2026). Les versions maintenues à la date de rédaction sont 1.33, 1.34 et 1.35. Remplacer
v1.33par la version souhaitée dans toutes les commandes si nécessaire.
Objectifs :
- 1 nœud control-plane fonctionnel
- kubeadm 1.33 / kubelet 1.33 / kubectl 1.33
- CRI-O 1.33
- Flannel VXLAN
- CoreDNS opérationnel
- État final :
kubectl get nodes→Ready
1. Préparation système (OBLIGATOIRE)
1.1 Désactivation du swap
Kubernetes refuse de démarrer avec le swap actif.
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab
Vérification :
swapon --show
Aucune sortie ne doit apparaître.
1.2 SELinux en mode permissif
CRI-O + CNI VXLAN sans politiques personnalisées exigent SELinux permissif.
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
1.3 Modules kernel requis
sudo modprobe overlay
sudo modprobe br_netfilter
Persistant :
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
1.4 Paramètres sysctl réseau Kubernetes
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
1.5 Ouverture des ports firewalld (OBLIGATOIRE sur Fedora/RHEL)
firewalld est actif par défaut sur Fedora et RHEL. Sans ces règles, le CNI Flannel et les composants kubelet échouent silencieusement même si les pods semblent démarrer.
Ports control-plane :
sudo firewall-cmd --permanent --add-port=6443/tcp # API server
sudo firewall-cmd --permanent --add-port=2379-2380/tcp # etcd
sudo firewall-cmd --permanent --add-port=10250/tcp # kubelet API
sudo firewall-cmd --permanent --add-port=10257/tcp # kube-controller-manager
sudo firewall-cmd --permanent --add-port=10259/tcp # kube-scheduler
Port Flannel VXLAN (UDP 8472) — indispensable pour la communication inter-pods :
sudo firewall-cmd --permanent --add-port=8472/udp # Flannel VXLAN
Interfaces CNI en zone trusted (permet le trafic pod-to-pod sans interférence firewalld) :
sudo firewall-cmd --permanent --zone=trusted --add-interface=cni0
sudo firewall-cmd --permanent --zone=trusted --add-interface=flannel.1
Application :
sudo firewall-cmd --reload
Diagnostic : si CoreDNS répond
no route to hostalors que les pods ont des IPs correctes et queflannel.1est UP, la cause est presque toujours firewalld qui bloque le trafic sur l’interface Flannel. Vérifier avecsudo firewall-cmd --list-all.
2. Installation de CRI-O 1.33 et des outils Kubernetes
CRI-O doit être aligné exactement sur la version mineure de Kubernetes.
2.1 Dépôts
KUBERNETES_VERSION=v1.33
CRIO_VERSION=v1.33
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/${KUBERNETES_VERSION}/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/${KUBERNETES_VERSION}/rpm/repodata/repomd.xml.key
EOF
cat <<EOF | sudo tee /etc/yum.repos.d/cri-o.repo
[cri-o]
name=CRI-O
baseurl=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/${CRIO_VERSION}/rpm/
enabled=1
gpgcheck=1
gpgkey=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/${CRIO_VERSION}/rpm/repodata/repomd.xml.key
EOF
Le dépôt CRI-O a migré de
pkgs.k8s.io/addons:/cri-oversdownload.opensuse.org/repositories/isv:/cri-o. Utiliser exclusivement la nouvelle URL.
2.2 Installation des paquets
sudo dnf install -y \
cri-o \
kubelet \
kubeadm \
kubectl \
container-selinux \
conntrack \
socat
Sur Fedora 41+, les paquets sont versionnés. Utiliser les noms versionnés si dnf install cri-o installe une version différente :
sudo dnf install -y cri-o1.33 kubernetes1.33 kubernetes1.33-client kubernetes1.33-kubeadm
2.3 Démarrage de CRI-O
sudo systemctl enable --now crio
sudo systemctl status crio
Vérifications :
# Socket
ls -l /var/run/crio/crio.sock
# cgroup driver (doit être "systemd")
grep cgroup_manager /etc/crio/crio.conf
Résultat attendu pour cgroup_manager :
cgroup_manager = "systemd"
2.4 Activation de kubelet
sudo systemctl enable kubelet
Ne pas démarrer kubelet manuellement : kubeadm le démarre lors de l’init.
3. kubeadm init (fondation du cluster)
3.1 Nettoyage préalable (IMPORTANT si machine déjà utilisée)
Avant toute init :
sudo kubeadm reset -f
sudo rm -rf \
/etc/kubernetes \
/var/lib/kubelet \
/var/lib/etcd \
/etc/cni/net.d \
/var/lib/cni \
/var/run/flannel \
"$HOME/.kube"
3.2 Initialisation du control-plane
sudo kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket=unix:///var/run/crio/crio.sock
⚠️ Ne jamais continuer si cette commande échoue.
3.3 Configuration de kubectl
À exécuter en tant qu’utilisateur normal (pas root) :
mkdir -p "$HOME/.kube"
sudo cp /etc/kubernetes/admin.conf "$HOME/.kube/config"
sudo chown "$(id -u):$(id -g)" "$HOME/.kube/config"
3.4 Vérification immédiate (critique)
kubectl get nodes -o wide
Résultat attendu :
STATUS: NotReady
C’est normal : aucun CNI n’est encore installé.
4. Installation du CNI Flannel (VXLAN)
4.1 Déploiement Flannel
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
4.2 Attente de convergence
Attendre que le pod Flannel soit Running avant de continuer :
kubectl rollout status daemonset/kube-flannel-ds -n kube-flannel --timeout=120s
4.3 Vérification Flannel
kubectl get pods -n kube-flannel -o wide
Attendu :
kube-flannel-ds-* Running
5. Problème réel rencontré : CoreDNS bloqué en ContainerCreating
5.1 Symptôme
kubectl get pods -n kube-system
coredns-* 0/1 ContainerCreating
5.2 Cause réelle (non théorique)
Après plusieurs kubeadm init/reset, le bridge CNI cni0 reste DOWN, même si :
flannel.1est UP- le PodCIDR est correct
- le Node est Ready
Résultat :
- aucun pod non-hostNetwork ne peut créer son sandbox
- CoreDNS bloque indéfiniment
6. Correctif définitif du CNI (clé du tutoriel)
6.1 Arrêt kubelet
sudo systemctl stop kubelet
6.2 Suppression explicite du bridge CNI
sudo ip link delete cni0
6.3 Purge complète de l’état CNI local
sudo rm -rf /var/lib/cni/*
sudo rm -rf /etc/cni/net.d/*
sudo rm -rf /var/run/flannel
6.4 Redémarrage kubelet
sudo systemctl start kubelet
6.5 Recréation Flannel + CoreDNS
kubectl delete pod -n kube-flannel -l app=flannel
kubectl delete pod -n kube-system -l k8s-app=kube-dns
7. Validation réseau finale
7.1 Interfaces réseau
ip link show cni0
Attendu :
state UP
inet 10.244.0.1/24
7.2 Pods système
kubectl get pods -n kube-system -o wide
Attendu :
coredns-* 1/1 Running
7.3 Test DNS interne
kubectl run dns-test --image=busybox --restart=Never -- sleep 3600
kubectl exec dns-test -- nslookup kubernetes.default
Résultat attendu :
Address: 10.96.0.1
8. État final attendu
kubectl get nodes -o wide
STATUS: Ready
CRI-O: cri-o://1.33.x
Cluster 100 % opérationnel.
9. Ce qu’il ne faut plus jamais faire
- Ne pas relancer
kubeadm initsans purge complète - Ne pas empiler plusieurs CNI
- Ne pas laisser
cni0DOWN - Ne pas “forcer” CoreDNS
- Ne pas oublier d’ouvrir les ports firewalld avant
kubeadm init
10. Conclusion
Ce tutoriel décrit le chemin réel, pas idéalisé. Les deux règles clés sont :
Kubernetes ne répare jamais un CNI local cassé.
cni0 DOWN⇒ purge manuelle obligatoire.
firewalld actif bloque silencieusement Flannel VXLAN si UDP 8472 n’est pas ouvert et si les interfaces CNI ne sont pas en zone trusted.
Une fois ces règles respectées, CRI-O + Flannel + Kubernetes 1.33 est parfaitement stable.
Script Bash final (exécutable, idempotent)
À exécuter en root sur une machine vierge.
#!/usr/bin/env bash
set -euo pipefail
KUBERNETES_VERSION=v1.33
CRIO_VERSION=v1.33
# Utilisateur qui recevra ~/.kube/config (ne pas laisser à root)
KUBE_USER="${SUDO_USER:-$(logname 2>/dev/null || echo root)}"
echo "[1] Désactivation swap"
swapoff -a
sed -i '/swap/d' /etc/fstab
echo "[2] SELinux permissif"
setenforce 0 || true
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
echo "[3] Modules kernel"
modprobe overlay
modprobe br_netfilter
cat <<EOF >/etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
cat <<EOF >/etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
echo "[4] Dépôts Kubernetes et CRI-O"
cat <<EOF >/etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/${KUBERNETES_VERSION}/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/${KUBERNETES_VERSION}/rpm/repodata/repomd.xml.key
EOF
cat <<EOF >/etc/yum.repos.d/cri-o.repo
[cri-o]
name=CRI-O
baseurl=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/${CRIO_VERSION}/rpm/
enabled=1
gpgcheck=1
gpgkey=https://download.opensuse.org/repositories/isv:/cri-o:/stable:/${CRIO_VERSION}/rpm/repodata/repomd.xml.key
EOF
echo "[5] Installation des paquets"
dnf install -y \
cri-o \
kubelet \
kubeadm \
kubectl \
container-selinux \
conntrack \
socat
echo "[6] firewalld — ouverture des ports"
firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --permanent --add-port=10257/tcp
firewall-cmd --permanent --add-port=10259/tcp
firewall-cmd --permanent --add-port=8472/udp
firewall-cmd --permanent --zone=trusted --add-interface=cni0 || true
firewall-cmd --permanent --zone=trusted --add-interface=flannel.1 || true
firewall-cmd --reload
echo "[7] Reset Kubernetes"
kubeadm reset -f || true
rm -rf /etc/kubernetes /var/lib/kubelet /var/lib/etcd \
/etc/cni/net.d /var/lib/cni /var/run/flannel
KUBE_HOME=$(eval echo "~${KUBE_USER}")
rm -rf "${KUBE_HOME}/.kube"
echo "[8] Démarrage CRI-O"
systemctl enable --now crio
echo "[9] Activation kubelet"
systemctl enable kubelet
echo "[10] kubeadm init"
kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket=unix:///var/run/crio/crio.sock
echo "[11] Configuration kubectl pour ${KUBE_USER}"
mkdir -p "${KUBE_HOME}/.kube"
cp /etc/kubernetes/admin.conf "${KUBE_HOME}/.kube/config"
chown -R "${KUBE_USER}:$(id -gn "${KUBE_USER}")" "${KUBE_HOME}/.kube"
export KUBECONFIG=/etc/kubernetes/admin.conf
echo "[12] Flannel"
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
echo "[13] Attente convergence Flannel"
kubectl rollout status daemonset/kube-flannel-ds -n kube-flannel --timeout=120s
echo "[14] Fix CNI si cni0 reste DOWN"
systemctl stop kubelet
ip link delete cni0 2>/dev/null || true
rm -rf /var/lib/cni/* /etc/cni/net.d/* /var/run/flannel
systemctl start kubelet
sleep 5
kubectl delete pod -n kube-flannel -l app=flannel || true
kubectl delete pod -n kube-system -l k8s-app=kube-dns || true
echo "[OK] Attente pods système..."
kubectl wait --for=condition=Ready pod -l k8s-app=kube-dns -n kube-system --timeout=120s
echo "[OK] Cluster prêt"
kubectl get nodes -o wide
Fin.