Knotendienste mit Kubernetes-DaemonSets bereitstellen

KubernetesBeginner
Jetzt üben

Einführung

Manche Software sollte auf jedem geeigneten Knoten genau einmal ausgeführt werden und nicht anhand einer festen Anzahl von Replikaten. Log-Sammler, Monitoring-Agenten und Netzwerkkomponenten verwenden für diese knotenorientierte Platzierung häufig DaemonSets.

Du versiehst den vorbereiteten Knoten mit einem Label, stellst einen Knoten-Reporter bereit, verfolgst dessen Besitzverhältnisse, änderst die Eignung des Knotens und führst ein rollierendes Update durch. In der Umgebung mit nur einem Knoten lässt sich die Platzierungsregel besonders leicht beobachten, während das Verhalten des Controllers dem größerer Cluster entspricht.

Die zentrale Frage lautet in diesem Lab nicht: „Wie viele Replikate sollen ausgeführt werden?“, sondern: „Welche Knoten sind geeignet?“ Ein DaemonSet beantwortet diese Frage fortlaufend und erstellt auf jedem passenden Knoten genau einen Pod. In dieser Umgebung gibt es nur einen Knoten. Daher führt jede Änderung der Eignung eindeutig zu einem Ergebnis von eins zu null oder von null zu eins.

Einen geeigneten Knoten kennzeichnen

In diesem Schritt fügst du dem Knoten ein zweckgebundenes Label hinzu. Labels beschreiben Eigenschaften von Knoten, nach denen Controller auswählen können.

Zeige zunächst den Knoten und seine vorhandenen Labels an. Die Ausgabe ist sehr breit. Du musst sie daher nicht auswendig lernen, sondern lediglich erkennen, dass Labels Schlüssel-Wert-Informationen sind, die am Node-Objekt hinterlegt werden.

cd /home/labex/project/daemonset-workloads
kubectl get nodes --show-labels

Füge nun das neue Label hinzu. Die Option --overwrite ist hier nicht erforderlich, da die Einrichtung alte Werte entfernt hat. kubectl label weist dich jedoch darauf hin, falls bereits ein widersprüchlicher Wert vorhanden ist:

kubectl label node labex-v135 practice-tier=operations
kubectl get node labex-v135 -L practice-tier

-L practice-tier fügt das Label als Spalte in der Tabelle hinzu. Der Knoten weist sich nun als geeignet für den Übungs-Agenten für Betriebsaufgaben aus.

Der zweite Befehl liefert ein übersichtliches Ergebnis anstelle der sehr langen Ausgabezeile von --show-labels:

NAME         STATUS   ROLES           VERSION   PRACTICE-TIER
labex-v135   Ready    control-plane   v1.35.5   operations

PRACTICE-TIER=operations ist der benötigte Nachweis. Das Label führt allein noch nichts aus. Es wird erst relevant, wenn ein Workload im nächsten Schritt danach auswählt.

Ein DaemonSet bereitstellen

In diesem Schritt erstellst du ein DaemonSet, das auf Knoten mit dem neuen Label abzielt.

Lies das Manifest zunächst als drei zusammenhängende Entscheidungen, bevor du es eingibst. Der Selektor und das Pod-Label verwenden beide app: node-reporter, sodass der Controller seine Pods erkennen kann. nodeSelector beschränkt die Eignung anschließend auf Knoten mit dem Label practice-tier=operations. Schließlich übernimmt die Downward API den Wert von spec.nodeName des ausgewählten Pods als NODE_NAME in den Container.

Die Schleife hält den Demo-Agenten am Leben. Ein echtes DaemonSet könnte stattdessen einen Log-Sammler oder Monitoring-Agenten ausführen.

cat <<'EOF' > node-reporter.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-reporter
  namespace: practice-daemon
spec:
  selector:
    matchLabels:
      app: node-reporter
  template:
    metadata:
      labels:
        app: node-reporter
    spec:
      nodeSelector:
        practice-tier: operations
      containers:
        - name: reporter
          image: busybox:1.36
          imagePullPolicy: IfNotPresent
          command: ["sh", "-c", "while true; do echo node=${NODE_NAME} version=v1; sleep 15; done"]
          env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
EOF

Erstelle den Namespace, wende die Datei an und warte, bis der Rollout des DaemonSets abgeschlossen ist:

kubectl create namespace practice-daemon
kubectl apply -f node-reporter.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl get daemonset,pods -n practice-daemon -o wide

Die Downward-API-Referenz fieldRef stellt den Namen des eingeplanten Knotens bereit, ohne ihn fest im Manifest zu hinterlegen. In diesem Cluster mit nur einem Knoten sollten die gewünschten, aktuellen und bereiten Anzahlen jeweils eins betragen.

Der Pod-Name enthält ein automatisch erzeugtes Suffix. In der Spalte NODE sollte jedoch labex-v135 stehen. Das ist ein direkter Beleg dafür, dass die Eignungsregel und das Ergebnis der Einplanung übereinstimmen.

Im Testcluster mit nur einem Knoten sahen die wichtigen Spalten so aus:

NAME            DESIRED   CURRENT   READY   NODE SELECTOR
node-reporter   1         1         1       practice-tier=operations

NAME                  READY   STATUS    NODE
node-reporter-...      1/1     Running   labex-v135

Lies die erste Zeile von links nach rechts: Ein Knoten entspricht dem Selektor, ein Pod existiert und dieser Pod ist bereit. In einem größeren Cluster würden diese Werte mit der Anzahl der geeigneten Knoten wachsen.

