Esegui automaticamente il bootstrap dei nodi GKE con DaemonSet

Progetto: /architecture/_project.yaml Book: /architecture/_book.yaml refresh_date: 2023-11-03 Nascondi_from_catalogs: True

Questo tutorial mostra come personalizzare i nodi di un cluster Google Kubernetes Engine (GKE) utilizzando DaemonSets. Un DaemonSet garantisce che tutti i nodi (o selezionati) eseguano una copia di un pod. Questo approccio ti consente di utilizzare gli stessi strumenti per orchestrare i carichi di lavoro che utilizzi per modificare i nodi GKE.

Se gli strumenti e i sistemi che utilizzi per inizializzare i cluster sono diversi da quelli che utilizzi per eseguire i carichi di lavoro, aumenti l'impegno necessario per gestire il tuo ambiente. Ad esempio, se utilizzi uno strumento di gestione della configurazione per inizializzare i nodi del cluster, ti affidi a una procedura esterna all'ambiente di runtime in cui viene eseguito il resto dei carichi di lavoro.

L'obiettivo di questo tutorial è aiutare gli amministratori di sistema, gli ingegneri di sistema o gli operatori di infrastruttura a semplificare l'inizializzazione dei cluster Kubernetes.

Per questo tutorial, devi acquisire familiarità con i seguenti strumenti:

In questo tutorial imparerai a utilizzare le etichette e i selettori Kubernetes per scegliere la procedura di inizializzazione da eseguire in base alle etichette applicate a un nodo. In questi passaggi, eseguirai il deployment di un DaemonSet in modo che venga eseguito solo sui nodi a cui è applicata l'etichetta default-init. Tuttavia, per dimostrare la flessibilità di questo meccanismo, puoi creare un altro pool di nodi e applicare l'etichetta alternative-init ai nodi in questo nuovo pool. Nel cluster, potresti quindi eseguire il deployment di un altro DaemonSet configurato per l'esecuzione solo sui nodi con l'etichetta alternative-init.

Inoltre, puoi eseguire più procedure di inizializzazione su ciascun nodo, non solo uno. Puoi sfruttare questo meccanismo per strutturare meglio le procedure di inizializzazione, separando chiaramente i problemi di ognuna.

In questo tutorial, ad esempio, la procedura di inizializzazione esegue le seguenti azioni su ciascun nodo etichettato con l'etichetta default-init:

  1. Collega un disco aggiuntivo al nodo.
  2. Installa un insieme di pacchetti e librerie utilizzando il gestore di pacchetti del sistema operativo del nodo.
  3. Carica un set di moduli kernel Linux.

Obiettivi

In questo tutorial imparerai a:

  • Eseguire il provisioning e la configurazione di un cluster GKE.
  • Prepara un descrittore DaemonSet per inizializzare i nodi nel cluster.
  • Eseguire il deployment del DaemonSet nel cluster.
  • Verifica che i nodi del cluster siano stati inizializzati.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud possono essere idonei a una prova senza costi aggiuntivi.

Una volta completate le attività descritte in questo documento, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la pagina Pulizia.

Prima di iniziare

  1. Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  3. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  4. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  5. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

Esegui il bootstrap dell'ambiente

In questa sezione:

  1. Abilita le API Cloud necessarie.
  2. Esegui il provisioning di un account di servizio con privilegi limitati per i nodi nel cluster GKE.
  3. Prepara il cluster GKE.
  4. Concedi i privilegi di amministrazione del cluster utente.

Abilita Cloud APIs

  1. Apri Cloud Shell.

    APRI Cloud Shell

  2. Seleziona il progetto Google Cloud:

    gcloud config set project project-id
    

    Sostituisci project-id con l'ID del progetto Google Cloud che hai creato o selezionato per questo tutorial.

  3. Abilita l'API Google Kubernetes Engine:

    gcloud services enable container.googleapis.com
    

Esegui il provisioning di un account di servizio per gestire i cluster GKE

