GKE-Knoten automatisch mit DaemonSets starten

In dieser Anleitung wird gezeigt, wie Sie die Knoten eines Google Kubernetes Engine-Clusters (GKE-Clusters) mithilfe von DaemonSets anpassen. Mit einem DaemonSet wird sichergestellt, dass alle (oder ausgewählte) Knoten eine Kopie eines Pods ausführen. Wenn einem Cluster neue Knoten hinzugefügt werden, wird auch auf diesen ein Pod aus dem DaemonSet ausgeführt.

Wenn Sie zum Initialisieren Ihrer Cluster andere Tools und Systeme verwenden als zum Ausführen Ihrer Arbeitslasten, erhöht dies den Verwaltungsaufwand für Ihre Umgebung. Wenn Sie beispielsweise ein Konfigurationsmanagementtool zum Initialisieren der Clusterknoten verwenden, bauen Sie auf ein Verfahren außerhalb der Laufzeitumgebung, in der die übrigen Arbeitslasten ausgeführt werden. Mit einem DaemonSet können Sie dieselben Tools zum Orchestrieren Ihrer Arbeitslasten verwenden, die Sie auch zum Ändern Ihrer GKE-Knoten verwenden.

Ziel dieser Anleitung ist es, Systemadministratoren, Systementwickler oder Infrastrukturbetreiber bei der Optimierung der Initialisierung von Kubernetes-Clustern zu unterstützen.

Bevor Sie diese Seite lesen, sollten Sie mit Folgendem vertraut sein:

In dieser Anleitung erfahren Sie, wie Sie Kubernetes-Taints und -Toleranzen verwenden, um sicherzustellen, dass Knoten von einem DaemonSet konfiguriert werden, bevor Anwendungsarbeitslasten darauf geplant werden können.

Ziele

In dieser Anleitung tun Sie Folgendes:

  • Stellen Sie einen GKE-Cluster bereit.
  • Markieren Sie einen Knotenpool, um die Planung von Arbeitslasten vor dem Anwenden der Knotenkonfiguration zu verhindern.
  • Stellen Sie ein DaemonSet bereit, das Knoten konfiguriert und die Markierung entfernt.
  • Prüfen Sie, ob die Clusterknoten konfiguriert und die Taint entfernt wurde.

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.

Neuen Nutzern von Google Cloud steht möglicherweise eine kostenlose Testversion zur Verfügung.

Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.

Hinweis

  1. Melden Sie sich in Ihrem Google Cloud -Konto an. Wenn Sie mit Google Cloudnoch nicht vertraut sind, erstellen Sie einfach ein Konto, um die Leistungsfähigkeit unserer Produkte in der Praxis sehen und bewerten zu können. Neukunden erhalten außerdem ein Guthaben von 300 $, um Arbeitslasten auszuführen, zu testen und bereitzustellen.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

Auswirkungen auf die Sicherheit von privilegierten DaemonSets

Die Verwendung der Einstellung securityContext: privileged: true in einem DaemonSet (oder einem beliebigen Pod) ist leistungsstark, birgt aber erhebliche Sicherheitsrisiken, da die meisten Containerisolierungsgrenzen für diesen Pod deaktiviert werden. Sie sollten sich der folgenden Sicherheitsbeschränkungen und Risiken bewusst sein:

  • Container-Escape oder Host-Gefährdung:Eine Sicherheitslücke in der privilegierten Containeranwendung oder im Image kann direkt zu Root-Zugriff auf dem Hostknoten führen.
  • Verstoß gegen das Prinzip der geringsten Berechtigung: Der privilegierte Modus gewährt alle Funktionen, wahrscheinlich weit mehr als für eine bestimmte Aufgabe erforderlich. Dieser umfassende Zugriff erhöht das potenzielle Schadensrisiko, wenn der Container manipuliert wird.
  • Knotendestabilisierung: Versehentliche oder bösartige Befehle könnten im privilegierten Container ausgeführt werden, z. B. falsche sysctl-Werte oder Befehle wie rm -rf /host/boot. Diese Arten von Befehlen können das Betriebssystem des Hostknotens zum Absturz bringen oder beschädigen.
  • Laterale Bewegung:Wenn ein Knoten über ein privilegiertes DaemonSet kompromittiert wird, erhält ein Angreifer eine gute Ausgangsposition, um andere Knoten, die Kubernetes-Steuerungsebene oder verbundene Systeme anzugreifen.
  • Datenpanne: Uneingeschränkter Zugriff auf das Hostdateisystem (/) kann sensible Daten offenlegen, die auf dem Knoten gespeichert sind, einschließlich Anmeldedaten, Schlüssel oder Daten, die zu anderen Pods gehören, wenn sie hostPath-Volumes verwenden.
  • Größere Angriffsfläche:Im privilegierten Modus sind mehr Host-Kernel-Systemaufrufe und ‑Funktionen für potenzielle Exploits im Container verfügbar.

