En este instructivo, se muestra cómo personalizar los nodos de un clúster de Google Kubernetes Engine (GKE) mediante DaemonSets. Un DaemonSet ayuda a garantizar que todos los nodos (o los nodos seleccionados) ejecuten una copia de un Pod. Cuando se agregan nodos nuevos a un clúster, también ejecutan un Pod desde el DaemonSet.
Si las herramientas y los sistemas que usas cuando inicializas los clústeres son diferentes a las herramientas y a los sistemas que usas para ejecutar las cargas de trabajo, aumenta el esfuerzo que se necesita para administrar el entorno. Por ejemplo, si usas una herramienta de administración de la configuración para inicializar los nodos del clúster, dependes de un procedimiento que está fuera del entorno de ejecución en el que se ejecuta el resto de las cargas de trabajo. El uso de un DaemonSet te permite usar las mismas herramientas para organizar las cargas de trabajo que usas para modificar tus nodos de GKE.
El objetivo de este instructivo es ayudar a los administradores de sistemas, los ingenieros de sistemas o los operadores de infraestructura a optimizar la inicialización de los clústeres de Kubernetes.
Antes de leer esta página, asegúrate de estar familiarizado con los siguientes temas:
En este instructivo, aprenderás a usar taints y tolerancias de Kubernetes para garantizar que un DaemonSet configure los nodos antes de que se puedan programar cargas de trabajo de aplicaciones en ellos.
Objetivos
En este instructivo, harás lo que se indica a continuación:
- Aprovisiona un clúster de GKE.
- Aplica un taint a un grupo de nodos para evitar la programación de cargas de trabajo antes de aplicar la configuración del nodo.
- Implementa un DaemonSet que configure nodos y quite el taint.
- Verifica que los nodos del clúster estén configurados y que se quite el taint.
Costos
En este documento, usarás los siguientes componentes facturables de Google Cloud:
Para generar una estimación de costos en función del uso previsto,
usa la calculadora de precios.
Cuando completes las tareas que se describen en este documento, podrás borrar los recursos que creaste para evitar que se te siga facturando. Para obtener más información, consulta Realiza una limpieza.
Antes de comenzar
- Accede a tu Google Cloud cuenta de. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
-
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.
Implicaciones de seguridad de DaemonSet con privilegios
Usar el parámetro de configuración securityContext: privileged: true en un DaemonSet (o cualquier Pod) es potente, pero tiene implicaciones de seguridad significativas porque inhabilita la mayoría de los límites de aislamiento de contenedores para ese Pod. Debes tener en cuenta las siguientes restricciones y riesgos de seguridad que introduce:
- Escape de contenedor o compromiso del host: Una vulnerabilidad dentro de la aplicación o imagen de contenedor con privilegios puede generar acceso raíz directo en el nodo host.
- Violación del principio de privilegio mínimo: El modo privilegiado otorga todas las capacidades, probablemente mucho más de lo necesario para una tarea específica. Este acceso amplio aumenta el daño potencial si el contenedor se ve comprometido.
- Desestabilización del nodo: Los comandos accidentales o maliciosos se pueden ejecutar dentro del contenedor con privilegios, por ejemplo, valores
sysctlincorrectos o comandos comorm -rf /host/boot. Estos tipos de comandos pueden fallar o dañar el sistema operativo del nodo host. - Movimiento lateral: Comprometer un nodo a través de un DaemonSet con privilegios le da a un atacante una base sólida para atacar otros nodos, el plano de control de Kubernetes o los sistemas conectados.
- Exposición de datos: El acceso sin restricciones al sistema de archivos del host (
/) puede exponer datos sensibles almacenados en el nodo, incluidas las credenciales, las claves o los datos que pertenecen a otros Pods si usan volúmenes hostPath. - Mayor superficie de ataque: El modo privilegiado expone más de las llamadas y funciones del sistema del kernel del host a posibles vulnerabilidades desde el contenedor.
Para evitar riesgos de seguridad, debes tener en cuenta las siguientes prácticas recomendadas y mitigaciones:
- Evita usar el modo privilegiado: El enfoque más seguro es evitar por completo el parámetro de configuración
privileged: true. - Usa capacidades de Linux: Si se necesitan derechos elevados, puedes otorgar capacidades específicas de Linux, como
NET_ADMIN,SYS_ADMIN,SYS_MODULEen el camposecurityContext.capabilities.adden lugar de privilegios completos. Este enfoque sigue el principio de privilegio mínimo, que recomendamos en lugar de otorgar permisos amplios. - Limita el alcance: Ejecuta DaemonSets con privilegios solo en grupos de nodos dedicados, posiblemente con taints, para contener el impacto potencial si un contenedor se ve comprometido.
- Aplica políticas: Usa herramientas como Policy Controller o Gatekeeper para crear políticas que restrinjan, auditen o requieran justificación para implementar contenedores con privilegios.
- Analiza y usa imágenes de confianza: Usa la Autorización binaria y el análisis riguroso de imágenes para garantizar que solo se ejecuten imágenes de contenedor verificadas y de confianza con privilegios elevados.
- Minimiza los montajes de host: Solo monta las rutas de acceso de host específicas necesarias y usa
readOnly: truesiempre que sea posible. Evita montar todo el sistema de archivos raíz (/). - Realiza auditorías periódicas: Revisa periódicamente todas las cargas de trabajo que se ejecutan con el parámetro de configuración
privileged: true.
Inicia el entorno
En esta sección, harás lo siguiente:
- Habilita las API de Cloud necesarias.
- Aprovisiona una cuenta de servicio con privilegios limitados para los nodos en el clúster de GKE.
- Prepara el clúster de GKE.
- Otorga al usuario privilegios de administrador de clústeres.
Habilita las API de Cloud
Abre Cloud Shell
Selecciona el Google Cloud proyecto:
gcloud config set project project-id
Reemplaza
project-idpor el ID del Google Cloud proyecto que creaste o seleccionaste para este instructivo.Habilita la API de Kubernetes Engine:
gcloud services enable container.googleapis.com
Aprovisiona una cuenta de servicio para administrar clústeres de GKE
En esta sección, crearás una cuenta de servicio asociada a los nodos del clúster. En este instructivo, los nodos de GKE usan esta cuenta de servicio en lugar de la cuenta de servicio predeterminada. Como práctica recomendada, otorga a la cuenta de servicio solo los roles y los permisos de acceso necesarios para ejecutar la aplicación.
Las funciones que se necesitan para la cuenta de servicio son las que se describen a continuación:
- Función de visualizador de Monitoring (
roles/monitoring.viewer). Esta función proporciona acceso de solo lectura a los datos de supervisión. - Función de escritor de métricas de Monitoring (
roles/monitoring.metricWriter). Esta función permite escribir datos de supervisión. - Función de escritor de registros (
roles/logging.logWriter). Esta función otorga permisos para escribir registros.
Para aprovisionar una cuenta de servicio, sigue estos pasos:
En Cloud Shell, inicializa una variable de entorno que almacene el nombre de la cuenta de servicio:
GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gkeCrea una cuenta de servicio:
gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \ --display-name="$GKE_SERVICE_ACCOUNT_NAME"Inicializa una variable de entorno que almacene el nombre de la cuenta de correo electrónico de la cuenta de servicio:
GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \ --format='value(email)' \ --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"Vincula las funciones de administración de identidades y accesos (IAM) a la cuenta de servicio:
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 el clúster de GKE
En esta sección, iniciarás el clúster de GKE, otorgarás permisos y finalizarás la configuración del clúster.
Un clúster con una cantidad relativamente baja de nodos pequeños de uso general es suficiente para demostrar el concepto de este instructivo. Debes crear un clúster con un grupo de nodos (el predeterminado).
En Cloud Shell, crea e inicia un clúster regional de clúster de GKE:
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"
Aplica configuraciones de nodos con un DaemonSet
En esta sección, evitarás que las cargas de trabajo se ejecuten en nodos antes de que se complete la configuración. Para ello, aplica un taint al grupo de nodos. Luego, implementa un DaemonSet que hace lo siguiente:
- Programa Pods en nodos con taints mediante una tolerancia para el taint.
- Ejecuta un contenedor init con privilegios que primero aplica la configuración del nodo con
sysctly, luego, quita el taint del nodo conkubectl. Quitar el taint hace que el nodo se pueda programar para las cargas de trabajo. - Programa y ejecuta un contenedor de pausa que permanece inactivo y no consume recursos para evitar que el DaemonSet reprograme el Pod que se usa para la configuración.
En este instructivo, se aplica el parámetro del kernel vm.max_map_count=262144 como configuración de ejemplo.
Aplica un taint al grupo de nodos predeterminado:
gcloud container node-pools update default-pool \ --cluster=ds-init-tutorial \ --node-taints=node.config.status/stage=configuring:NoSchedule \ --region=us-central1Con este taint, solo los Pods que lo toleran, como el Pod de DaemonSet, se pueden programar en este grupo de nodos.
Verifica que se aplique el taint:
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep TaintsEl estado del nodo debe mostrar
node.config.status/stage=configuring:NoSchedule.Guarda el siguiente manifiesto como
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.9Este manifiesto crea una ServiceAccount, ClusterRole y ClusterRoleBinding para otorgar al DaemonSet permiso para quitar taints de los nodos. El DaemonSet implementa un Pod en cada nodo que tolera el taint
configuring:NoSchedule. Este Pod ejecuta un contenedor init con privilegios que aplica la configuraciónsysctl(vm.max_map_count=262144) y quita el taint del nodo, lo que hace que el nodo se pueda programar. Luego, se inicia un contenedor de pausa para mantener el Pod en ejecución.El contenedor init se ejecuta en modo privilegiado, lo que tiene implicaciones de seguridad. Para obtener más detalles, consulta Intercambios de DaemonSet con privilegios y seguridad restricciones.
Aplica el manifiesto
kubectl apply -f auto-untaint-daemonset.yamlVerifica que se creen los Pods de DaemonSet y espera a que alcancen el estado
Running:kubectl get pods -l app=auto-untaint-configurator -o wideEl estado
Runningindica que el contenedor init se completó correctamente. Toma nota del nombre del Pod para que puedas usarlo para verificar la inicialización en la siguiente sección.
Valida y verifica el procedimiento de inicialización
Una vez que se complete la configuración del nodo, puedes verificar los resultados consultando los registros.
Verifica los registros del contenedor init de uno de los Pods para ver su resultado:
kubectl logs POD_NAME -c configure-and-untaintReemplaza
POD_NAMEpor el nombre del Pod.Deberías ver un resultado que indica que la configuración y la eliminación del taint del nodo se realizaron correctamente.
Verifica que se quite el taint:
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep TaintsEl estado del nodo debe mostrar
Taints: <none>o mostrar taints que tengan la clavenode.config.status/stage.
Limpia
Para evitar que se apliquen cargos a tu Google Cloud cuenta de por los recursos que usaste en este instructivo, puedes borrar el proyecto de que creaste para este instructivo. Si creaste un proyecto dedicado a este instructivo, puedes borrarlo por completo. Si usaste un proyecto existente, pero no deseas borrarlo, sigue estos pasos para limpiar el proyecto.
Limpia el proyecto
Para limpiar un proyecto sin borrarlo, debes quitar los recursos que creaste en este instructivo.
En Cloud Shell, borra el clúster de GKE:
gcloud container clusters delete ds-init-tutorial --quiet --region us-central1Borra la cuenta de servicio:
gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
Borra el proyecto
La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.
- En la Google Cloud consola, ve a la página Administrar recursos.
- En la lista de proyectos, elige el proyecto que tú quieres borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.
¿Qué sigue?
- Obtén más información sobre GKE.
- Implementa una cadena de suministro de software segura.
- Obtén más información sobre cómo endurecer la seguridad del clúster de GKE.
- Explora arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.