Orchestration

k0s

Distribution Kubernetes zéro dépendance développée par Mirantis - un seul binaire statique, tourne sur n'importe quel Linux sans rien installer.

k0s ("zero friction Kubernetes") est une distribution Kubernetes certifiée packagée en un seul binaire statique sans aucune dépendance système. Contrairement à k3s, k0s ne regroupe pas d'Ingress controller ni de provisioner de stockage par défaut : il fournit le strict minimum pour un cluster fonctionnel, laissant le choix de la stack réseau et stockage à l'opérateur.

Idéal pour : clusters multi-distribution Linux, edge computing, environnements air-gapped, automatisation via k0sctl.


Informations essentielles

Origine : Mirantis (États-Unis)  ·  Licence : Apache 2.0  ·  Architectures : x86_64, ARM64, ARMv7

Liens : Site officiel  ·  Documentation  ·  GitHub  ·  Releases

Support : k0s suit le cycle Kubernetes upstream - les 3 dernières versions mineures sont maintenues (~15 mois par version). La version k0s suit le schéma v1.35.3+k0s.0 (version Kubernetes + patch k0s).

Stack par défaut

ComposantValeur
Runtimecontainerd (inclus)
CNIkube-router
Ingress controllerAucun (à installer séparément)
StockageAucun (à installer séparément)
Base de donnéesSQLite/kine (nœud unique), etcd (multi-nœuds)
DNSCoreDNS

Composants embarqués

ComposantRôle
containerdRuntime de conteneurs
kube-routerCNI (réseau pods, BGP natif)
CoreDNSDNS interne cluster
Metrics ServerMétriques CPU/RAM
KonnectivityTunnel control plane ↔ workers
kineAdaptateur SQLite/MySQL/PostgreSQL pour remplacer etcd

Chaque composant peut être désactivé ou remplacé dans k0s.yaml. Aucun Ingress ni provisioner de stockage n'est inclus - à ajouter selon le besoin.


Prérequis

Système d'exploitation

  • N'importe quel Linux 64-bit - aucun paquet OS requis
  • Kernel ≥ 3.10 (4.x+ recommandé)
  • iptables ou nftables disponible

Ports à ouvrir

PortProtocoleNœudRôle
6443TCPControllerAPI Kubernetes
9443TCPControllerAPI join k0s (workers et controllers)
8132TCPControllerKonnectivity (tunnel workers → control plane)
10250TCPWorkerkubelet (metrics)
179TCPTouskube-router BGP (inter-nœuds)
2379–2380TCPControlleretcd (HA uniquement)

Installation

Nœud unique (controller + worker)

# Télécharger et installer le binaire
curl --proto '=https' --tlsv1.2 -sSf https://get.k0s.sh | sudo sh

# Installer et démarrer en mode single
sudo k0s install controller --single
sudo k0s start

Le service systemd s'appelle k0scontroller.

--single fusionne controller et worker dans un seul processus. Pour un cluster multi-nœuds où le controller doit aussi exécuter des workloads, utiliser --enable-worker à la place lors de l'installation du controller - équivalent du detaint Kubernetes.

Vérifier le statut

sudo systemctl status k0scontroller
sudo k0s kubectl get nodes

Configurer kubectl en local (sans sudo)

mkdir -p ~/.kube
sudo cp /var/lib/k0s/pki/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
# Si accès distant, remplacer 127.0.0.1 par l'IP du controller
sed -i 's/127.0.0.1/<IP_CONTROLLER>/' ~/.kube/config

kubectl get nodes

Installer une version spécifique

curl --proto '=https' --tlsv1.2 -sSf https://get.k0s.sh | \
  sudo K0S_VERSION=v1.35.3+k0s.0 sh

Cluster multi-nœuds

Déploiement manuel

1. Installer le controller

# Générer la config par défaut
mkdir -p /etc/k0s && k0s config create > /etc/k0s/k0s.yaml

# Installer sans --single (workers séparés)
sudo k0s install controller -c /etc/k0s/k0s.yaml
sudo k0s start

2. Générer un token worker

# Sur le controller
sudo k0s token create --role=worker --expiry=24h > /tmp/worker-token

3. Rejoindre un worker

# Copier /tmp/worker-token sur le worker, puis :
sudo k0s install worker --token-file /path/to/worker-token
sudo k0s start

Le service worker s'appelle k0sworker.

4. Vérifier les nœuds

sudo k0s kubectl get nodes -o wide

Déploiement avec k0sctl (recommandé)

k0sctl est l'outil officiel pour déployer et gérer des clusters k0s de façon déclarative, via SSH.

Installer k0sctl

# Linux (téléchargement direct)
curl -sSLf https://github.com/k0sproject/k0sctl/releases/latest/download/k0sctl-linux-amd64 \
  -o /usr/local/bin/k0sctl && chmod +x /usr/local/bin/k0sctl

# macOS
brew install k0sproject/tap/k0sctl

