Contexte : lab Kubernetes léger : un cluster K3s d'un master et deux workers dans trois conteneurs LXC privilégiés Proxmox VE, de la création des conteneurs à la validation · Testé sur : Proxmox VE, conteneurs Rocky Linux 9, K3s v1.31 · Dernière vérification : contenu de 2026 non revérifié
Adaptez les identifiants et les adresses avant toute exécution. Les numéros de conteneurs (VMID) et les adresses IP sont des variables : ne réutilisez jamais un numéro sans avoir vérifié qu'il est libre. Une commande
pct destroylancée sur un mauvais numéro supprime définitivement un conteneur, y compris en production.
Déployer un cluster K3s (distribution Kubernetes légère) sur trois conteneurs LXC Proxmox VE sous Rocky Linux 9 : un nœud master (plan de contrôle) et deux nœuds workers. La procédure couvre la création des conteneurs, la configuration spécifique à LXC, l'installation de K3s et la validation du cluster.
Cette méthode utilise des conteneurs privilégiés sans confinement AppArmor : un processus du conteneur dispose de droits étendus sur l'hôte. Réservez-la à un environnement de lab isolé. Pour des conteneurs non privilégiés, voir K3s dans des conteneurs LXC Proxmox.
root au shell de l'hôte.vmbr0, ainsi que l'adresse de la passerelle et du serveur DNS.root et pour l'utilisateur d'administration, conservés dans un gestionnaire de mots de passe (voir Utiliser Bitwarden).Inventaire des machines :
| Rôle | Numéro (VMID) | Nom d'hôte | Adresse IP | Système |
|---|---|---|---|---|
| Master | $MASTER_ID |
KubMaster | <IP_MASTER> |
Rocky Linux 9 |
| Worker | $WORKER1_ID |
KubWorker1 | <IP_WORKER1> |
Rocky Linux 9 |
| Worker | $WORKER2_ID |
KubWorker2 | <IP_WORKER2> |
Rocky Linux 9 |
Dans un shell root de l'hôte, renseignez les valeurs de votre environnement. Toutes les commandes des étapes 2 à 5 réutilisent ces variables : restez dans la même session, ou redéfinissez-les avant de continuer.
# À adapter à votre environnement
TEMPLATE="local:vztmpl/rockylinux-9-default_20221109_amd64.tar.xz"
STORAGE="local-lvm"
BRIDGE="vmbr0"
GATEWAY="<IP_PASSERELLE>"
DNS="<IP_DNS>"
MASTER_IP="<IP_MASTER>"
WORKER1_IP="<IP_WORKER1>"
WORKER2_IP="<IP_WORKER2>"
# Modèles déjà présents sur le stockage local
pveam list local | grep -i rocky
# Si absent : mettre à jour la liste, repérer le nom exact, puis télécharger
pveam update
pveam available --section system | grep -i rocky
pveam download local rockylinux-9-default_20221109_amd64.tar.xz
Adaptez le nom exact du modèle (ici
rockylinux-9-default_20221109_amd64.tar.xz) à ce que retournent ces commandes, et reportez-le dans la variableTEMPLATE.
La commande pvesh get /cluster/nextid renvoie le premier numéro libre du cluster Proxmox VE. Elle ne le réserve pas : appelez-la juste avant chaque création.
Master (KubMaster)
MASTER_ID=$(pvesh get /cluster/nextid)
pct create "$MASTER_ID" "$TEMPLATE" \
--hostname KubMaster \
--password '<MOT_DE_PASSE_ROOT>' \
--cores 2 \
--memory 8192 \
--swap 0 \
--rootfs "${STORAGE}:16" \
--net0 "name=eth0,bridge=${BRIDGE},ip=${MASTER_IP}/24,gw=${GATEWAY}" \
--nameserver "$DNS" \
--unprivileged 0 \
--features nesting=1,keyctl=1 \
--start 0
Worker 1 (KubWorker1)
WORKER1_ID=$(pvesh get /cluster/nextid)
pct create "$WORKER1_ID" "$TEMPLATE" \
--hostname KubWorker1 \
--password '<MOT_DE_PASSE_ROOT>' \
--cores 2 \
--memory 8192 \
--swap 0 \
--rootfs "${STORAGE}:16" \
--net0 "name=eth0,bridge=${BRIDGE},ip=${WORKER1_IP}/24,gw=${GATEWAY}" \
--nameserver "$DNS" \
--unprivileged 0 \
--features nesting=1,keyctl=1 \
--start 0
Worker 2 (KubWorker2)
WORKER2_ID=$(pvesh get /cluster/nextid)
pct create "$WORKER2_ID" "$TEMPLATE" \
--hostname KubWorker2 \
--password '<MOT_DE_PASSE_ROOT>' \
--cores 2 \
--memory 8192 \
--swap 0 \
--rootfs "${STORAGE}:16" \
--net0 "name=eth0,bridge=${BRIDGE},ip=${WORKER2_IP}/24,gw=${GATEWAY}" \
--nameserver "$DNS" \
--unprivileged 0 \
--features nesting=1,keyctl=1 \
--start 0
Notez les trois numéros attribués, ils resserviront pour la maintenance :
echo "Master : $MASTER_ID / Worker 1 : $WORKER1_ID / Worker 2 : $WORKER2_ID"
Pour que le mot de passe
rootn'apparaisse pas dans l'historique du shell, vous pouvez omettre l'option--password, puis le définir après le démarrage du conteneur avecpct enteret la commandepasswd.
K3s ne peut pas démarrer dans un conteneur LXC standard. Avant le premier démarrage, ajoutez ces lignes à la fin du fichier /etc/pve/lxc/<VMID>.conf de chacun des trois conteneurs :
lxc.apparmor.profile: unconfined
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw cgroup:rw
| Ligne | Effet |
|---|---|
lxc.apparmor.profile: unconfined |
Désactive le confinement AppArmor du conteneur |
lxc.cgroup2.devices.allow: a |
Autorise l'accès à tous les périphériques |
lxc.cap.drop: |
Ne retire aucune capacité Linux au conteneur |
lxc.mount.auto: proc:rw sys:rw cgroup:rw |
Monte /proc, /sys et les cgroups en lecture-écriture |
Commande rapide pour les trois conteneurs :
for VMID in "$MASTER_ID" "$WORKER1_ID" "$WORKER2_ID"; do
cat >> /etc/pve/lxc/${VMID}.conf << 'EOF'
lxc.apparmor.profile: unconfined
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw cgroup:rw
EOF
done
for VMID in "$MASTER_ID" "$WORKER1_ID" "$WORKER2_ID"; do
pct start "$VMID"
done
# Vérifier qu'ils tournent
pct list
Les commandes de cette étape sont à exécuter dans chacun des trois conteneurs. Depuis l'hôte, ouvrez un shell dans un conteneur avec pct enter suivi de son numéro, puis quittez-le avec exit.
Mise à jour du système et installation des outils :
dnf update -y
dnf install -y curl
Désactivation du pare-feu, pour faciliter la communication entre les pods (réseau Flannel en VXLAN) dans un environnement de lab :
systemctl disable --now firewalld
En production, conservez le pare-feu et ouvrez les ports nécessaires : TCP
6443(API Kubernetes), UDP8472(VXLAN Flannel) et TCP10250(kubelet).
Création de l'utilisateur d'administration, membre du groupe wheel (droits sudo) ; le mot de passe est demandé de façon interactive :
ADMIN_USER="<UTILISATEUR>"
useradd -m "$ADMIN_USER"
passwd "$ADMIN_USER"
usermod -aG wheel "$ADMIN_USER"
Dans le conteneur KubMaster :
curl -sfL https://get.k3s.io | sh -
Vérifiez que le service est actif :
systemctl status k3s --no-pager
Le fichier de configuration du cluster, /etc/rancher/k3s/k3s.yaml, appartient à root. Pour utiliser kubectl avec l'utilisateur d'administration, puis avec root :
ADMIN_USER="<UTILISATEUR>"
# Configuration pour l'utilisateur d'administration
mkdir -p /home/${ADMIN_USER}/.kube
cp /etc/rancher/k3s/k3s.yaml /home/${ADMIN_USER}/.kube/config
chown ${ADMIN_USER}:${ADMIN_USER} /home/${ADMIN_USER}/.kube/config
chmod 600 /home/${ADMIN_USER}/.kube/config
# Configuration pour root
mkdir -p /root/.kube
cp /etc/rancher/k3s/k3s.yaml /root/.kube/config
Ce fichier donne un accès administrateur complet au cluster : gardez-le en droits
600et ne le copiez pas hors des machines d'administration.
Ce jeton est nécessaire pour joindre les workers au cluster :
cat /var/lib/rancher/k3s/server/node-token
La valeur retournée commence par K10 et contient ::server:. Elle est désignée par <K3S_TOKEN> dans la suite.
Le jeton permet à n'importe quelle machine de rejoindre le cluster : traitez-le comme un mot de passe et ne le recopiez jamais dans une page ou un dépôt partagé.
Dans les conteneurs KubWorker1 et KubWorker2, définissez les variables en remplaçant les valeurs d'exemple :
MASTER_IP="<IP_MASTER>"
NODE_TOKEN="<K3S_TOKEN>"
Installez K3s en mode agent (worker) :
curl -sfL https://get.k3s.io | K3S_URL=https://${MASTER_IP}:6443 K3S_TOKEN=${NODE_TOKEN} sh -
Vérifiez le service sur chaque worker :
systemctl status k3s-agent --no-pager
Sur le master, vérifiez que les trois nœuds sont enregistrés :
kubectl get nodes
Résultat attendu :
NAME STATUS ROLES AGE VERSION
kubmaster Ready control-plane,master 10m v1.31.x+k3s1
kubworker1 Ready <none> 2m v1.31.x+k3s1
kubworker2 Ready <none> 2m v1.31.x+k3s1
Les trois nœuds sont à l'état
Ready: le cluster K3s est opérationnel.
Sur le master :
echo 'source <(kubectl completion bash)' >> ~/.bashrc
source ~/.bashrc
Sur le master :
systemctl restart k3s
Sur les workers :
systemctl restart k3s-agent
| Nœud | Commande |
|---|---|
| Master | /usr/local/bin/k3s-uninstall.sh |
| Worker | /usr/local/bin/k3s-agent-uninstall.sh |
Suppression définitive. Vérifiez d'abord que les trois numéros désignent bien les conteneurs du cluster : si les variables ont été perdues (nouvelle session), redéfinissez-les avec les numéros notés à l'étape 3.
Contrôle préalable, sur l'hôte Proxmox VE :
for VMID in "$MASTER_ID" "$WORKER1_ID" "$WORKER2_ID"; do
echo "$VMID : $(pct config "$VMID" | grep '^hostname:')"
done
Chaque ligne doit afficher KubMaster, KubWorker1 ou KubWorker2. Seulement dans ce cas, arrêtez et supprimez les conteneurs :
for VMID in "$MASTER_ID" "$WORKER1_ID" "$WORKER2_ID"; do
pct stop "$VMID" 2>/dev/null
pct destroy "$VMID" --purge
done
| Symptôme | Cause probable | Solution |
|---|---|---|
pct create refuse l'option keyctl |
Cette option ne concerne que les conteneurs non privilégiés | Retirez keyctl=1 de --features et gardez nesting=1 |
pct create ne trouve pas le modèle |
Nom du modèle différent sur votre hôte | Reprenez l'étape 2 et corrigez la variable TEMPLATE |
Le service k3s démarre puis s'arrête |
Options LXC absentes ou ajoutées après le premier démarrage | Vérifiez les quatre lignes de l'étape 4 dans le fichier du conteneur, redémarrez-le, puis consultez journalctl -u k3s |
Un worker n'apparaît pas dans kubectl get nodes |
Jeton ou adresse du master erronés, port 6443 injoignable |
Vérifiez MASTER_IP et NODE_TOKEN, testez l'accès au port 6443 du master, puis consultez journalctl -u k3s-agent |