Um Sicherheitsrisiken zu vermeiden, sollten Sie die folgenden Best Practices und Maßnahmen beachten:

  • Vermeiden Sie die Verwendung des privilegierten Modus:Die sicherste Methode ist, die Einstellung privileged: true ganz zu vermeiden.
  • Linux-Funktionen verwenden:Wenn erhöhte Rechte erforderlich sind, können Sie im Feld securityContext.capabilities.add anstelle von vollen Berechtigungen bestimmte Linux-Funktionen wie NET_ADMIN, SYS_ADMIN und SYS_MODULE gewähren. Dieser Ansatz folgt dem Prinzip der geringsten Berechtigung, das wir gegenüber der Erteilung umfassender Berechtigungen empfehlen.
  • Umfang einschränken: Führen Sie privilegierte DaemonSets nur auf dedizierten, möglicherweise mit Markierungen versehenen Knotenpools aus, um die potenziellen Auswirkungen einzugrenzen, wenn ein Container manipuliert wird.
  • Richtlinien erzwingen:Verwenden Sie Tools wie Policy Controller oder Gatekeeper, um Richtlinien zu erstellen, die die Bereitstellung privilegierter Container einschränken, prüfen oder eine Begründung dafür erfordern.
  • Vertrauenswürdige Images scannen und verwenden:Verwenden Sie die Binärautorisierung und gründliche Image-Scans, um sicherzustellen, dass nur geprüfte, vertrauenswürdige Container-Images mit erhöhten Berechtigungen ausgeführt werden.
  • Host-Mounts minimieren:Mounten Sie nur die erforderlichen Host-Pfade und verwenden Sie nach Möglichkeit readOnly: true. Vermeiden Sie die Bereitstellung des gesamten Stammdateisystems (/).
  • Regelmäßige Audits durchführen:Überprüfen Sie regelmäßig alle Arbeitslasten, die mit der Einstellung privileged: true ausgeführt werden.

Umgebung bootstrappen

In diesem Abschnitt tun Sie Folgendes:

  1. Erforderliche Cloud APIs aktivieren
  2. Dienstkonto mit eingeschränkten Berechtigungen für die Knoten im GKE-Cluster bereitstellen
  3. GKE-Cluster vorbereiten
  4. Gewähren Sie dem Nutzer Administratorberechtigungen für den Cluster.

Cloud APIs aktivieren

  1. Cloud Shell öffnen

    Cloud Shell öffnen

  2. Wählen Sie das Google Cloud Projekt aus:

    gcloud config set project project-id
    

    Ersetzen Sie dabei project-id durch die ID desGoogle Cloud -Projekts, das Sie für diese Anleitung erstellt oder ausgewählt haben.

  3. Aktivieren Sie die Kubernetes Engine API:

    gcloud services enable container.googleapis.com
    

Dienstkonto zum Verwalten von GKE-Clustern bereitstellen

In diesem Abschnitt erstellen Sie ein Dienstkonto, das den Knoten im Cluster zugeordnet ist. In dieser Anleitung wird dieses Dienstkonto anstelle des Standarddienstkontos von GKE-Knoten verwendet. Als Best Practice empfehlen wir, dem Dienstkonto nur die zum Ausführen der Anwendung erforderlichen Rollen und Zugriffsberechtigungen zuzuweisen.

Folgende Rollen sind für das Dienstkonto erforderlich:

  • Rolle „Monitoring-Betrachter“ (roles/monitoring.viewer): Diese Rolle bietet Lesezugriff auf Monitoringdaten.
  • Rolle "Monitoring-Messwert-Autor" (roles/monitoring.metricWriter). Diese Rolle ermöglicht das Schreiben von Monitoringdaten.
  • Rolle „Logautor“ (roles/logging.logWriter): Mit dieser Rolle werden Berechtigungen zum Schreiben von Logs gewährt.

So stellen Sie ein Dienstkonto bereit:

  1. Initialisieren Sie in Cloud Shell eine Umgebungsvariable, in der der Name des Dienstkontos gespeichert wird:

    GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gke
    
  2. Erstellen Sie ein Dienstkonto:

    gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \
      --display-name="$GKE_SERVICE_ACCOUNT_NAME"
    
  3. Initialisieren Sie eine Umgebungsvariable, in der der E-Mail-Kontoname des Dienstkontos gespeichert wird:

    GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \
        --format='value(email)' \
        --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"
    
  4. Binden Sie die IAM-Rollen (Identitäts- und Zugriffsverwaltung) an das Dienstkonto:

    gcloud projects add-iam-policy-binding \
        "$(gcloud config get-value project 2> /dev/null)" \
        --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \
        --role roles/monitoring.viewer
    gcloud projects add-iam-policy-binding \
        "$(gcloud config get-value project 2> /dev/null)" \
        --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \
        --role roles/monitoring.metricWriter
    gcloud projects add-iam-policy-binding \
        "$(gcloud config get-value project 2> /dev/null)" \
        --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \
        --role roles/logging.logWriter
    