Déployer un cluster

# Générer un template de config
k0sctl init > k0sctl.yaml

# Éditer k0sctl.yaml avec les IPs et clés SSH des nœuds, puis :
k0sctl apply --config k0sctl.yaml

# Récupérer le kubeconfig
k0sctl kubeconfig --config k0sctl.yaml > ~/.kube/config

# Vérifier
kubectl get nodes

Template k0sctl.yaml

apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: mon-cluster
spec:
  hosts:
  - role: controller
    ssh:
      address: 192.168.1.10
      user: root
      keyPath: ~/.ssh/id_rsa
  - role: worker
    ssh:
      address: 192.168.1.11
      user: root
      keyPath: ~/.ssh/id_rsa
  - role: worker
    ssh:
      address: 192.168.1.12
      user: root
      keyPath: ~/.ssh/id_rsa
  k0s:
    version: v1.35.3+k0s.0

Configuration (k0s.yaml)

Le fichier de configuration principal se trouve dans /etc/k0s/k0s.yaml.

# Générer la config par défaut
k0s config create > /etc/k0s/k0s.yaml
# /etc/k0s/k0s.yaml
apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
metadata:
  name: k0s
spec:
  api:
    address: 192.168.1.10       # IP du controller
    port: 6443
    externalAddress: 192.168.1.100  # IP du LB (HA uniquement)
    sans:
      - 192.168.1.10
      - k0s.example.com
  network:
    provider: kuberouter          # ou calico
    podCIDR: 10.244.0.0/16
    serviceCIDR: 10.96.0.0/12
  storage:
    type: etcd                    # ou kine (SQLite)
  extensions:
    helm:
      charts:
        - name: ingress-nginx
          chartname: ingress-nginx/ingress-nginx
          version: "4.10.0"
          namespace: ingress-nginx
          values: |
            controller:
              service:
                type: NodePort

Tout changement de config nécessite un redémarrage de k0s.


Ingress

k0s n'inclut pas d'Ingress controller - à déployer selon le besoin. Un Ingress expose des Services HTTP/HTTPS via un point d'entrée unique avec routage par nom d'hôte ou chemin.

Installer ingress-nginx

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  --set controller.service.type=NodePort
# Vérifier
kubectl -n ingress-nginx rollout status deployment/ingress-nginx-controller
kubectl get svc -n ingress-nginx

Sur bare-metal, le Service est de type NodePort. Pour une IP externe stable, voir MetalLB.

Exemple de ressource Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: mon-app
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: app.mondomaine.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: mon-service
            port:
              number: 80

Gateway API est le successeur officiel des Ingress (plus expressif, multi-tenant). À considérer pour les nouveaux clusters : gateway-api.sigs.k8s.io.


Stockage persistant (PVC / StorageClass)

k0s ne fournit aucun provisioner de stockage par défaut.

local-path-provisioner (labo / single-node)

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml

# En faire la StorageClass par défaut
kubectl patch storageclass local-path \
  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

kubectl get storageclass

Longhorn (stockage distribué, multi-nœuds)

helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn \
  --namespace longhorn-system --create-namespace

Exemple : PVC + Pod

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mon-volume
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-avec-volume
spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - mountPath: /data
      name: data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: mon-volume
kubectl apply -f pvc-pod.yaml
kubectl get pvc
kubectl get pv

