Kapitel 4. Erstellen und Ändern grundlegender Workloads
Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com
In diesem Kapitel stellen wir dir Rezepte vor, die dir zeigen, wie du die grundlegenden Kubernetes-Workload-Typen verwalten kannst: Pods und Deployments. Wir zeigen dir, wie du Deployments und Pods über CLI-Befehle und ein YAML-Manifest erstellst und wie du ein Deployment skalieren und aktualisieren kannst.
4.1 Erstellen eines Pods mit kubectl run
Lösung
Verwende den Befehl kubectl run
, einen Generator, der einen Pod im Handumdrehen erstellt. Um zum Beispiel mit einen Pod zu erstellen, der den NGINX Reverse Proxy ausführt, gehst du wie folgt vor:
$ kubectl run nginx --image=nginx $ kubectl get pod/nginx NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 3m55s
Diskussion
Der Befehl kubectl run
kann eine Reihe von Argumenten annehmen, um zusätzliche Parameter der Pods zu konfigurieren. Du kannst zum Beispiel Folgendes tun:
-
Setze Umgebungsvariablen mit
--env
. -
Definiere Containerhäfen mit
--port
. -
Definiere einen Befehl, der mit
--command
ausgeführt werden soll. -
Erstelle automatisch einen zugehörigen Dienst mit
--expose
. -
Teste einen Lauf, ohne etwas mit
--dry-run=client
auszuführen.
Typische Anwendungsfälle sind die folgenden. Um NGINX auf Port 2368 zu starten und einen Dienst zu erstellen, gibst du Folgendes ein:
$ kubectl run nginx --image=nginx --port=2368 --expose
Um MySQL mit dem root-Passwort zu starten, gibst du Folgendes ein:
$ kubectl run mysql --image=mysql --env=MYSQL_ROOT_PASSWORD=root
Um einen busybox
Container zu starten und beim Start den Befehl sleep 3600
auszuführen, gibst du Folgendes ein:
$ kubectl run myshell --image=busybox:1.36 --command -- sh -c "sleep 3600"
Siehe auch kubectl run --help
für weitere Informationen über die verfügbaren Argumente.
4.2 Erstellen einer Bereitstellung mit kubectl create
Lösung
Verwende kubectl create deployment
, um ein Bereitstellungsmanifest im Handumdrehen zu erstellen. Um zum Beispiel eine Bereitstellung zu erstellen, auf der das WordPress Content ManagementSystem läuft, gehe wie folgt vor:
$ kubectl create deployment wordpress --image wordpress:6.3.1 $ kubectl get deployments.apps/wordpress NAME READY UP-TO-DATE AVAILABLE AGE wordpress 1/1 1 1 90s
Diskussion
Der Befehl kubectl create deployment
kann eine Reihe von Argumenten annehmen, um zusätzliche Parameter für die Einsätze zu konfigurieren. Du kannst zum Beispiel Folgendes tun:
-
Definiere Containerhäfen mit
--port
. -
Definiere die Anzahl der Replikate mit
--replicas
. -
Teste einen Lauf, ohne etwas mit
--dry-run=client
auszuführen. -
Stelle das erstellte Manifest mit
--output yaml
zur Verfügung.
Siehe auch kubectl create deployment --help
für weitere Informationen über die verfügbaren Argumente.
4.3 Objekte aus Dateimanifesten erstellen
Lösung
Verwende kubectl apply
wie folgt:
$ kubectl apply -f <manifest>
In Rezept 7.3 siehst du, wie du einen Namensraum mit einem YAML-Manifest erstellst. Dies ist eines der einfachsten Beispiele, da das Manifest sehr kurz ist. Es kann in YAML oder JSON geschrieben werden - zum Beispiel mit einer YAML-Manifestdatei myns.yaml wie folgt:
apiVersion
:
v1
kind
:
Namespace
metadata
:
name
:
myns
Du kannst dieses Objekt damit erstellen:
$ kubectl apply -f myns.yaml
Überprüfe, ob der Namensraum mit diesem erstellt wurde:
$ kubectl get namespaces
Diskussion
Du kannst kubectl apply
auf eine URL statt auf einen Dateinamen in deinem lokalen Dateisystem verweisen. Um zum Beispiel das Frontend für die kanonische Gästebuch-Anwendung zu erstellen, holst du dir die URL der Roh-YAML, die die Anwendung in einem einzigen Manifest definiert, und gibst diese ein:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/examples/ master/guestbook/all-in-one/guestbook-all-in-one.yaml
Überprüfe die Ressourcen, die durch diesen Vorgang erstellt wurden, zum Beispiel mit diesem:
$ kubectl get all
4.4 Ein Pod-Manifest von Grund auf neu schreiben
Lösung
Ein Pod ist ein /api/v1
Objekt, und wie jedes andere Kubernetes-Objekt enthält seine Manifestdatei die folgenden Felder:
-
apiVersion
, die die API-Version angibt -
kind
, die den Typ des Objekts angibt -
metadata
die einige Metadaten über das Objekt liefert -
spec
, die die Objektspezifikation liefert
Das Pod-Manifest enthält eine Reihe von Containern und eine optionale Reihe von Volumes (siehe Kapitel 8). In seiner einfachsten Form, mit einem einzigen Container und keinem Volume, sieht es etwa so aus:
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
oreilly
spec
:
containers
:
-
name
:
oreilly
image
:
nginx:1.25.2
Speichere dieses YAML-Manifest in einer Datei namens oreilly.yaml und verwende dann kubectl
, um es zu erstellen:
$ kubectl apply -f oreilly.yaml
Überprüfe die Ressourcen, die durch diesen Vorgang erstellt wurden, zum Beispiel mit diesem:
$ kubectl get all
Diskussion
Die API-Spezifikation eines Pods ist viel umfangreicher als das, was in der Lösung gezeigt wird, die den grundlegendsten funktionierenden Pod darstellt. Ein Pod kann zum Beispiel mehrere Container enthalten, wie hier gezeigt:
apiVersion
:
v1
kind
:
Pod
metadata
:
name
:
oreilly
spec
:
containers
:
-
name
:
oreilly
image
:
nginx:1.25.2
-
name
:
safari
image
:
redis:7.2.0
Ein Pod kann auch Volume-Definitionen enthalten, um Daten in die Container zu laden (siehe Rezept 8.1), sowie Sonden, um den Zustand der containerisierten Anwendung zu überprüfen (siehe Rezepte 11.2 und 11.3).
Eine Beschreibung der Überlegungen, die hinter vielen der Spezifikationsfelder stehen, und ein Link zur vollständigen API-Objektspezifikation sind in der Dokumentation zu finden.
Hinweis
Erstelle niemals einen Pod allein, es sei denn, es gibt ganz besondere Gründe dafür. Verwende ein Deployment
Objekt (siehe Rezept 4.5), um Pods zu überwachen - es überwacht die Pods über ein anderes Objekt namens ReplicaSet
.
4.5 Starten eines Einsatzes mit Hilfe eines Manifests
Lösung
Schreibe ein Bereitstellungsmanifest. Für die Grundlagen, siehe auch Rezept 4.4.
Nehmen wir an, du hast eine Manifestdatei namens fancyapp.yaml mit dem folgenden Inhalt:
apiVersion
:
apps/v1
kind
:
Deployment
metadata
:
name
:
fancyapp
spec
:
replicas
:
5
selector
:
matchLabels
:
app
:
fancy
template
:
metadata
:
labels
:
app
:
fancy
env
:
development
spec
:
containers
:
-
name
:
sise
image
:
gcr.io/google-samples/hello-app:2.0
ports
:
-
containerPort
:
8080
env
:
-
name
:
SIMPLE_SERVICE_VERSION
value
:
"2.0"
Wie du siehst, gibt es ein paar Dinge, die du beim Starten der App explizit tun solltest:
-
Lege die Anzahl der Pods (
replicas
), also der identischen Kopien, fest, die gestartet und überwacht werden sollen. -
Beschrifte sie, z.B. mit
env=development
(siehe auch Rezepte 7.5 und 7.6). -
Setze Umgebungsvariablen, wie z.B.
SIMPLE_SERVICE_VERSION
.
Schauen wir uns nun an, was der Einsatz mit sich bringt:
$ kubectl apply -f fancyapp.yaml deployment.apps/fancyapp created $ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE fancyapp 5/5 5 5 57s $ kubectl get replicasets NAME DESIRED CURRENT READY AGE fancyapp-1223770997 5 5 0 59s $ kubectl get pods -l app=fancy NAME READY STATUS RESTARTS AGE fancyapp-74c6f7cfd7-98d97 1/1 Running 0 115s fancyapp-74c6f7cfd7-9gm2l 1/1 Running 0 115s fancyapp-74c6f7cfd7-kggsx 1/1 Running 0 115s fancyapp-74c6f7cfd7-xfs6v 1/1 Running 0 115s fancyapp-74c6f7cfd7-xntk2 1/1 Running 0 115s
Warnung
Wenn du ein Deployment und damit auch die Replikat-Sets und Pods, die es überwacht, loswerden willst, führst du einen Befehl wie kubectl delete deploy/fancyapp
aus. Versuche nicht, einzelne Pods zu löschen, denn sie werden von dem Einsatz neu erstellt. Das ist etwas, das Anfänger oft verwirrt.
Mit Deployments kannst du die App skalieren (siehe Rezept 9.1), eine neue Version ausrollen oder eine ReplicaSet
auf eine frühere Version zurücksetzen. Sie eignen sich im Allgemeinen gut für zustandslose Anwendungen, die Pods mit identischen Eigenschaften benötigen.
Diskussion
Ein Deployment ist ein Supervisor für Pods und Replikat-Sets (RSs), mit dem du genau steuern kannst, wie und wann eine neue Pod-Version ausgerollt oder auf einen früheren Zustand zurückgesetzt wird. Die RS und Pods, die ein Deployment überwacht, sind in der Regel für dich uninteressant, es sei denn, du musst zum Beispiel einen Pod debuggen (siehe Rezept 12.5). Abbildung 4-1 veranschaulicht, wie du zwischen den Revisionen eines Deployments hin und her wechseln kannst.
Um das Manifest für eine Bereitstellung zu erstellen, kannst du den Befehl kubectl create
und die Option --dry-run=client
verwenden. Damit kannst du das Manifest im YAML- oder JSON-Format erstellen und zur späteren Verwendung speichern. Um zum Beispiel das Manifest eines Einsatzes namens fancy-app
mit dem Container-Image nginx
zu erstellen, gibst du den folgenden Befehl ein:
$ kubectl create deployment fancyapp --image nginx:1.25.2 -o yaml \ --dry-run=client kind: Deployment apiVersion: apps/v1 metadata: name: fancyapp creationTimestamp: labels: app: fancyapp ...
Siehe auch
-
Kubernetes
Deployment
Dokumentation
4.6 Aktualisieren eines Einsatzes
Lösung
Aktualisiere dein Deployment und lass die Standard-Update-Strategie RollingUpdate
den Rollout automatisch durchführen.
Wenn du z.B. ein neues Container-Image erstellst und das darauf basierende Deployment aktualisieren möchtest, kannst du wie folgt vorgehen:
$ kubectl create deployment myapp --image=gcr.io/google-samples/hello-app:1.0 deployment.apps/myapp created $ kubectl set image deployment/myapp \ hello-app=gcr.io/google-samples/hello-app:2.0 deployment.apps/myapp image updated $ kubectl rollout status deployment myapp deployment "myapp" successfully rolled out $ kubectl rollout history deployment myapp deployment.apps/myapp REVISION CHANGE-CAUSE 1 <none> 2 <none>
Du hast jetzt erfolgreich eine neue Version deines Einsatzes ausgerollt, bei der sich nur das verwendete Container-Image geändert hat. Alle anderen Eigenschaften der Bereitstellung, wie z.B. die Anzahl der Replikate, bleiben unverändert. Was aber, wenn du andere Aspekte des Einsatzes aktualisieren willst, wie z.B. die Umgebungsvariablen ändern? Du kannst eine Reihe von kubectl
Befehlen verwenden, um die Bereitstellung zu aktualisieren. Um zum Beispiel eine Portdefinition zur aktuellen Bereitstellung hinzuzufügen, kannst du kubectl edit
verwenden:
$ kubectl edit deploy myapp
Dieser Befehl öffnet das aktuelle Deployment in deinem Standard-Editor oder, wenn er gesetzt und exportiert wurde, in dem durch die Umgebungsvariable KUBE_EDITOR
festgelegten Editor .
Angenommen, du möchtest die folgende Portdefinition hinzufügen (siehe Abbildung 4-2 für die vollständige Datei):
...
ports
:
-
containerPort
:
9876
...
Das Ergebnis des Bearbeitungsvorgangs (in diesem Fall mit KUBE_EDITOR
auf vi
) ist in Abbildung 4-2 dargestellt.
Sobald du den Editor speicherst und beendest, startet Kubernetes ein neues Deployment, jetzt mit dem definierten Port. Lass uns das überprüfen:
$ kubectl rollout history deployment myapp deployments "sise" REVISION CHANGE-CAUSE 1 <none> 2 <none> 3 <none>
In der Tat sehen wir, dass Revision 3 mit den Änderungen, die wir mit kubectl edit
eingeführt haben, ausgerollt wurde. Die Spalte CHANGE-CAUSE
ist jedoch leer. Du kannst eine Änderungsursache für eine Revision angeben, indem du einen speziellen Vermerk verwendest. Im Folgenden findest du ein Beispiel für die Angabe einer Änderungsursache für die letzte Revision:
$ kubectl annotate deployment/myapp \ kubernetes.io/change-cause="Added port definition." deployment.apps/myapp annotate
Wie bereits erwähnt, gibt es weitere kubectl
Befehle, die du verwenden kannst, um deine Bereitstellung zu aktualisieren:
-
Mit
kubectl apply
kannst du ein Deployment aus einer Manifestdatei aktualisieren (oder erstellen, wenn es noch nicht existiert) - zum Beispielkubectl apply -f simpleservice.yaml
. -
Verwende
kubectl replace
, um eine Bereitstellung aus einer Manifestdatei zu ersetzen - zum Beispielkubectl replace -f simpleservice.yaml
. Beachte, dass im Gegensatz zuapply
die Bereitstellung bereits existieren muss, umreplace
zu verwenden. -
Verwende
kubectl patch
, um einen bestimmten Schlüssel zu aktualisieren - zum Beispiel:kubectl patch deployment myapp -p '{"spec": {"template": {"spec": {"containers": [{"name": "sise", "image": "gcr.io/google-samples/hello-app:2.0"}]}}}}'
Was ist, wenn du einen Fehler machst oder Probleme mit der neuen Version des Deployments auftreten? Zum Glück ist es in Kubernetes ganz einfach, mit dem Befehl kubectl rollout undo
zu einem bekannten guten Zustand zurückzukehren. Angenommen, die letzte Bearbeitung war ein Fehler und du willst auf Revision 2 zurückgehen. Das kannst du mit dem folgenden Befehl tun:
$ kubectl rollout undo deployment myapp ‐‐to‐revision 2
Du kannst dann mit kubectl get deploy/myapp -o yaml
überprüfen, ob die Portdefinition entfernt wurde.
Hinweis
Der Rollout eines Deployments wird nur dann ausgelöst, wenn Teile der Pod-Vorlage (d.h. Schlüssel unter .spec.template
) geändert werden, z.B. Umgebungsvariablen, Ports oder das Container-Image. Änderungen an Aspekten des Deployments, wie z. B. der Anzahl der Replikate, lösen kein neues Deployment aus.
4.7 Einen Batch-Auftrag ausführen
Lösung
Verwende eine Kubernetes Job
um den/die Pods zu starten und zu überwachen, die den Batch-Prozess durchführen.
Definiere zunächst das Kubernetes-Manifest für den Auftrag in einer Datei namens counter-batch-job.yaml:
apiVersion
:
batch/v1
kind
:
Job
metadata
:
name
:
counter
spec
:
template
:
metadata
:
name
:
counter
spec
:
containers
:
-
name
:
counter
image
:
busybox:1.36
command
:
-
"sh"
-
"-c"
-
"for
i
in
1
2
3
;
do
echo
$i
;
done"
restartPolicy
:
Never
Dann starte den Auftrag und wirf einen Blick auf seinen Status: :
$ kubectl apply -f counter-batch-job.yaml job.batch/counter created $ kubectl get jobs NAME COMPLETIONS DURATION AGE counter 1/1 7s 12s $ kubectl describe jobs/counter Name: counter Namespace: default Selector: controller-uid=2d21031e-7263-4ff1-becd-48406393edd5 Labels: controller-uid=2d21031e-7263-4ff1-becd-48406393edd5 job-name=counter Annotations: batch.kubernetes.io/job-tracking: Parallelism: 1 Completions: 1 Completion Mode: NonIndexed Start Time: Mon, 03 Apr 2023 18:19:13 +0530 Completed At: Mon, 03 Apr 2023 18:19:20 +0530 Duration: 7s Pods Statuses: 0 Active (0 Ready) / 1 Succeeded / 0 Failed Pod Template: Labels: controller-uid=2d21031e-7263-4ff1-becd-48406393edd5 job-name=counter Containers: counter: Image: busybox:1.36 Port: <none> Host Port: <none> Command: sh -c for i in 1 2 3 ; do echo $i ; done Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 30s job-controller Created pod: counter-5c8s5 Normal Completed 23s job-controller Job completed
Zum Schluss willst du überprüfen, ob er die Aufgabe tatsächlich ausgeführt hat (Zählen von 1 bis 3):
$ kubectl logs jobs/counter 1 2 3
Wie du sehen kannst, hat der counter
Job tatsächlich wie erwartet gezählt.
Diskussion
Nachdem ein Auftrag erfolgreich ausgeführt wurde, befindet sich der Pod, der durch den Auftrag erstellt wurde, im Status Abgeschlossen. Du kannst den Auftrag löschen, wenn du ihn nicht mehr brauchst. Dadurch werden die Pods, die er erstellt hat, aufgeräumt:
$ kubectl delete jobs/counter
Du kannst die Ausführung eines Auftrags auch vorübergehend aussetzen und später wieder aufnehmen. Wenn du einen Auftrag unterbrichst, werden auch die Pods aufgeräumt, die er erstellt hat:
$ kubectl patch jobs/counter --type=strategic --patch '{"spec":{"suspend":true}}'
Um den Auftrag fortzusetzen, drehst du einfach die Flagge suspend
um:
$ kubectl patch jobs/counter --type=strategic \ --patch '{"spec":{"suspend":false}}'
4.8 Einen Task auf einem Zeitplan innerhalb eines Pods ausführen
Lösung
Verwende die CronJob
Objekte von Kubernetes. Das CronJob
Objekt ist eine Ableitung des allgemeineren Job
Objekts (siehe Rezept 4.7).
Du kannst einen Auftrag regelmäßig planen, indem du ein Manifest schreibst, das dem hier gezeigten ähnelt. Im spec
siehst du einen schedule
Abschnitt, der dem crontab Format folgt. Du kannst auch einige Makros verwenden, wie z.B. @hourly
, @daily
, @weekly
, @monthly
, und @yearly
. Der Abschnitt template
beschreibt den Pod, der ausgeführt wird, und den Befehl, der ausgeführt wird (dieser gibt jede Stunde das aktuelle Datum und die Uhrzeit an stdout
aus):
apiVersion
:
batch/v1
kind
:
CronJob
metadata
:
name
:
hourly-date
spec
:
schedule
:
"0
*
*
*
*"
jobTemplate
:
spec
:
template
:
spec
:
containers
:
-
name
:
date
image
:
busybox:1.36
command
:
-
"sh"
-
"-c"
-
"date"
restartPolicy
:
OnFailure
Diskussion
Genau wie ein Auftrag kann auch ein Cron-Job ausgesetzt und wieder aufgenommen werden, indem du das Flag suspend
umdrehst. Zum Beispiel:
$ kubectl patch cronjob.batch/hourly-date --type=strategic \ --patch '{"spec":{"suspend":true}}'
Wenn du den Cron-Job nicht mehr brauchst, lösche ihn, um die Pods, die er erstellt hat, aufzuräumen:
$ kubectl delete cronjob.batch/hourly-date
Siehe auch
4.9 Ausführen von Infrastruktur-Daemons pro Knoten
Lösung
Verwende eine DaemonSet
, um den Daemon-Prozess zu starten und zu überwachen. Um zum Beispiel einen Fluentd-Agenten auf jedem Knoten in deinem Cluster zu starten, erstelle eine Datei namens fluentd-daemonset.yaml mit folgendem Inhalt:
kind
:
DaemonSet
apiVersion
:
apps/v1
metadata
:
name
:
fluentd
spec
:
selector
:
matchLabels
:
app
:
fluentd
template
:
metadata
:
labels
:
app
:
fluentd
name
:
fluentd
spec
:
containers
:
-
name
:
fluentd
image
:
gcr.io/google_containers/fluentd-elasticsearch:1.3
env
:
-
name
:
FLUENTD_ARGS
value
:
volumeMounts
:
-
name
:
varlog
mountPath
:
/varlog
-
name
:
containers
mountPath
:
/var/lib/docker/containers
volumes
:
-
hostPath
:
path
:
/var/log
name
:
varlog
-
hostPath
:
path
:
/var/lib/docker/containers
name
:
containers
Starte nun die DaemonSet
, etwa so:
$ kubectl apply -f fluentd-daemonset.yaml daemonset.apps/fluentd created $ kubectl get ds NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE fluentd 1 1 1 1 1 <none> 60s $ kubectl describe ds/fluentd Name: fluentd Selector: app=fluentd Node-Selector: <none> Labels: <none> Annotations: deprecated.daemonset.template.generation: 1 Desired Number of Nodes Scheduled: 1 Current Number of Nodes Scheduled: 1 Number of Nodes Scheduled with Up-to-date Pods: 1 Number of Nodes Scheduled with Available Pods: 1 Number of Nodes Misscheduled: 0 Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed ...
Diskussion
Da der Befehl auf Minikube ausgeführt wird, siehst du in der vorangegangenen Ausgabe nur einen laufenden Pod, da es nur einen Knoten in diesem Setup gibt. Hättest du 15 Knoten in deinem Cluster, würdest du insgesamt 15 Pods haben und 1 Pod pro Knoten laufen lassen. Du kannst den Daemon auch auf bestimmte Knoten beschränken, indem du den Abschnitt nodeSelector
im spec
des Manifests DaemonSet
verwendest.
Get Kubernetes Kochbuch, 2. Auflage now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.