GKE-Cluster vorbereiten

In diesem Abschnitt starten Sie den GKE-Cluster, gewähren Berechtigungen und schließen die Clusterkonfiguration ab.

Zum Demonstrieren des Konzepts dieser Anleitung reicht ein Cluster mit einer relativ kleinen Anzahl kleiner Knoten für allgemeine Zwecke aus. Sie erstellen einen Cluster mit einem Knotenpool (dem Standardpool).

  • Erstellen Sie in Cloud Shell einen regionalen GKE-Cluster und starten Sie ihn:

    gcloud container clusters create ds-init-tutorial \
        --enable-ip-alias \
        --machine-type=n1-standard-2 \
        --metadata disable-legacy-endpoints=true \
        --node-labels=app=default-init \
        --node-locations us-central1-a,us-central1-b,us-central1-c \
        --no-enable-basic-auth \
        --no-issue-client-certificate \
        --num-nodes=1 \
        --location us-central1 \
        --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
    

Knotenkonfigurationen mit einem DaemonSet anwenden

In diesem Abschnitt verhindern Sie, dass Arbeitslasten auf Knoten ausgeführt werden, bevor die Konfiguration abgeschlossen ist. Dazu wenden Sie eine Markierung auf den Knotenpool an. Anschließend stellen Sie ein DaemonSet bereit, das Folgendes ausführt:

  1. Plant Pods auf markierten Knoten ein, indem eine Toleranz für die Markierung verwendet wird.
  2. Führt einen privilegierten Init-Container aus, der zuerst die Knotenkonfiguration mit sysctl anwendet und dann den Taint mit kubectl vom Knoten entfernt. Durch das Entfernen der Markierung kann der Knoten für Arbeitslasten geplant werden.
  3. Einen Pause-Container planen und ausführen, der inaktiv bleibt und keine Ressourcen verbraucht, um zu verhindern, dass das DaemonSet den für die Konfiguration verwendeten Pod neu plant.

