Was Sie über Docker wissen müssen

Was Sie über Docker wissen müssen

Im vorherigen Artikel habe ich eine detaillierte Einführung in das Konzept der Pods gegeben, die im Kubernetes-Projekt das wichtigste sind. Im heutigen Artikel werde ich weitere Details zu Pod-Objekten teilen.

Pods vs. Virtuelle Maschinen

Inzwischen sollte Ihnen klar sein, dass im Kubernetes-Projekt der Pod und nicht der Container die kleinste Orchestrierungseinheit ist. Dieses Design spiegelt sich in den API-Objekten wider, bei denen der Container nur ein reguläres Feld innerhalb der Pod-Eigenschaften ist. Natürlich stellt sich die Frage: Welche Attribute gehören zum Pod-Objekt und welche zum Container?

Der Pod spielt die Rolle einer „virtuellen Maschine“ in traditionellen Bereitstellungsumgebungen. Dieses Design soll den Übergang von traditionellen Umgebungen (virtuelle Maschinen) zu Kubernetes (Container-Umgebungen) erleichtern.

Wenn wir den Pod als die „Maschine“ in einer traditionellen Umgebung und den Container als das „Benutzerprogramm“ betrachten, das auf dieser „Maschine“ läuft, dann werden viele Aspekte des Pod-Objekt-Designs viel verständlicher.

Beispielsweise liegen Attribute zu Scheduling, Netzwerk, Speicher und Sicherheit grundsätzlich auf Pod-Ebene. Das gemeinsame Merkmal dieser Attribute ist, dass sie die „Maschine“ als Ganzes beschreiben, nicht die darin laufenden „Programme“.

Zum Beispiel die Konfiguration der Netzwerkkarte der „Maschine“ (d.h. die Netzwerkdefinition des Pods), die Konfiguration der Festplatte der „Maschine“ (d.h. die Speicherdefinition des Pods) und die Konfiguration der Firewall der „Maschine“ (d.h. die Sicherheitsdefinition des Pods). Ganz zu schweigen davon, auf welchem Server diese „Maschine“ läuft (d.h. das Scheduling des Pods).

Kubernetes YAML

In Kubernetes definieren wir Pod-Ressourcen über deklarative Dateien.

NodeSelector: Dies ist ein Feld, das es Benutzern ermöglicht, einen Pod an einen Node zu binden, wie unten gezeigt:

apiVersion: v1
kind: Pod
...
spec:
  nodeSelector:
    disktype: ssd

Eine solche Konfiguration bedeutet, dass dieser Pod nur auf einem Node mit dem Label „disktype: ssd“ ausgeführt werden kann; andernfalls schlägt das Scheduling fehl.

NodeName: Sobald dieses Feld eines Pods zugewiesen ist, geht das Kubernetes-Projekt davon aus, dass der Pod eingeplant wurde, und das Ergebnis des Schedulings ist der zugewiesene Node-Name. Daher wird dieses Feld normalerweise vom Scheduler gesetzt, aber Benutzer können es auch setzen, um den Scheduler zu „tricksen“, obwohl diese Praxis normalerweise nur beim Testen oder Debuggen verwendet wird.

HostAliases: Definiert den Inhalt der hosts-Datei des Pods (z.B. /etc/hosts), wie unten gezeigt:

apiVersion: v1
kind: Pod
...
spec:
  hostAliases:
  - ip: "10.1.2.3"
    hostnames:
    - "foo.remote"
    - "bar.remote"
...

Es ist zu beachten, dass Sie im Kubernetes-Projekt, wenn Sie den Inhalt der hosts-Datei festlegen möchten, dies unbedingt auf diese Weise tun müssen. Andernfalls überschreibt kubelet die geänderten Inhalte automatisch, wenn Sie die hosts-Datei direkt ändern und der Pod gelöscht und neu erstellt wird.

Zusätzlich zu den oben genannten „maschinenbezogenen“ Konfigurationen werden Sie möglicherweise feststellen, dass alle Attribute, die sich auf den Linux-Namespace des Containers beziehen, ebenfalls auf Pod-Ebene liegen. Dies ist ebenfalls leicht zu verstehen: Das Design des Pods ermöglicht es den darin enthaltenen Containern, so viele Linux-Namespaces wie möglich zu teilen, wobei nur die notwendigen Isolations- und Einschränkungsfähigkeiten erhalten bleiben. Auf diese Weise ähnelt der vom Pod simulierte Effekt stark der Beziehung zwischen Programmen in einer virtuellen Maschine.

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]

Dies ist eine Pod-YAML-Datei aus der offiziellen Kubernetes-Dokumentation. Sie ist tatsächlich sehr einfach, definiert lediglich einen Container mit dem nginx-Image. Im containers-Bereich dieser YAML-Datei sehen Sie jedoch, dass der Container die Parameter postStart und preStop hat.

Was bedeutet das?

Beginnen wir mit postStart. Dies bezieht sich auf eine Operation, die unmittelbar nach dem Start des Containers ausgeführt wird. Es sollte klar sein, dass die von postStart definierte Operation nach dem ENTRYPOINT des Docker-Containers ausgeführt wird, aber eine strikte Reihenfolge wird nicht garantiert. Das heißt, wenn postStart startet, ist der ENTRYPOINT möglicherweise noch nicht beendet.

