Monter un cluster k3s

D'une à trois machines Ubuntu à un Kubernetes qui marche : k3s figé sur une version, kubectl et helm sur ton portable, l'ingress Traefik livré avec, cert-manager et un ClusterIssuer, puis un hello-world derrière HTTPS pour prouver toute la chaîne.

intermédiaire~40 min de manipulation
#kubernetes#k3s#traefik#cert-manager#helm

Pas encore validée de bout en bout — sois le premier.Signaler un problème

Brouillon — pas encore exécuté de bout en bout. Cette page est écrite mais son auteur ne l'a pas encore déroulée sur une vraie machine. Des commandes peuvent être fausses : lis avant de lancer, et dis-nous ce qui casse.

En un coup d'œilUne API, un ingress, un certificat
Ton cluster
kubectlHTTPSIngress
Ton portablekubectl · helm
Un navigateurhttps://
Nœud serveur 1 · k3s
Traefik:80 :443 · Ingress
Let's EncryptACME · HTTP-01
hello-worldDeployment · Service · Ingress

kubectl sur ton portable parle à l'API k3s du premier nœud. Les navigateurs atteignent Traefik sur le 443 de n'importe quel nœud ; il route par nom d'hôte vers le Service hello-world. cert-manager obtient le certificat et le range dans un Secret que lit Traefik.

k3s, c'est Kubernetes en un seul binaire : l'API server, le scheduler, le kubelet, un datastore et un ingress controller, installés par un script en moins d'une minute. Cette page part d'une machine Ubuntu et arrive à un cluster que tu pilotes depuis ton portable, avec des certificats émis tout seuls, prouvé par un hello-world derrière HTTPS sur .

Avant de commencer

Sur chaque nœud, en root :

$swapoff -a
$sed -i '/ swap / s/^/#/' /etc/fstab
$timedatectl set-ntp true
$ufw allow 22/tcp
$ufw allow 80/tcp
$ufw allow 443/tcp
$ufw allow 6443/tcp
$ufw allow from 10.42.0.0/16 to any
$ufw allow from 10.43.0.0/16 to any

Installer le premier serveur

$curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION= sh -s - server \
$ --tls-san --write-kubeconfig-mode 644
Si le nœud reste NotReady

Laisse-lui une minute : le nœud passe Ready une fois flannel et CoreDNS lancés. S'il reste NotReady, journalctl -u k3s --no-pager | tail -50 nomme en général la cause : swap encore actif, un pare-feu qui bloque 8472/udp, ou un reste de Docker ou de containerd sur la machine. Les images cloud Ubuntu avec apparmor passent sans problème ; les images Raspberry Pi demandent d'activer les cgroups dans cmdline.txt, voir la doc k3s.

Kubeconfig, kubectl et helm sur le portable

$mkdir -p ~/.kube
$ssh root@ cat /etc/rancher/k3s/k3s.yaml | sed "s/127.0.0.1//" > ~/.kube/config
$chmod 600 ~/.kube/config
Commande sensible — exécute un script distant. Vérifie avant d'exécuter.
$curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
$sudo install -m 755 kubectl /usr/local/bin/kubectl
$curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Vérification
$kubectl get nodes --no-headers | awk '{print $2}' | sort -u
Retour attendu
Ready
Si kubectl dit x509: certificate is valid for …

Le certificat de l'API n'inclut pas : l'option --tls-san manquait ou portait une autre adresse. Relance la commande d'installation sur le premier nœud avec le bon --tls-san ; le script est idempotent et ne réécrit que l'unité et le certificat.

Ingress : Traefik et ServiceLB

$kubectl -n kube-system get svc traefik
Vérification
$kubectl -n kube-system rollout status deploy/traefik
Retour attendu
deployment "traefik" successfully rolled out

cert-manager et un ClusterIssuer

$helm repo add jetstack https://charts.jetstack.io --force-update
$helm upgrade --install cert-manager jetstack/cert-manager \
$ --namespace cert-manager --create-namespace --set crds.enabled=true --wait
Vérification
$kubectl -n cert-manager rollout status deploy/cert-manager-webhook
Retour attendu
deployment "cert-manager-webhook" successfully rolled out
clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email:
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
ingress:
ingressClassName: traefik
$kubectl apply -f clusterissuer.yaml

Stockage : la classe local-path

$kubectl get storageclass

Hello world derrière HTTPS

hello.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
replicas: 1
selector:
matchLabels: { app: hello }
template:
metadata:
labels: { app: hello }
spec:
containers:
- name: whoami
image: traefik/whoami:v1.10
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: hello
spec:
selector: { app: hello }
ports:
- port: 80
targetPort: 80
hello-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: traefik
tls:
- hosts: [""]
secretName: hello-tls
rules:
- host:
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello
port: { number: 80 }
$kubectl apply -f hello.yaml -f hello-ingress.yaml
$kubectl get certificate hello-tls -w
Vérification
$kubectl wait --for=condition=Ready certificate/hello-tls --timeout=120s
Retour attendu
certificate.cert-manager.io/hello-tls condition met
Vérification
$curl -sI https:// | head -1
Retour attendu
HTTP/2 200
Si le certificat reste non Ready

Par ordre de probabilité :

  • ne résout pas encore vers un nœud, ou résout vers une adresse privée que Let's Encrypt ne peut pas joindre. Fais un dig +short du nom depuis l'extérieur.
  • Le port 80 est fermé quelque part (ufw, le pare-feu de l'hébergeur) : HTTP-01 en a besoin, même si les utilisateurs n'utilisent que le 443.
  • Limite de débit atteinte après trop d'essais : kubectl describe order le dit. Utilise l'endpoint de staging jusqu'à ce que le montage soit bon.
  • Le Challenge est pending avec un wrong status code 404 : Traefik ne sert pas l'Ingress temporaire, regarde kubectl -n kube-system logs deploy/traefik.

Mettre à jour, désinstaller

Mettre k3s à jour, c'est relancer le script d'installation avec une version plus récente ; désinstaller, c'est un script par nœud.

Terminé

Un nœud, piloté depuis ton portable, un ingress sur chaque nœud, des certificats qui s'émettent et se renouvellent seuls, et une StorageClass pour la base. Le hello-world peut partir :

$kubectl delete -f hello-ingress.yaml -f hello.yaml

La page suivante déploie indicat sur ce cluster : namespace, secrets, PostgreSQL, l'application avec son Ingress sur , et un autoscaler.

Tout a fonctionné ?

Si tu as suivi cette page jusqu'au bout sur une vraie machine, dis-le. Ta validation est datée et enregistre ta stack : le prochain lecteur sur le même chemin sait que ça marche toujours.

Cette copie est en lecture seule. Pour dire que ça marche, ou que ça ne marche pas, ouvre une issue

Seuls tes choix de stack sont enregistrés, jamais tes valeurs. Le pseudo reste sur ce navigateur.