In questa sezione creerai un account di servizio associato ai nodi nel cluster. In questo tutorial, i nodi GKE utilizzano questo account di servizio anziché l'account di servizio predefinito. Come best practice, concedi all'account di servizio solo i ruoli e le autorizzazioni di accesso necessarie per eseguire l'applicazione.

I ruoli richiesti per l'account di servizio sono i seguenti:

  • Ruolo Visualizzatore Monitoring (roles/monitoring.viewer). Questo ruolo concede l'accesso di sola lettura alla console e all'API Cloud Monitoring.
  • Ruolo di Writer metriche di monitoraggio (roles/monitoring.metricWriter). Questo ruolo consente di scrivere dati di monitoraggio.
  • Ruolo Writer log (roles/logging.logWriter). Questo ruolo concede le autorizzazioni sufficienti per scrivere i log.
  • Ruolo Utente account di servizio (roles/iam.serviceAccountUser). Questo ruolo concede l'accesso agli account di servizio in un progetto. In questo tutorial, la procedura di inizializzazione simula l'account di servizio per eseguire operazioni con privilegi.
  • Ruolo Amministratore Compute (roles/compute.admin). Questo ruolo fornisce il controllo completo di tutte le risorse Compute Engine. In questo tutorial, l'account di servizio richiede questo ruolo per collegare altri dischi ai nodi del cluster.

Per eseguire il provisioning di un account di servizio:

  1. In Cloud Shell, inizializza una variabile di ambiente in cui è archiviato il nome dell'account di servizio:

    GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gke
    
  2. Crea un account di servizio:

    gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \
      --display-name="$GKE_SERVICE_ACCOUNT_NAME"
    
  3. Inizializza una variabile di ambiente in cui è archiviato il nome dell'account email dell'account di servizio:

    GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \
        --format='value(email)' \
        --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"
    
  4. Associa i ruoli IAM (Identity and Access Management) all'account di servizio:

    gcloud projects add-iam-policy-binding \
        "$(gcloud config get-value project 2> /dev/null)" \
        --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \
        --role roles/compute.admin
    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
    gcloud projects add-iam-policy-binding \
        "$(gcloud config get-value project 2> /dev/null)" \
        --member serviceAccount:"$GKE_SERVICE_ACCOUNT_EMAIL" \
        --role roles/iam.serviceAccountUser
    

Prepara il cluster GKE

In questa sezione avvierai il cluster GKE, concederai le autorizzazioni e completerai la configurazione del cluster.

Per questo tutorial, un cluster con un numero relativamente basso di nodi per uso generico di piccole dimensioni è sufficiente per dimostrare il concetto di questo tutorial. Puoi creare un cluster con un pool di nodi (quello predefinito). Quindi etichetta tutti i nodi nel pool di nodi predefinito con l'etichetta default-init.

  • In Cloud Shell, crea e avvia un cluster GKE a livello di regione:

    gcloud container clusters create ds-init-tutorial \
        --enable-ip-alias \
        --image-type=ubuntu_containerd \
        --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 \
        --region us-central1 \
        --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
    

Deployment del DaemonSet

In questa sezione:

  1. Crea la risorsa ConfigMap che archivia la procedura di inizializzazione.
  2. Eseguire il deployment del DaemonSet che pianifica ed esegue la procedura di inizializzazione.

Il DaemonSet svolge le seguenti operazioni:

  1. Configura un volume che rende i contenuti del ConfigMap disponibili ai container gestiti dal DaemonSet.
  2. Configura i volumi per le aree del file system con privilegi del nodo cluster sottostante. Queste aree consentono ai container pianificati dal DaemonSet di interagire direttamente con il nodo che li esegue.
  3. Pianifica ed esegue un container init che esegue la procedura di inizializzazione, dopodiché viene terminato al completamento.
  4. Pianifica ed esegue un container che rimane inattivo e non consuma risorse.