Wenn postStart natürlich ein Timeout oder einen Fehler verursacht, meldet Kubernetes eine Fehlermeldung, die angibt, dass der Container in den Events dieses Pods nicht gestartet werden konnte, was dazu führt, dass der Pod ebenfalls in einem fehlerhaften Zustand ist.

Ähnlich tritt der Zeitpunkt von preStop ein, bevor der Container beendet wird (z.B. wenn er ein SIGKILL-Signal erhält). Es ist wichtig zu klären, dass die Ausführung der preStop-Operation synchron ist. Daher blockiert sie den aktuellen Container-Beendigungsprozess, bis die definierte Operation abgeschlossen ist, was sich von postStart unterscheidet.

In diesem Beispiel schreibt der Container also nach erfolgreichem Start eine „Begrüßungsnachricht“ in /usr/share/message (d.h. die von postStart definierte Operation). Und bevor dieser Container gelöscht wird, rufen wir zuerst den nginx-Exit-Befehl auf (d.h. die von preStop definierte Operation), um so ein „sanftes Herunterfahren“ des Containers zu erreichen.

Nachdem Sie sich mit den Hauptfeldern des Pods und seines Container-Abschnitts vertraut gemacht haben, werde ich den Lebenszyklus eines solchen Pod-Objekts in Kubernetes teilen.

Die Änderungen im Pod-Lebenszyklus spiegeln sich hauptsächlich im Status-Teil des Pod-API-Objekts wider, das neben Metadata und Spec das dritte wichtige Feld ist. pod.status.phase gibt den aktuellen Zustand des Pods an, mit den folgenden möglichen Bedingungen:

  1. Pending. Dieser Status bedeutet, dass die YAML-Datei des Pods an Kubernetes übergeben wurde, das API-Objekt erstellt und in Etcd gespeichert wurde. Einige Container in diesem Pod können jedoch aus irgendeinem Grund nicht reibungslos erstellt werden. Zum Beispiel ein Scheduling-Fehler.

  2. Running. In diesem Zustand wurde der Pod erfolgreich eingeplant und an einen bestimmten Node gebunden. Alle darin enthaltenen Container wurden erfolgreich erstellt, und mindestens einer läuft derzeit.

  3. Succeeded. Dieser Zustand bedeutet, dass alle Container im Pod vollständig ausgeführt wurden und beendet sind. Diese Situation tritt am häufigsten bei der Ausführung von einmaligen Aufgaben auf.

  4. Failed. In diesem Zustand wurde mindestens ein Container im Pod in einem abnormalen Zustand beendet (ein Rückgabecode ungleich null). Das Auftreten dieses Zustands bedeutet, dass Sie herausfinden müssen, wie Sie die Anwendung im Container debuggen können, z.B. durch Überprüfen der Events und Protokolle des Pods.

  5. Unknown. Dies ist ein abnormaler Zustand, der anzeigt, dass der Status des Pods nicht kontinuierlich von kubelet an kube-apiserver gemeldet werden kann, was wahrscheinlich auf ein Kommunikationsproblem zwischen dem Master und dem Kubelet zurückzuführen ist.

Darüber hinaus kann das Statusfeld des Pod-Objekts weiter in eine Reihe von Conditions unterteilt werden. Diese detaillierten Statuswerte umfassen: PodScheduled, Ready, Initialized und Unschedulable. Sie werden hauptsächlich verwendet, um die spezifischen Gründe für den aktuellen Status zu beschreiben.

Wenn der aktuelle Status des Pods beispielsweise Pending ist und die entsprechende Condition Unschedulable ist, bedeutet dies, dass ein Problem mit seinem Scheduling vorliegt.

Unter ihnen ist der Unterstatus Ready besonders beachtenswert: Er bedeutet, dass der Pod nicht nur normal gestartet ist (im Running-Zustand), sondern auch bereit ist, Dienste extern bereitzustellen. Es gibt einen Unterschied zwischen diesen beiden (Running und Ready), daher sollten Sie vielleicht sorgfältig darüber nachdenken.

Diese Statusmeldungen des Pods sind ein wichtiges Kriterium für die Beurteilung des Betriebszustands der Anwendung, insbesondere wenn der Pod in einen Nicht-„Running“-Zustand gerät. Sie müssen schnell reagieren können, die Verfolgung und Lokalisierung basierend auf der dargestellten abnormalen Situation beginnen, anstatt hektisch die Dokumentation zu konsultieren.

Zusammenfassung

In diesem Artikel habe ich das Pod-API-Objekt detailliert erläutert, die Kernverwendungsmethoden von Pods vorgestellt und die Gemeinsamkeiten und Unterschiede zwischen Pods und Containern in Bezug auf Felder analysiert. Ich hoffe, diese Erklärungen helfen Ihnen, die Kernfelder in der Pod-YAML und ihre präzise Bedeutung besser zu verstehen und zu merken.

Tatsächlich ist das Pod-API-Objekt das zentralste Konzept im gesamten Kubernetes-System und wird auch in den Controllern verwendet, die ich später erklären werde.