In dieser Anleitung wird der Kernelparameter vm.max_map_count=262144 als Beispielkonfiguration verwendet.

  1. Wenden Sie eine Markierung auf den Standardknotenpool an:

    gcloud container node-pools update default-pool \
      --cluster=ds-init-tutorial \
      --node-taints=node.config.status/stage=configuring:NoSchedule \
      --region=us-central1
    

    Mit dieser Markierung können nur Pods, die sie tolerieren, wie der DaemonSet-Pod, in diesem Knotenpool geplant werden.

  2. Prüfen Sie, ob die Markierung angewendet wurde:

    kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep Taints
    

    Der Knotenstatus sollte node.config.status/stage=configuring:NoSchedule sein.

  3. Speichern Sie das folgende Manifest als auto-untaint-daemonset.yaml:

    # WARNING: This DaemonSet runs as privileged, which has significant
    # security implications. Only use this on clusters where you have
    # strict controls over what is deployed.
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: node-config-sa
      namespace: default
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: node-patcher-role
    rules:
    - apiGroups: [""]
      resources: ["nodes"]
      # Permissions needed to read and remove a taint from the node.
      verbs: ["get", "patch", "update"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: node-config-binding
    subjects:
    - kind: ServiceAccount
      name: node-config-sa
      namespace: default
    roleRef:
      kind: ClusterRole
      name: node-patcher-role
      apiGroup: rbac.authorization.k8s.io
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: auto-untaint-daemonset
      labels:
        app: auto-untaint-configurator
    spec:
      selector:
        matchLabels:
          app: auto-untaint-configurator
      updateStrategy:
        type: RollingUpdate
      template:
        metadata:
          labels:
            app: auto-untaint-configurator
        spec:
          serviceAccountName: node-config-sa
          hostPID: true
          # Toleration now matches the taint on your node.
          tolerations:
          - key: "node.config.status/stage"
            operator: "Equal"
            value: "configuring"
            effect: "NoSchedule"
          volumes:
          - name: host-root-fs
            hostPath:
              path: /
          initContainers:
          - name: configure-and-untaint
            image: ubuntu:22.04 # Using a standard container image.
            securityContext:
              privileged: true # Required for chroot and sysctl.
            env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            volumeMounts:
            - name: host-root-fs
              mountPath: /host
            command: ["/bin/bash", "-c"]
            args:
            - |
              # Using explicit error checking for each critical command.
    
              # Define the configuration and taint details.
              SYSCTL_PARAM="vm.max_map_count"
              SYSCTL_VALUE="262144"
              TAINT_KEY="node.config.status/stage"
    
              echo "Running configuration on node: ${NODE_NAME}"
    
              # 1. APPLY CONFIGURATION
              echo "--> Applying ${SYSCTL_PARAM}=${SYSCTL_VALUE}..."
              if ! chroot /host sysctl -w "${SYSCTL_PARAM}=${SYSCTL_VALUE}"; then
                echo "ERROR: Failed to apply sysctl parameter." >&2
                exit 1
              fi
              echo "--> Configuration applied successfully."
    
              # 2. UNTAINT THE NODE
              # This command removes the taint from the node this Pod is running on.
              echo "--> Untainting node ${NODE_NAME} by removing taint ${TAINT_KEY}..."
              if ! /host/home/kubernetes/bin/kubectl taint node "${NODE_NAME}" "${TAINT_KEY}:NoSchedule-"; then
                echo "ERROR: Failed to untaint the node." >&2
                exit 1
              fi
              echo "--> Node has been untainted and is now schedulable."
          # The main container is minimal; it just keeps the Pod running.
          containers:
          - name: pause-container
            image: registry.k8s.io/pause:3.9
    

    Mit diesem Manifest werden ein ServiceAccount, eine ClusterRole und eine ClusterRoleBinding erstellt, um dem DaemonSet die Berechtigung zum Entfernen von Taints von Knoten zu erteilen. Das DaemonSet stellt auf jedem Knoten, der die configuring:NoSchedule-Markierung toleriert, einen Pod bereit. In diesem Pod wird ein privilegierter Init-Container ausgeführt, der die sysctl-Konfiguration (vm.max_map_count=262144) anwendet und die Knotenmarkierung entfernt, wodurch der Knoten planbar wird. Anschließend wird ein Pausencontainer gestartet, damit der Pod weiter ausgeführt wird.

    Der Init-Container wird im privilegierten Modus ausgeführt, was Sicherheitsrisiken birgt. Weitere Informationen finden Sie unter Kompromisse und Sicherheitseinschränkungen bei privilegierten DaemonSets.

  4. Wenden Sie das Manifest an:

    kubectl apply -f auto-untaint-daemonset.yaml
    
  5. Prüfen Sie, ob die DaemonSet-Pods erstellt wurden, und warten Sie, bis sie den Status Running erreichen:

    kubectl get pods -l app=auto-untaint-configurator -o wide
    

    Der Status Running gibt an, dass der Init-Container erfolgreich abgeschlossen wurde. Notieren Sie sich den Pod-Namen, damit Sie ihn im nächsten Abschnitt zur Überprüfung der Initialisierung verwenden können.

Initialisierungsverfahren validieren und verifizieren

Nachdem die Knotenkonfiguration abgeschlossen ist, können Sie die Ergebnisse anhand der Logs prüfen.

  1. Sehen Sie sich die Init-Container-Logs eines der Pods an, um die Ausgabe zu sehen:

    kubectl logs POD_NAME -c configure-and-untaint
    

    Ersetzen Sie POD_NAME durch den Namen Ihres Pods.

    Die Ausgabe sollte darauf hinweisen, dass die Konfiguration und das Entfernen der Taints für den Knoten erfolgreich waren.

  2. Prüfen Sie, ob der Taint entfernt wurde:

    kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep Taints
    

    Der Knotenstatus sollte Taints: <none> oder Taints mit dem Schlüssel node.config.status/stage anzeigen.

Bereinigen

Damit Ihrem Google Cloud Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, können Sie das für diese Anleitung erstellte Projekt löschen. Wenn Sie ein Projekt speziell für diese Anleitung erstellt haben, können Sie es vollständig löschen. Wenn Sie ein vorhandenes Projekt verwendet haben, es aber nicht löschen möchten, können Sie es anhand der folgenden Schritte bereinigen.

Projekt bereinigen

Wenn Sie ein Projekt bereinigen möchten, ohne es zu löschen, müssen Sie die Ressourcen entfernen, die Sie in dieser Anleitung erstellt haben.

  1. Löschen Sie den GKE-Cluster in Cloud Shell:

    gcloud container clusters delete ds-init-tutorial --quiet --region us-central1
    
  2. Löschen Sie das Dienstkonto:

    gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
    

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten, wenn Sie das für die Anleitung erstellte Projekt löschen.

  1. Wechseln Sie in der Google Cloud -Console zur Seite Ressourcen verwalten.

    Zur Seite „Ressourcen verwalten“

  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie dann auf Löschen.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Shut down (Beenden), um das Projekt zu löschen.

Nächste Schritte