Eignung und Besitzverhältnisse beobachten

In diesem Schritt weist du nach, dass die Anzahl der Pods eines DaemonSets von der Eignung der Knoten und nicht von einem Feld für Replikate gesteuert wird.

Erfasse zunächst einen funktionierenden Ausgangszustand. Die benutzerdefinierten Spalten verknüpfen den automatisch erzeugten Pod mit dem DaemonSet. Die Logs belegen außerdem, dass die Downward API den Knotennamen bereitgestellt hat:

kubectl get pods -n practice-daemon -l app=node-reporter -o custom-columns='POD:.metadata.name,NODE:.spec.nodeName,OWNER:.metadata.ownerReferences[0].kind,READY:.status.containerStatuses[0].ready'
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

Die Tabelle zu den Besitzverhältnissen und die Logs sollten ungefähr so aussehen:

POD                   NODE         OWNER       READY
node-reporter-...     labex-v135   DaemonSet   true
node=labex-v135 version=v1

Das Feld OWNER belegt, dass dieser Pod von einem Controller verwaltet wird. Das Log zeigt, dass NODE_NAME aus dem tatsächlichen spec.nodeName des Pods stammt und nicht fest codiert wurde.

Entferne das Label vorübergehend und beobachte, wie der Pod verschwindet:

kubectl label node labex-v135 practice-tier-
kubectl get daemonset node-reporter -n practice-daemon
kubectl wait --for=delete pod -n practice-daemon -l app=node-reporter --timeout=60s

Ein abschließendes - entfernt einen Label-Schlüssel. Stelle anschließend die Eignung wieder her und warte, bis der Controller einen Ersatz-Pod erstellt:

Nach dem Entfernen des Labels meldet das DaemonSet kurzzeitig folgende stabile Beziehung:

NAME            DESIRED   CURRENT   READY
node-reporter   0         0         0

Das ist eine korrekte Reaktion auf die geänderte Eignung und kein Fehler. Derzeit entspricht kein Knoten dem nodeSelector des DaemonSets. Daher beträgt die korrekte gewünschte Anzahl null.

kubectl label node labex-v135 practice-tier=operations
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s

Vergleiche den Pod-Namen vor und nach der Label-Änderung. Der Ersatz-Pod besitzt eine neue Identität, während der Name des DaemonSets und das gewünschte Verhalten unverändert bleiben. Hier zeigt sich die Abstimmung des tatsächlichen Zustands auf den gewünschten Zustand.

Ein Update des DaemonSets ausrollen

In diesem Schritt aktualisierst du das gespeicherte Manifest und beobachtest, wie das DaemonSet den Knoten-Agenten ersetzt. Wenn Datei und aktives Objekt übereinstimmen, lässt sich der gewünschte Zustand zuverlässig reproduzieren.

Erstelle zunächst mit cp eine Arbeitskopie. Verwende anschließend dasselbe gezielte Muster zur Textbearbeitung, das in Kubernetes für Einsteiger eingeführt wurde: sed -i 's/old/new/' file ersetzt passende Textstellen direkt in der Datei, während grep -n die gefundene Zeile zusammen mit ihrer Zeilennummer ausgibt. So kannst du das Ergebnis vor der Anwendung prüfen.

cp node-reporter.yaml node-reporter-v2.yaml
sed -i 's/version=v1/version=v2/' node-reporter-v2.yaml
grep -n 'version=' node-reporter-v2.yaml
kubectl apply -f node-reporter-v2.yaml
kubectl rollout status daemonset/node-reporter -n practice-daemon --timeout=60s
kubectl rollout history daemonset/node-reporter -n practice-daemon
kubectl logs -n practice-daemon -l app=node-reporter --tail=3

Die kopierte Datei bewahrt das ursprüngliche v1-Beispiel zum Vergleich. Die einmalige Ersetzung ändert nur den Versions-Text im Container-Befehl. Beim Anwenden der aktualisierten Datei ändert sich die Pod-Vorlage, wodurch eine neue Controller-Revision und ein Ersatz-Pod erstellt werden. Die Logs sollten nun version=v2 enthalten.

rollout history bestätigt, dass Kubernetes eine neue Revision aufgezeichnet hat. DaemonSets unterstützen somit kontrollierte Aktualisierungen von Vorlagen ähnlich wie Deployments. Der Austausch richtet sich jedoch nach den geeigneten Knoten und nicht nach einer Anzahl von Replikaten.

Die getestete Ausgabe enthielt zwei Revisionen und die neue Log-Nachricht:

REVISION  CHANGE-CAUSE
1         <none>
2         <none>

node=labex-v135 version=v2

CHANGE-CAUSE=<none> bedeutet lediglich, dass keine für Menschen lesbare Änderungsannotation aufgezeichnet wurde. Revision 2 zusammen mit version=v2 im Log des Ersatz-Pods liefert den entscheidenden Nachweis, dass der Rollout stattgefunden hat.

Zusammenfassung

Du hast mit Knoten-Labels die Eignung für ein DaemonSet gesteuert, die Abstimmung mit genau einem Pod pro geeignetem Knoten beobachtet, die Besitzverhältnisse des Controllers nachvollzogen und ein Update des Knoten-Agenten ausgerollt. Nun kannst du DaemonSets mit replikaorientierten Deployments und auf Abschluss ausgerichteten Jobs vergleichen.