Das passende Training Kubernetes Einführung Training – 3 Tage Praxis mit Live-Cluster
kubectl apply oder edit? Such dir eine Familie aus – wie beim Heiraten

Das passende Training Kubernetes Einführung Training – 3 Tage Praxis mit Live-Cluster

kubectl apply oder edit? Such dir eine Familie aus – wie beim Heiraten

Kurze Antwort: apply. Immer apply.

Pro Ressource entscheidest du dich für genau eine Befehlsfamilie, und das sollte apply sein. Die einzige Ausnahme: Der Hersteller oder das Projekt schreibt dir ausdrücklich etwas anderes vor. Dann machst du, was er sagt.

Ihr Name, sein Name oder Doppelname

Im Training vergleiche ich das mit dem Heiraten. Da musst du dich auch entscheiden: ihr Name, sein Name oder Doppelname. Was nicht geht: montags so heißen und dienstags anders. Das Standesamt findet das nicht lustig. Kubernetes auch nicht, es sagt’s dir nur nicht ins Gesicht.

Die beiden Namen in Kubernetes: apply auf der einen Seite. Du sagst dem Cluster in einem Manifest, was er machen soll, und im Unterschied zu create merkt er sich die Werte in deinen Feldern. Gibst du ihm beim nächsten Mal genau dieselben Werte noch einmal, lächelt er nur müde („unchanged“, haha) und macht genau nix. Auf der anderen Seite create, edit, patch und ihre Kumpels. Da sagst du dem Cluster Schritt für Schritt, was er tun soll. (Die Kubernetes-Doku unterscheidet sogar drei Techniken. Ich mach’s im Training einfacher.)

Glaubst du mir nicht? Dann frag die Kubernetes-Doku. Die liest sich sonst eher wie ein Beipackzettel, aber hier haut sie auf den Tisch: „A Kubernetes object should be managed using only one technique. Mixing and matching techniques for the same object results in undefined behavior."

Undefiniert. Klingt harmlos, heißt aber: Keiner garantiert dir irgendwas.

Was beim Mischen kaputtgeht

Ganz ehrlich: erst mal gar nichts. Kein Fehler, kein rotes Lämpchen. Und genau das ist das Problem.

apply ist ein Buchhalter, und zwar einer von der ganz genauen Sorte. Bei jedem Lauf klebt er eine Kopie deiner Datei als Notizzettel ans Objekt, die Annotation last-applied-configuration. Beim nächsten Lauf macht er zwei Dinge. Was in deiner Datei steht, setzt er durch. Was auf dem Zettel stand und jetzt in der Datei fehlt, fliegt raus. Was weder hier noch da steht, fasst er nicht an.

create, edit und patch sind die Kollegen vom Typ „Ich mach das mal eben schnell". Zettel? Welcher Zettel?