Il container inattivo garantisce che un nodo venga inizializzato una sola volta. I DaemonSet sono progettati in modo da che tutti i nodi idonei eseguano una copia di un pod. Se utilizzi un container normale, quest'ultimo esegue la procedura di inizializzazione, dopodiché viene terminato al completamento. Il DaemonSet riprogramma il pod. Per evitare la "ripianificazione continua", il DaemonSet esegue prima la procedura di inizializzazione in un container di inizializzazione, quindi lascia un container in esecuzione.

La seguente procedura di inizializzazione contiene operazioni con privilegi e senza privilegi. Con chroot, puoi eseguire i comandi come se li eseguissi direttamente sul nodo, non solo all'interno di un container.

# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: entrypoint
  labels:
    app: default-init
data:
  entrypoint.sh: |
    #!/usr/bin/env bash

    set -euo pipefail

    DEBIAN_FRONTEND=noninteractive
    ROOT_MOUNT_DIR="${ROOT_MOUNT_DIR:-/root}"

    echo "Installing dependencies"
    apt-get update
    apt-get install -y apt-transport-https curl gnupg lsb-release

    echo "Installing gcloud SDK"
    export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)"
    echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
    apt-get update
    apt-get install -y google-cloud-sdk

    echo "Getting node metadata"
    NODE_NAME="$(curl -sS http://metadata.google.internal/computeMetadata/v1/instance/name -H 'Metadata-Flavor: Google')"
    ZONE="$(curl -sS http://metadata.google.internal/computeMetadata/v1/instance/zone -H 'Metadata-Flavor: Google' | awk -F  "/" '{print $4}')"

    echo "Setting up disks"
    DISK_NAME="$NODE_NAME-additional"

    if ! gcloud compute disks list --filter="name:$DISK_NAME" | grep "$DISK_NAME" > /dev/null; then
        echo "Creating $DISK_NAME"
        gcloud compute disks create "$DISK_NAME" --size=1024 --zone="$ZONE"
    else
        echo "$DISK_NAME already exists"
    fi

    if ! gcloud compute instances describe "$NODE_NAME" --zone "$ZONE" --format '(disks[].source)' | grep "$DISK_NAME" > /dev/null; then
        echo "Attaching $DISK_NAME to $NODE_NAME"
        gcloud compute instances attach-disk "$NODE_NAME" --device-name=sdb --disk "$DISK_NAME" --zone "$ZONE"
    else
        echo "$DISK_NAME is already attached to $NODE_NAME"
    fi

    # We use chroot to run the following commands in the host root (mounted as the /root volume in the container)
    echo "Installing nano"
    chroot "${ROOT_MOUNT_DIR}" apt-get update
    chroot "${ROOT_MOUNT_DIR}" apt-get install -y nano

    echo "Loading Kernel modules"
    # Load the bridge kernel module as an example
    chroot "${ROOT_MOUNT_DIR}" modprobe bridge
...

Ti consigliamo di esaminare attentamente ogni procedura di inizializzazione, in quanto potrebbe alterare lo stato dei nodi del cluster. Solo un piccolo gruppo di individui dovrebbe avere il diritto di modificare queste procedure, perché queste possono influire notevolmente sulla disponibilità e sulla sicurezza dei cluster.

Per eseguire il deployment di ConfigMap e di DaemonSet:

  1. In Cloud Shell, cambia la directory di lavoro nella directory $HOME:

    cd "$HOME"
    
  2. Clona il repository Git che contiene gli script e i file manifest di cui eseguire il deployment e configurare la procedura di inizializzazione:

    git clone https://github.com/GoogleCloudPlatform/solutions-gke-init-daemonsets-tutorial
    
  3. Cambia la directory di lavoro nella directory del repository appena clonata:

    cd "$HOME"/solutions-gke-init-daemonsets-tutorial
    
  4. Crea un ConfigMap per contenere lo script di inizializzazione del nodo:

    kubectl apply -f cm-entrypoint.yaml
    
  5. Esegui il deployment del DaemonSet:

    kubectl apply -f daemon-set.yaml
    
  6. Verifica che l'inizializzazione del nodo sia stata completata:

    kubectl get ds --watch
    

    Attendi che il DaemonSet venga segnalato come pronto e aggiornato, come indicato da un output simile al seguente:

    NAME              DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
    node-initializer   3         3         3         3            3          <none>  2h
    