RBAC (contrôle d'accès)

Kubernetes utilise le RBAC (Role-Based Access Control) pour contrôler qui peut faire quoi sur le cluster. Activé par défaut dans k0s.

RessourcePortéeDescription
RoleNamespacePermissions dans un namespace donné
ClusterRoleClusterPermissions à l'échelle du cluster
RoleBindingNamespaceAssocie un Role à un sujet
ClusterRoleBindingClusterAssocie un ClusterRole à un sujet

Les sujets peuvent être : User, Group, ou ServiceAccount.

Exemple : accès lecture seule sur un namespace

# role-readonly.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: readonly
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: readonly-binding
  namespace: production
subjects:
- kind: User
  name: alice
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: readonly
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f role-readonly.yaml

# Vérifier les permissions d'un utilisateur
kubectl auth can-i list pods --namespace=production --as=alice

ServiceAccount pour une application

kubectl create serviceaccount mon-app -n production

# Associer un Role existant
kubectl create rolebinding mon-app-binding \
  --role=readonly \
  --serviceaccount=production:mon-app \
  -n production

NetworkPolicy

Par défaut, tous les pods peuvent communiquer entre eux sans restriction. Les NetworkPolicy permettent de filtrer le trafic réseau entre pods.

kube-router (CNI par défaut de k0s) supporte les NetworkPolicy nativement. Si vous avez remplacé kube-router par Calico ou Cilium, le support est identique.

Isoler un namespace (deny-all par défaut)

# deny-all.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Autoriser uniquement le frontend vers le backend

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
kubectl apply -f deny-all.yaml
kubectl get networkpolicy -n production

Haute disponibilité (HA)

k0s supporte le HA avec 3 ou 5 controllers (quorum etcd) et un load balancer TCP.

# Premier controller
curl --proto '=https' --tlsv1.2 -sSf https://get.k0s.sh | sudo sh
sudo k0s install controller -c /etc/k0s/k0s.yaml
sudo k0s start

# Token pour les autres controllers
sudo k0s token create --role=controller --expiry=1h > /tmp/controller-token

# Autres controllers
sudo k0s install controller \
  -c /etc/k0s/k0s.yaml \
  --token-file /tmp/controller-token
sudo k0s start

k0sctl gère automatiquement la distribution des certificats PKI en mode HA - recommandé pour éviter les erreurs manuelles.


Sauvegarde et restauration

# Sauvegarder (sur le controller)
sudo k0s stop
k0s backup --save-path=/tmp/
# Crée : /tmp/k0s_backup_<timestamp>.tar.gz

# Restaurer
sudo k0s stop
k0s restore /tmp/k0s_backup_<timestamp>.tar.gz
sudo k0s start

Via k0sctl :

k0sctl backup
k0sctl apply --restore-from ./k0s_backup_<timestamp>.tar.gz

Mise à jour

Règle absolue : ne jamais sauter de version mineure. Mettre à jour de v1.35 → v1.36, jamais de v1.34 → v1.36 directement.

Via k0sctl (recommandé)

Modifier la version dans k0sctl.yaml puis réappliquer :

k0s:
  version: v1.36.1+k0s.0   # bumper ici
k0sctl apply --config k0sctl.yaml

k0sctl gère automatiquement l'ordre de mise à jour (controllers d'abord, puis workers).

Manuellement

# Télécharger et installer le nouveau binaire
curl --proto '=https' --tlsv1.2 -sSf https://get.k0s.sh | sudo K0S_VERSION=v1.36.1+k0s.0 sh

# Controllers en premier
sudo systemctl restart k0scontroller

# Puis chaque worker
sudo systemctl restart k0sworker

Ne pas mettre à jour plusieurs controllers simultanément en mode HA.

Mettre à jour les addons

Les composants embarqués (CoreDNS, kube-router, Metrics Server) sont mis à jour avec le binaire k0s. Les addons installés séparément sont à mettre à jour manuellement :

# ingress-nginx (si installé via Helm)
helm repo update
helm upgrade ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx

# Longhorn (si installé)
helm upgrade longhorn longhorn/longhorn -n longhorn-system

Vérifier la matrice de compatibilité de chaque addon avec la version Kubernetes cible avant de mettre à jour.


Troubleshooting

Logs du controller

sudo journalctl -u k0scontroller -f
sudo journalctl -u k0scontroller --since "10 minutes ago"

Logs d'un worker

sudo journalctl -u k0sworker -f

Inspecter un pod en erreur

kubectl describe pod <nom-pod>
kubectl logs <nom-pod>
kubectl logs <nom-pod> --previous
kubectl exec -it <nom-pod> -- /bin/sh

Pod bloqué en Pending

kubectl describe pod <nom-pod> | grep -A10 Events
kubectl top nodes
kubectl describe nodes | grep -A5 "Allocated resources"

Problèmes réseau kube-router

# Vérifier que kube-router tourne sur chaque nœud
kubectl get pods -n kube-system -l k8s-app=kube-router

# Logs kube-router
kubectl logs -n kube-system -l k8s-app=kube-router

Reset complet

sudo k0s stop
sudo k0s reset
# Recommandé : redémarrer le nœud après reset
sudo reboot

Commandes utiles

# Gestion des contextes (multi-cluster)
kubectl config get-contexts                                        # Lister les contextes disponibles
kubectl config current-context                                     # Contexte actif
kubectl config use-context <nom>                                   # Changer de cluster
kubectl config set-context --current --namespace=<ns>             # Namespace par défaut du contexte actif

# Fusionner plusieurs kubeconfig
KUBECONFIG=~/.kube/config:~/.kube/config-cluster2 kubectl config view --flatten > ~/.kube/config-merged
# État du cluster
sudo k0s kubectl get nodes -o wide
sudo k0s kubectl get pods -A
sudo k0s kubectl get svc -A

# Version k0s et Kubernetes
sudo k0s version
sudo k0s kubectl version

# Config active
sudo k0s config status

# Token de jointure (worker)
sudo k0s token create --role=worker --expiry=24h

# Événements du cluster
kubectl get events -A --sort-by='.lastTimestamp' | tail -20

# Port-forward
kubectl port-forward svc/<nom-service> 8080:80

# Redémarrer un deployment
kubectl rollout restart deployment/<nom>

Ressources

Newsletter · 2 000+ abonnés

Reste au courant de ce qui bouge en prod

RudeOps veille devops hebdo, droit au but.

Gratuit · Sans spam · Désinscription en un clic