Erst create, dann apply. Läuft ohne Fehler durch, solange das Objekt nicht riesig ist. Der Buchhalter meckert kurz („Zettel fehlt!"), klebt ihn nachträglich dran, deine Änderung gilt. Offiziell unterstützt ist das trotzdem nicht. Denn was per create im Objekt landete und nicht in deiner Datei steht, bleibt. Für immer, oder bis du es in der Datei ausdrücklich auf null setzt. Wer macht das schon? Es stand ja nie auf einem Zettel.

Ein konkretes Beispiel, selbst geprüft mit kind v1.37.0. Erst eine ConfigMap per create mit den Werten a und b:

# aus-create.yaml
apiVersion: v1
kind: ConfigMap
metadata: {name: mix}
data: {a: "von-create", b: "nur-in-create"}

Dann eine apply-Datei, die b gar nicht kennt:

# aus-apply.yaml
apiVersion: v1
kind: ConfigMap
metadata: {name: mix}
data: {a: "von-apply", c: "nur-in-apply"}
kubectl create -f aus-create.yaml
# configmap/mix created
kubectl apply -f aus-apply.yaml
# Warning: resource configmaps/mix is missing the kubectl.kubernetes.io/last-applied-configuration annotation ...
# configmap/mix configured
kubectl get cm mix -o jsonpath='{.data}'
# {"a":"von-apply","b":"nur-in-create","c":"nur-in-apply"}

a ist neu, c ist dazugekommen, und b steht immer noch da, obwohl in deiner Datei kein Wort davon steht. Ein zweites apply mit derselben Datei meldet nur unchanged. Aufgeräumt wird nichts.

Erst apply, dann Handarbeit. Hier wird’s fies. Ich hab das selbst durchgespielt: Deployment per apply angelegt. Dann per Hand mit kubectl set env eine Variable HAND angehängt und mit scale auf 5 Replicas hochgedreht. Danach kommt die nächste Datei per apply rein, da stehen weiter 2 Replicas drin.

Ergebnis: Die Replicas springen zurück auf 2. Die Variable HAND bleibt. Keine Fehlermeldung, keine Rückfrage. Die eine Handarbeit ist weg, die andere klebt fest. Der Cluster entspricht weder deiner Datei noch dem, was du per Hand gemacht hast.

Das ist die Leiche im Keller, die in keinem Git-Diff auftaucht. Oder der Doppelname, den nur die Hälfte der Ämter kennt: Git sagt A, der Cluster sagt B, und keiner weiß, warum.

Selbst geprüft mit kind v1.37.0 (Wegwerf-Cluster)Ergebnis
ConfigMap per create, danach apply mit geändertem WertNur Warnung (Annotation fehlt), dann „configured", neuer Wert gilt
ConfigMap per create mit a, b; apply mit a (neu), ca neu, c neu, b bleibt, auch nach weiterem apply
Deployment per apply (2 Replicas), dann set env HAND=ja und scale auf 5, dann apply mit neuer Datei (weiter 2 Replicas, ohne HAND)2 Replicas, HAND bleibt

Warum gerade apply gewinnt

Meine Faustzahl aus der Praxis: Rund 95 Prozent von dem, was du im Cluster änderst, kriegst du mit apply gelöst. Für so einen kleinen Rest heiratest du nicht zweimal.

Dazu kommt deine Pipeline. Die tippt kein kubectl edit, die kennt nur das Repository. Schraubst du trotzdem per Hand am Cluster, spielst du Tauziehen mit deiner eigenen Automatisierung. Der nächste Lauf bügelt deine Handarbeit weg. Mit klassischem apply allerdings nur zur Hälfte, siehe oben. Gewinnen tust du so oder so nicht. Arbeitest du mit Datei und apply, ziehst du am selben Ende wie sie.

Und create? Nehme ich nur noch mit --dry-run=client, wenn ich mir ein Manifest bauen will, das ich gar nicht an den Server schicke: kubectl create deployment web --image=nginx --dry-run=client -o yaml > web.yaml. Ab da ist es eine Datei, und die läuft über apply. Sonst immer apply.

Die Ausnahme: Der Hersteller sagt was anderes

Manchmal geht das klassische apply schlicht nicht. Der Buchhalter klebt die komplette Konfiguration jedes Objekts auf seinen Zettel, und alle Annotationen eines Objekts zusammen dürfen höchstens 256 KiB groß sein. Bei richtig großen Objekten wird aus dem Notizzettel ein Telefonbuch, und das klebt dir keiner mehr ans Objekt. apply bricht ab. Übrigens auch ganz ohne Mischen.

Selbst geprüft mit kind v1.37.0 (Wegwerf-Cluster)Ergebnis
ConfigMap mit rund 300 KB, nur applyAbbruch: metadata.annotations: Too long: may not be more than 262144 bytes
Dieselbe ConfigMap per create, später applycreate klappt, das spätere apply bricht genauso ab

Das Beispiel aus meinen Workshops? Calico. Mindestens eine Calico-CRD ist genau so ein Brocken. Calico schreibt selbst, dass apply wegen der Größe des CRD-Pakets an Grenzen stoßen kann. Also installiert die Quickstart-Anleitung die CRDs mit kubectl create. Den Tigera-Operator gleich mit. In meinen Workshop-Unterlagen steht dazu dick: create, nicht apply. Für spätere Upgrades gilt wieder, was in der Anleitung des Herstellers steht. Nicht dein spontaner Einfall um halb fünf.

Klingt nach Doppelname? Ist es auch. Aber den hat der Hersteller ausgesucht, nicht du.

Meine Regel bleibt deshalb kurz: apply, außer der Hersteller oder das Projekt schreibt es anders vor. Dann gilt seine Doku, und zwar wörtlich.

Wie du deine Ressourcen von Anfang an sauber deklarativ aufziehst, statt später Leichen aus dem Keller zu holen, üben wir in meinem Training Kubernetes Einführung am Live-Cluster.