Convalida e verifica la procedura di inizializzazione

Dopo che ogni nodo del cluster contrassegnato con l'etichetta default-init esegue la procedura di inizializzazione, puoi verificare i risultati.

Per ogni nodo, la procedura di verifica controlla quanto segue:

  1. Un disco aggiuntivo è collegato e pronto per essere utilizzato.
  2. Il gestore di pacchetti del sistema operativo del nodo ha installato pacchetti e librerie.
  3. I moduli del kernel sono stati caricati.

Esegui la procedura di verifica:

  • In Cloud Shell, esegui lo script di verifica:

    kubectl get nodes -o=jsonpath='{range .items[?(@.metadata.labels.app=="default-init")]}{.metadata.name}{" "}{.metadata.labels.failure-domain\.beta\.kubernetes\.io/zone}{"\n"}{end}' | while IFS= read -r line ; do ./verify-init.sh $line < /dev/null; done
    

    Attendi l'esecuzione dello script e verifica che ogni nodo sia stato inizializzato correttamente, come indicato dall'output come il seguente:

    Verifying gke-ds-init-tutorial-default-pool-5464b7e3-nzjm (us-central1-c) configuration
    Disk configured successfully on gke-ds-init-tutorial-default-pool-5464b7e3-nzjm (us-central1-c)
    Packages installed successfully in gke-ds-init-tutorial-default-pool-5464b7e3-nzjm (us-central1-c)
    Kernel modules loaded successfully on gke-ds-init-tutorial-default-pool-5464b7e3-nzjm (us-central1-c)
    Verifying gke-ds-init-tutorial-default-pool-65baf745-0gwt (us-central1-a) configuration
    Disk configured successfully on gke-ds-init-tutorial-default-pool-65baf745-0gwt (us-central1-a)
    Packages installed successfully in gke-ds-init-tutorial-default-pool-65baf745-0gwt (us-central1-a)
    Kernel modules loaded successfully on gke-ds-init-tutorial-default-pool-65baf745-0gwt (us-central1-a)
    Verifying gke-ds-init-tutorial-default-pool-6b125c50-3xvl (us-central1-b) configuration
    Disk configured successfully on gke-ds-init-tutorial-default-pool-6b125c50-3xvl (us-central1-b)
    Packages installed successfully in gke-ds-init-tutorial-default-pool-6b125c50-3xvl (us-central1-b)
    Kernel modules loaded successfully on gke-ds-init-tutorial-default-pool-6b125c50-3xvl (us-central1-b)
    

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, puoi eliminare il progetto che hai creato per questo tutorial. Se hai creato un progetto dedicato a questo tutorial, puoi eliminarlo completamente. Se hai utilizzato un progetto esistente ma non vuoi eliminarlo, segui questi passaggi per ripulire il progetto.

Esegui la pulizia del progetto

Per eseguire la pulizia di un progetto senza eliminarlo, devi rimuovere le risorse create in questo tutorial.

  1. In Cloud Shell, elimina il cluster GKE:

    gcloud container clusters delete ds-init-tutorial --quiet --region us-central1
    
  2. Elimina i dischi aggiuntivi che hai creato come parte di questa procedura di inizializzazione di esempio:

    gcloud compute disks list --filter="name:additional" --format="csv[no-heading](name,zone)" | while IFS= read -r line ; do DISK_NAME="$(echo $line | cut -d',' -f1)"; ZONE="$(echo $line | cut -d',' -f2)"; gcloud compute disks delete "$DISK_NAME" --quiet --zone "$ZONE" < /dev/null; done
    
  3. Elimina l'account di servizio:

    gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
    
  4. Elimina la directory del repository clonata:

    rm -rf "$HOME"/solutions-gke-init-daemonsets-tutorial
    

Elimina il progetto

Il modo più semplice per eliminare la fatturazione è eliminare il progetto creato per il tutorial.

  1. Nella console Google Cloud, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Passaggi successivi