Kubernetes – Container-Orchestrierung Grundlagen
Pods, Deployments, Services, kubectl, Helm und Ingress verstehen – inklusive k3s als schlanker Einstieg fuer Schweizer KMU.
Warum Kubernetes und wann brauchst du es ueberhaupt?
Docker loest das Problem “Wie packe ich eine Anwendung reproduzierbar ein”. Kubernetes loest das naechste Problem: “Wie betreibe ich hunderte Container zuverlaessig, verteilt auf mehreren Maschinen, mit automatischem Neustart bei Absturz, automatischer Skalierung und Zero-Downtime-Updates”. Kubernetes (kurz K8s, weil zwischen dem K und dem s acht Buchstaben stehen) ist ein Orchestrierungssystem, das von Google entwickelt und 2014 als Open-Source-Projekt veroeffentlicht wurde. Es liegt heute bei der Cloud Native Computing Foundation (CNCF).
Die ehrliche Wahrheit vorweg: Fuer die meisten Schweizer KMU mit ein paar Dutzend virtuellen Maschinen und einer Handvoll Applikationen ist Kubernetes oft ueberdimensioniert. Ein docker compose up -d auf zwei, drei Servern erledigt 80 Prozent der Faelle problemlos. Kubernetes lohnt sich, sobald mindestens eine dieser Bedingungen zutrifft:
- Du betreibst mehrere Dutzend Microservices, die unabhaengig skaliert werden muessen.
- Du brauchst echte Selbstheilung: Ein Node faellt aus, die Workloads wandern automatisch auf andere Nodes.
- Du willst deklarativ arbeiten: Der gewuenschte Zustand steht im YAML, Kubernetes sorgt selbststaendig dafuer, dass die Realitaet dem entspricht.
- Mehrere Teams teilen sich eine Infrastruktur und brauchen Isolation via Namespaces und RBAC.
Architektur: Control Plane und Worker Nodes
Ein Kubernetes-Cluster besteht aus zwei Rollen von Maschinen (physisch, virtuell oder Cloud-Instanzen):
| Komponente | Rolle | Laeuft auf |
|---|---|---|
| kube-apiserver | Zentrale Schnittstelle, alle Befehle (auch von kubectl) laufen hier durch | Control Plane |
| etcd | Verteilter Key-Value-Store, speichert den gesamten Cluster-Zustand | Control Plane |
| kube-scheduler | Entscheidet, auf welchem Node ein neuer Pod platziert wird | Control Plane |
| kube-controller-manager | Ueberwacht Ist- vs. Soll-Zustand, startet z.B. fehlende Pods neu | Control Plane |
| kubelet | Agent, der auf jedem Node laeuft und Pods gemaess Vorgabe startet | Worker Node |
| kube-proxy | Regelt Netzwerkweiterleitung fuer Services auf jedem Node | Worker Node |
| Container-Runtime | Startet die eigentlichen Container (containerd, CRI-O) | Worker Node |
Der Ablauf in Kurzform: Du schickst per kubectl ein YAML-Manifest an den kube-apiserver. Der Scheduler entscheidet, welcher Node genug freie Ressourcen hat. Das kubelet auf diesem Node zieht das Image und startet den Container ueber die Runtime. Der controller-manager beobachtet laufend, ob Ist- und Soll-Zustand uebereinstimmen – faellt ein Pod aus, wird automatisch ein neuer erstellt.
Pods – die kleinste Einheit
Ein Pod ist nicht dasselbe wie ein Container. Ein Pod ist eine Gruppe von einem oder mehreren Containern, die sich Netzwerk (dieselbe IP-Adresse, gleicher Loopback) und optional Storage-Volumes teilen. In der Praxis laeuft in den allermeisten Faellen genau ein Container pro Pod – Mehrfach-Container-Pods (Sidecar-Pattern) nutzt man fuer Logging-Agenten, Service-Mesh-Proxys (z.B. Envoy bei Istio) oder Init-Container fuer Vorbereitungsschritte.
# pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-test
labels:
app: nginx-test
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "250m"
memory: "128Mi"
kubectl apply -f pod-nginx.yaml
kubectl get pods
kubectl describe pod nginx-test
kubectl logs nginx-test
kubectl delete pod nginx-test
Wichtig fuer die Ressourcenplanung: requests ist der Wert, den der Scheduler fuer die Platzierung verwendet (garantierte Mindestressourcen), limits ist die harte Obergrenze. Ueberschreitet ein Container sein Memory-Limit, wird er vom Kernel mit OOMKilled beendet. CPU-Limits fuehren dagegen zu Throttling, nicht zum Abbruch.
Deployments – Pods verwalten, skalieren, aktualisieren
Ein Deployment ist die Kontrollinstanz, die dafuer sorgt, dass immer die gewuenschte Anzahl Pod-Replikas laeuft. Es verwaltet im Hintergrund ein ReplicaSet, das wiederum die einzelnen Pods erzeugt.
# deployment-webapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
labels:
app: webapp
spec:
replicas: 3
selector:
matchLabels:
app: webapp
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: registry.example.ch/webapp:1.4.2
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
# Anwenden
kubectl apply -f deployment-webapp.yaml
# Status pruefen
kubectl get deployments
kubectl rollout status deployment/webapp
# Skalieren
kubectl scale deployment webapp --replicas=5
# Image aktualisieren (loest RollingUpdate aus)
kubectl set image deployment/webapp webapp=registry.example.ch/webapp:1.5.0
# Rollout-Historie ansehen
kubectl rollout history deployment/webapp
# Bei Problemen zurueckrollen
kubectl rollout undo deployment/webapp
kubectl rollout undo deployment/webapp --to-revision=2
Der Unterschied zwischen readinessProbe und livenessProbe ist ein haeufiger Stolperstein: Die Readiness-Probe entscheidet, ob ein Pod Traffic vom Service erhalten darf (schlaegt sie fehl, wird der Pod aus dem Load Balancing genommen, aber nicht neu gestartet). Die Liveness-Probe entscheidet, ob der Container ueberhaupt noch lebt – schlaegt sie fehl, killt Kubernetes den Container und startet ihn neu.
Services – stabile Netzwerkadressen fuer verguengliche Pods
Pods sind verguenglich: Sie bekommen bei jedem Neustart eine neue IP-Adresse. Ein Service loest das, indem er eine stabile virtuelle IP und einen DNS-Namen bereitstellt und den Traffic per Label-Selector auf die passenden Pods verteilt.
| Service-Typ | Zweck | Erreichbarkeit |
|---|---|---|
| ClusterIP (Default) | Interne Kommunikation zwischen Diensten im Cluster | Nur innerhalb des Clusters |
| NodePort | Oeffnet einen festen Port (30000–32767) auf jedem Node | Node-IP:Port von aussen |
| LoadBalancer | Fordert einen externen Load Balancer an (bei Cloud-Providern automatisch) | Oeffentliche IP |
| ExternalName | Mappt einen Service-Namen auf einen externen DNS-Namen | CNAME-artig, kein Proxying |
# service-webapp.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp-svc
spec:
type: ClusterIP
selector:
app: webapp
ports:
- port: 80
targetPort: 8080
protocol: TCP
kubectl apply -f service-webapp.yaml
kubectl get services
kubectl get endpoints webapp-svc
# Kurztest von innerhalb des Clusters
kubectl run curl-test --image=curlimages/curl -it --rm -- curl http://webapp-svc
Der Service-DNS-Name folgt dem Schema <service>.<namespace>.svc.cluster.local, innerhalb desselben Namespace reicht meist der kurze Name webapp-svc. Das ist der Grund, warum Microservices sich gegenseitig einfach ueber den Servicenamen ansprechen koennen, ohne IP-Adressen zu kennen.
Ingress – HTTP(S)-Routing und Load Balancing auf Layer 7
Waehrend ein Service auf Layer 4 (TCP/UDP) arbeitet, regelt ein Ingress das HTTP/HTTPS-Routing auf Layer 7: Ein einziger Eingangspunkt kann anhand von Hostname oder Pfad auf viele verschiedene Services verteilen – inklusive TLS-Terminierung. Ingress selbst ist nur die Regel-Definition; ausgefuehrt wird sie von einem Ingress-Controller (z.B. NGINX Ingress Controller, Traefik oder HAProxy), der als Pod im Cluster laeuft.
# ingress-webapp.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- webapp.firma-kmu.ch
secretName: webapp-tls
rules:
- host: webapp.firma-kmu.ch
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
# Ingress-Controller installieren (NGINX, per Helm)
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
kubectl apply -f ingress-webapp.yaml
kubectl get ingress
In diesem Beispiel routet webapp.firma-kmu.ch/ auf den Frontend-Service und webapp.firma-kmu.ch/api auf einen separaten API-Service – ein klassisches Muster, um mehrere Anwendungen hinter einer einzigen oeffentlichen IP und einem TLS-Zertifikat zu betreiben. Mit cert-manager (separates CNCF-Projekt) lassen sich Let’s-Encrypt-Zertifikate automatisch beziehen und erneuern.
kubectl – die wichtigsten Befehle im Alltag
# Kontext und Cluster-Info
kubectl cluster-info
kubectl config get-contexts
kubectl config use-context mein-cluster
kubectl config set-context --current --namespace=produktion
# Ressourcen anzeigen
kubectl get nodes -o wide
kubectl get pods -A # -A = alle Namespaces
kubectl get pods -n produktion -w # -w = watch (live)
kubectl get all -n produktion
# Details und Fehlersuche
kubectl describe pod webapp-7d8f9c6b5-x2klm
kubectl logs webapp-7d8f9c6b5-x2klm
kubectl logs webapp-7d8f9c6b5-x2klm --previous # Logs des vorherigen (abgestuerzten) Containers
kubectl exec -it webapp-7d8f9c6b5-x2klm -- /bin/sh
# YAML aus laufendem Cluster ziehen
kubectl get deployment webapp -o yaml > webapp-backup.yaml
# Aendern und Bereinigen
kubectl apply -f deployment-webapp.yaml
kubectl edit deployment webapp
kubectl delete -f deployment-webapp.yaml
kubectl delete pod webapp-7d8f9c6b5-x2klm # wird vom Deployment sofort ersetzt
# Ressourcennutzung (benoetigt metrics-server)
kubectl top nodes
kubectl top pods -n produktion
# Namespaces
kubectl create namespace staging
kubectl get namespaces
Helm – der Paketmanager fuer Kubernetes
Sobald eine Anwendung aus mehreren zusammenhaengenden Ressourcen besteht (Deployment, Service, Ingress, ConfigMap, Secret, PersistentVolumeClaim), wird das Verwalten einzelner YAML-Dateien schnell unuebersichtlich. Helm buendelt diese Ressourcen in einem Chart und macht sie ueber values.yaml parametrisierbar – vergleichbar mit einem Windows-Installer, der bei der Installation nach Zielpfad und Optionen fragt.
# Helm installieren (Windows via winget)
winget install Helm.Helm
# Offizielles Repository hinzufuegen (Beispiel: Bitnami)
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Verfuegbare Charts suchen
helm search repo wordpress
# Chart installieren
helm install mein-wordpress bitnami/wordpress \
--namespace webshop --create-namespace \
--set wordpressUsername=admin \
--set persistence.size=20Gi
# Installierte Releases anzeigen
helm list -A
# Konfiguration aendern und aktualisieren
helm upgrade mein-wordpress bitnami/wordpress \
--namespace webshop \
--set replicaCount=2
# Zuruecksetzen auf vorherige Version
helm rollback mein-wordpress 1 -n webshop
# Deinstallieren (loescht alle zugehoerigen Ressourcen)
helm uninstall mein-wordpress -n webshop
Ein eigenes Chart fuer eine interne Applikation legst du mit helm create meine-app an – das generiert ein Skelett mit Chart.yaml, values.yaml und templates/. In den Templates stehen die YAML-Manifeste mit Platzhaltern im Go-Template-Format, die zur Installationszeit durch Werte aus der values.yaml ersetzt werden (z.B. Image-Repository und Image-Tag als Variablen statt fest codiert):
# templates/deployment.yaml (Ausschnitt eines Helm-Charts)
containers:
- name: meine-app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
Kubernetes vs. Docker Compose – Entscheidungshilfe
Das ist die haeufigste Frage im KMU-Umfeld: reicht Docker Compose, oder braucht es Kubernetes?
| Kriterium | Docker Compose | Kubernetes |
|---|---|---|
| Lernkurve | Niedrig, ein YAML-File | Hoch, viele Konzepte (Pods, Services, RBAC, …) |
| Multi-Host-Betrieb | Nein (nativ nur ein Host) | Ja, das ist der Kernzweck |
| Automatisches Failover | Nein | Ja, Pods wandern auf andere Nodes |
| Selbstheilung | Eingeschraenkt (restart: always) | Umfassend (Health-Checks, Auto-Restart) |
| Rolling Updates | Manuell/Skripting noetig | Eingebaut (kubectl rollout) |
| Horizontale Skalierung | Manuell, begrenzt sinnvoll | Automatisch via HPA (Horizontal Pod Autoscaler) |
| Ressourcen-Overhead | Minimal | Control Plane braucht selbst CPU/RAM |
| Betriebsaufwand | Gering | Signifikant (Updates, Zertifikate, etcd-Backups) |
| Typischer Einsatz | 1–2 Server, wenige Dienste | Viele Services, mehrere Nodes, hohe Verfuegbarkeit |
Vereinfachter Entscheidungsablauf
Brauchst du Multi-Host-Ausfallsicherheit oder Auto-Scaling?
├── Nein → Docker Compose reicht
└── Ja
├── Team kennt Kubernetes noch nicht / kleines Setup (1-5 Nodes)?
│ └── Ja → k3s als Einstieg
└── Grosses Setup, mehrere Teams, hohe Verfuegbarkeit noetig?
└── Ja → Vollstaendiges Kubernetes (kubeadm, oder Managed: AKS/EKS/GKE)
k3s – der leichte Einstieg fuer Schweizer KMU
k3s ist eine von Rancher (heute Teil von SUSE) entwickelte, CNCF-zertifizierte Kubernetes-Distribution, die als einzelnes Binary unter 100 MB daherkommt. Sie ersetzt etcd standardmaessig durch SQLite (fuer Single-Node-Setups) und entfernt selten genutzte Alpha-Features, ist aber API-kompatibel zu Standard-Kubernetes. Genau das macht k3s zum idealen Einstiegspunkt fuer KMU: Ein Verwaltungsserver oder sogar ein Raspberry Pi reicht als erster Cluster-Node, alle gelernten kubectl- und Helm-Befehle funktionieren identisch weiter, ein spaeterer Umstieg auf einen vollwertigen Cluster ist ohne Konzeptwechsel moeglich.
# k3s Server-Node installieren (Linux, als root)
curl -sfL https://get.k3s.io | sh -
# Status pruefen
systemctl status k3s
k3s kubectl get nodes
# kubeconfig fuer externen Zugriff (z.B. von deinem Laptop) exportieren
cat /etc/rancher/k3s/k3s.yaml
# Server-IP in der Datei von "127.0.0.1" auf die echte IP des Servers anpassen,
# dann lokal als ~/.kube/config speichern
# Weiteren Node als Agent (Worker) beitreten lassen
# Token vom Server holen:
cat /var/lib/rancher/k3s/server/node-token
# Auf dem neuen Node ausfuehren:
curl -sfL https://get.k3s.io | K3S_URL=https://SERVER-IP:6443 \
K3S_TOKEN=DAS_TOKEN_VOM_SERVER sh -
k3s bringt bereits einen Ingress-Controller (Traefik) und einen einfachen Load Balancer (ServiceLB, vergleichbar mit MetalLB) fertig mit – fuer viele KMU-Szenarien musst du gar nichts mehr nachinstallieren. Falls du lieber NGINX als Ingress-Controller nutzen willst, deaktivierst du Traefik beim Setup:
curl -sfL https://get.k3s.io | sh -s - --disable traefik
Fuer Testumgebungen auf einem Windows- oder Mac-Laptop eignet sich alternativ k3d (k3s in Docker) oder minikube – beide starten einen kompletten Kubernetes-Cluster innerhalb weniger Sekunden lokal in Containern.
# k3d: k3s-Cluster in Docker-Containern (super fuer lokales Testen)
k3d cluster create testcluster --agents 2
kubectl get nodes
k3d cluster delete testcluster
ConfigMaps und Secrets – Konfiguration von Code trennen
# configmap-webapp.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-config
data:
LOG_LEVEL: "info"
API_TIMEOUT_SECONDS: "30"
---
apiVersion: v1
kind: Secret
metadata:
name: webapp-secret
type: Opaque
stringData:
DB_PASSWORD: "wird-in-der-praxis-aus-vault-oder-sealed-secrets-bezogen"
# Einbindung im Deployment:
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: webapp-config
key: LOG_LEVEL
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: webapp-secret
key: DB_PASSWORD
Namespaces und RBAC – Multi-Tenancy im KMU
Namespaces trennen logisch Umgebungen oder Teams innerhalb desselben physischen Clusters:
kubectl create namespace produktion
kubectl create namespace staging
kubectl create namespace team-buchhaltung
# Ressourcenquoten pro Namespace begrenzen (wichtig, damit sich Teams nicht gegenseitig Ressourcen wegnehmen)
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: team-buchhaltung
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
EOF
Mit RBAC (Role-Based Access Control) legst du fest, wer was in welchem Namespace darf – analog zu NTFS-Berechtigungen oder Active-Directory-Gruppen, nur eben fuer Kubernetes-Ressourcen:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: team-buchhaltung
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: buchhaltung-lesezugriff
namespace: team-buchhaltung
subjects:
- kind: User
name: m.mueller@firma-kmu.ch
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Haeufige Fallstricke in der Praxis
- CrashLoopBackOff: Der Container startet, stuerzt ab, wird neu gestartet, stuerzt wieder ab – mit exponentiell laengeren Wartezeiten. Ursache fast immer per
kubectl logsoderkubectl describe podsichtbar (fehlende Umgebungsvariable, falsches Startkommando, Health-Check zu strikt konfiguriert). - ImagePullBackOff: Falscher Image-Name/Tag, private Registry ohne
imagePullSecrets, oder Rate-Limit bei Docker Hub erreicht. - Pending-Pods: Meist zu wenig freie Ressourcen auf den Nodes, oder ein
nodeSelector/taintverhindert die Platzierung.kubectl describe podzeigt im Event-Log den genauen Grund. - Fehlende Ressourcenlimits: Ohne
resources.limitskann ein einzelner fehlerhafter Pod den ganzen Node lahmlegen (Noisy-Neighbour-Problem). In jedem produktiven Manifest Requests und Limits setzen. latest-Tag in Produktion: Ohne festen Versions-Tag weisst du nie genau, welches Image gerade laeuft, und Rollbacks werden unmoeglich. Immer konkrete Versions-Tags verwenden.- Zu wenig Replikas fuer echte Hochverfuegbarkeit: Ein Deployment mit
replicas: 1bietet keinen Ausfallschutz – faellt der Node aus, ist der Dienst kurzzeitig weg, bis der Scheduler den Pod neu platziert.
Weiterlernen
- Kubernetes offizielle Dokumentation – vollstaendige, aktuelle Referenz aller Konzepte und APIs
- Kubernetes Basics Tutorial – interaktives Einsteiger-Tutorial direkt im Browser
- k3s Dokumentation – offizielle Doku zur leichtgewichtigen Distribution
- Helm Dokumentation – Chart-Entwicklung, Templating, Repositories
- Kubernetes Ingress-NGINX Controller – Installation und Konfigurationsoptionen
- CNCF Cloud Native Landscape – Ueberblick ueber das gesamte Cloud-Native-Oekosystem rund um Kubernetes
Verwandte Themen
- Docker Grundlagen – Container-Basics, Voraussetzung fuer Kubernetes
- Container-Sicherheit und Haertung – Sicherheitsaspekte fuer Container-Workloads vertieft
- Virtualisierung Grundlagen – Hypervisoren als Basis fuer Kubernetes-Nodes
- Virtualisierung Hochverfuegbarkeit – HA-Konzepte, die sich mit Kubernetes-Prinzipien vergleichen lassen
- Infrastructure as Code – Vergleich der Tools – Terraform, Ansible & Co. fuer die Cluster-Bereitstellung
- Zero-Trust-Architektur fuer KMU – Netzwerksicherheitskonzepte, die auch fuer Kubernetes-Cluster gelten
Videos
Kommentare
Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.
- Lade Kommentare …