Questo tutorial mostra come personalizzare i nodi di un cluster Google Kubernetes Engine (GKE) utilizzando DaemonSets. Un DaemonSet contribuisce a garantire che tutti i nodi (o quelli selezionati) eseguano una copia di un pod. Quando vengono aggiunti nuovi nodi a un cluster, viene eseguito anche un pod da DaemonSet.
Se gli strumenti e i sistemi che utilizzi per inizializzare i cluster sono diversi da quelli che utilizzi per eseguire i workload, aumenti l'impegno necessario per gestire l'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 vengono eseguiti gli altri carichi di lavoro. L'utilizzo di un DaemonSet ti consente di utilizzare gli stessi strumenti per orchestrare i tuoi carichi di lavoro che utilizzi per modificare i nodi GKE.
Lo scopo di questo tutorial è aiutare gli amministratori di sistema, gli ingegneri di sistema o gli operatori dell'infrastruttura a semplificare l'inizializzazione dei cluster Kubernetes.
Prima di leggere questa pagina, assicurati di avere familiarità con:
In questo tutorial imparerai a utilizzare le incompatibilità e le tolleranze di Kubernetes per assicurarti che i nodi vengano configurati da un DaemonSet prima che i workload delle applicazioni possano essere pianificati su di essi.
Obiettivi
In questo tutorial imparerai a:
- Esegui il provisioning di un cluster GKE.
- Contamina un pool di nodi per impedire la pianificazione del carico di lavoro prima di applicare la configurazione del nodo.
- Esegui il deployment di un DaemonSet che configura i nodi e rimuove il taint.
- Verifica che i nodi del cluster siano configurati e che il taint sia stato rimosso.
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.
Al termine delle attività descritte in questo documento, puoi evitare l'addebito di ulteriori costi eliminando le risorse che hai creato. Per saperne di più, consulta Esegui la pulizia.
Prima di iniziare
- 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 senza costi per l'esecuzione, il test e il deployment dei workload.
-
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 theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
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 theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Implicazioni per la sicurezza di DaemonSet con privilegi
L'utilizzo dell'impostazione securityContext: privileged: true in un DaemonSet (o in qualsiasi pod) è
potente, ma comporta implicazioni di sicurezza significative perché disattiva
la maggior parte dei limiti di isolamento dei container per quel pod. Devi essere consapevole delle
seguenti restrizioni e rischi per la sicurezza che introduce:
- Container escape o compromissione dell'host:una vulnerabilità all'interno dell'applicazione o dell'immagine del container con privilegi può portare direttamente all'accesso root sul nodo host.
- Violazione del principio del privilegio minimo: la modalità privilegiata concede tutte le funzionalità, probabilmente molte di più di quelle necessarie per un'attività specifica. Questo ampio accesso aumenta il potenziale danno se il container viene compromesso.
- Destabilizzazione dei nodi:comandi accidentali o dannosi potrebbero essere eseguiti all'interno del
container con privilegi, ad esempio valori
sysctlerrati o comandi comerm -rf /host/boot. Questi tipi di comandi possono causare l'arresto anomalo o il danneggiamento del sistema operativo del nodo host. - Movimento laterale: la compromissione di un nodo tramite un DaemonSet privilegiato offre a un utente malintenzionato un punto d'appoggio solido per attaccare altri nodi, il piano di controllo di Kubernetes o i sistemi connessi.
- Esposizione dei dati:l'accesso senza restrizioni al file system host (
/) può esporre dati sensibili archiviati sul nodo, incluse credenziali, chiavi o dati appartenenti ad altri pod se utilizzano volumi hostPath. - Maggiore superficie di attacco:la modalità con privilegi espone un maggior numero di chiamate e funzionalità del sistema del kernel host a potenziali exploit dall'interno del container.
Per evitare rischi per la sicurezza, tieni presente le seguenti best practice e mitigazioni:
- Evita di utilizzare la modalità con privilegi:l'approccio più sicuro è evitare completamente l'impostazione
privileged: true. - Utilizza le funzionalità di Linux:se sono necessari diritti elevati, puoi concedere
funzionalità Linux specifiche come
NET_ADMIN,SYS_ADMIN,SYS_MODULEnel camposecurityContext.capabilities.addanziché privilegi completi. Questo approccio segue il principio del privilegio minimo, che consigliamo rispetto alla concessione di autorizzazioni generiche. - Limita l'ambito:esegui DaemonSet privilegiati solo su pool di nodi dedicati, possibilmente con taint, per contenere il potenziale impatto se un container viene compromesso.
- Applica le policy:utilizza strumenti come Policy Controller o Gatekeeper per creare policy che limitano, controllano o richiedono una giustificazione per il deployment di container privilegiati.
- Scansiona e utilizza immagini attendibili:utilizza Autorizzazione binaria e una rigorosa scansione delle immagini per garantire che vengano eseguite con privilegi elevati solo le immagini container verificate e attendibili.
- Riduci al minimo i montaggi dell'host:monta solo i percorsi host specifici necessari e utilizza
readOnly: true, se possibile. Evita di montare l'intero file system root (/). - Esegui controlli regolari:rivedi periodicamente tutti i carichi di lavoro in esecuzione con l'impostazione
privileged: true.
Esegui il bootstrap dell'ambiente
In questa sezione, imparerai a:
- Abilita le API Cloud necessarie.
- Esegui il provisioning di un service account con privilegi limitati per i nodi nel cluster GKE.
- Prepara il cluster GKE.
- Concedi all'utente i privilegi di amministrazione del cluster.
Abilita Cloud APIs
Apri Cloud Shell.
Seleziona il progetto Google Cloud :
gcloud config set project project-id
Sostituisci
project-idcon l'ID del progettoGoogle Cloud che hai creato o selezionato per questo tutorial.Abilita l'API Kubernetes Engine:
gcloud services enable container.googleapis.com
Provisiona un account di servizio per gestire i cluster GKE
In questa sezione crei un service account associato ai nodi del cluster. In questo tutorial, i nodi GKE utilizzano questo account di servizio anziché il service account predefinito. Come best practice, concedi al account di servizio solo i ruoli e le autorizzazioni di accesso necessari per eseguire l'applicazione.
I ruoli richiesti per il account di servizio sono i seguenti:
- Ruolo Visualizzatore monitoraggio (
roles/monitoring.viewer). Questo ruolo concede accesso di sola lettura ai dati di monitoraggio. - Ruolo Monitoring Metric Writer (
roles/monitoring.metricWriter). Questo ruolo consente di scrivere dati di monitoraggio. - Ruolo Writer log (
roles/logging.logWriter). Questo ruolo concede le autorizzazioni per scrivere i log.
Per eseguire il provisioning di un account di servizio:
In Cloud Shell, inizializza una variabile di ambiente che memorizza il nome delaccount di serviziot:
GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gkeCrea un service account:
gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \ --display-name="$GKE_SERVICE_ACCOUNT_NAME"Inizializza una variabile di ambiente che memorizza il nome dell'account email del account di servizio:
GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \ --format='value(email)' \ --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"Associa i ruoli Identity and Access Management (IAM) al 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/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
Prepara il cluster GKE
In questa sezione, avvii il cluster GKE, concedi le autorizzazioni e completi la configurazione del cluster.
Per questo tutorial, un cluster con un numero relativamente basso di nodi piccoli e di uso generale è sufficiente per dimostrare il concetto. Crea un cluster con un node pool (quello predefinito).
In Cloud Shell, crea e avvia un cluster GKE regionale:
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"
Applica le configurazioni dei nodi utilizzando un DaemonSet
In questa sezione, impedisci l'esecuzione dei carichi di lavoro sui nodi prima del completamento della configurazione applicando un taint al pool di nodi. Poi esegui il deployment di un DaemonSet che esegue le seguenti operazioni:
- Pianifica i pod sui nodi con incompatibilità utilizzando una tolleranza per l'incompatibilità.
- Esegue un container init con privilegi che applica prima la configurazione del nodo utilizzando
sysctl, quindi rimuove il taint dal nodo utilizzandokubectl. La rimozione del taint rende il nodo pianificabile per i carichi di lavoro. - Pianifica ed esegue un container di pausa che rimane inattivo e non consuma risorse per impedire a DaemonSet di riprogrammare il pod utilizzato per la configurazione.
Questo tutorial applica il parametro del kernel vm.max_map_count=262144 come configurazione di esempio.
Applica un taint al pool di nodi predefinito:
gcloud container node-pools update default-pool \ --cluster=ds-init-tutorial \ --node-taints=node.config.status/stage=configuring:NoSchedule \ --region=us-central1Con questa incompatibilità, solo i pod che la tollerano, come il pod DaemonSet, possono essere pianificati in questo pool di nodi.
Verifica che il taint sia applicato:
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep TaintsLo stato del nodo dovrebbe mostrare
node.config.status/stage=configuring:NoSchedule.Salva il seguente manifest come
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.9Questo manifest crea un service account, un ClusterRole e un ClusterRoleBinding per concedere al DaemonSet l'autorizzazione per rimuovere i taint dai nodi. DaemonSet esegue il deployment di un pod su ogni nodo che tollera l'incompatibilità
configuring:NoSchedule. Questo pod esegue un container init con privilegi che applica la configurazionesysctl(vm.max_map_count=262144) e rimuove l'incompatibilità del nodo, rendendolo pianificabile. Viene quindi avviato un container di pausa per mantenere in esecuzione il pod.Il container init viene eseguito in modalità con privilegi, il che ha implicazioni per la sicurezza. Per maggiori dettagli, vedi Compromessi e limitazioni di sicurezza di Privileged DaemonSet.
Applica il manifest:
kubectl apply -f auto-untaint-daemonset.yamlVerifica che i pod DaemonSet siano stati creati e attendi che raggiungano lo stato
Running:kubectl get pods -l app=auto-untaint-configurator -o wideLo stato
Runningindica che il container init è stato completato correttamente. Prendi nota del nome del pod in modo da poterlo utilizzare per verificare l'inizializzazione nella sezione successiva.
Convalida e verifica la procedura di inizializzazione
Una volta completata la configurazione del nodo, puoi verificare i risultati controllando i log.
Controlla i log del container init di uno dei pod per visualizzarne l'output:
kubectl logs POD_NAME -c configure-and-untaintSostituisci
POD_NAMEcon il nome del tuo pod.Dovresti visualizzare un output che indica la riuscita della configurazione e l'eliminazione del taint del nodo.
Verifica che l'incompatibilità sia stata rimossa:
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep TaintsLo stato del nodo deve mostrare
Taints: <none>o i taint con la chiavenode.config.status/stage.
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 il 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 pulire il progetto.
Liberare spazio nel progetto
Per liberare spazio in un progetto senza eliminarlo, devi rimuovere le risorse che hai creato in questo tutorial.
In Cloud Shell, elimina il cluster GKE:
gcloud container clusters delete ds-init-tutorial --quiet --region us-central1Elimina il account di servizio:
gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
Elimina il progetto
Il modo più semplice per eliminare la fatturazione è eliminare il progetto creato per il tutorial.
- Nella console Google Cloud , vai alla pagina Gestisci risorse.
- Nell'elenco dei progetti, seleziona quello che vuoi eliminare, quindi fai clic su Elimina.
- Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.
Passaggi successivi
- Scopri di più su GKE.
- Implementa una catena di fornitura del software sicura.
- Scopri come rafforzare la sicurezza del tuo cluster GKE.
- Esplora architetture, diagrammi e best practice di riferimento su Google Cloud. Consulta il nostro Cloud Architecture Center.