En este tutorial se muestra cómo personalizar los nodos de un clúster de Google Kubernetes Engine (GKE) mediante DaemonSets. Un DaemonSet se encarga de que todos los nodos (o los nodos seleccionados) ejecuten una copia de un pod. Este enfoque te permite usar las mismas herramientas para orquestar tus cargas de trabajo que las que usas para modificar tus nodos de GKE.
Si las herramientas y los sistemas que usas para inicializar tus clústeres son diferentes de las herramientas y los sistemas que usas para ejecutar tus cargas de trabajo, aumentará el esfuerzo necesario para gestionar tu entorno. Por ejemplo, si usas una herramienta de gestión de la configuración para inicializar los nodos del clúster, estás usando un procedimiento que está fuera del entorno de tiempo de ejecución en el que se ejecutan el resto de tus cargas de trabajo.
El objetivo de este tutorial es ayudar a los administradores de sistemas, ingenieros de sistemas u operadores de infraestructura a agilizar la inicialización de clústeres de Kubernetes.
Antes de leer esta página, asegúrate de que conoces los siguientes conceptos:
En este tutorial, aprenderás a usar etiquetas y selectores de Kubernetes para elegir qué procedimiento de inicialización ejecutar en función de las etiquetas que se apliquen a un nodo. En estos pasos, implementará un DaemonSet para que se ejecute solo en los nodos que tengan aplicada la etiqueta default-init
. Sin embargo, para demostrar la flexibilidad de este mecanismo, puedes crear otro grupo de nodos y aplicar la etiqueta alternative-init
a los nodos de este nuevo grupo. En el clúster, puedes desplegar otro DaemonSet configurado para ejecutarse solo en los nodos que tengan la etiqueta alternative-init
.
También puedes ejecutar varios procedimientos de inicialización en cada nodo, no solo uno. Puedes aprovechar este mecanismo para estructurar mejor tus procedimientos de inicialización y separar claramente las responsabilidades de cada uno.
En este tutorial, como ejemplo, el procedimiento de inicialización realiza las siguientes acciones en cada nodo etiquetado con la etiqueta default-init
:
- Adjunta un disco adicional al nodo.
- Instala un conjunto de paquetes y bibliotecas mediante el gestor de paquetes del sistema operativo del nodo.
- Carga un conjunto de módulos del kernel de Linux.
Inicializar el entorno
En esta sección, debes hacer lo siguiente:
- Habilita las APIs de Cloud necesarias.
- Aprovisiona una cuenta de servicio con privilegios limitados para los nodos del clúster de GKE.
- Prepara el clúster de GKE.
- Concede al usuario privilegios de administración del clúster.
Habilitar APIs de Cloud
Abre Cloud Shell.
Selecciona el Google Cloud proyecto:
gcloud config set project project-id
Sustituye
project-id
por el ID delGoogle Cloud proyecto que has creado o seleccionado para este tutorial.Habilita la API de Google Kubernetes Engine:
gcloud services enable container.googleapis.com
Aprovisionar una cuenta de servicio para gestionar clústeres de GKE
En esta sección, creará una cuenta de servicio asociada a los nodos del clúster. En este tutorial, los nodos de GKE usan esta cuenta de servicio en lugar de la cuenta de servicio predeterminada. Como práctica recomendada, concede a la cuenta de servicio solo los roles y permisos de acceso necesarios para ejecutar la aplicación.
La cuenta de servicio debe tener los siguientes roles:
- Rol Lector de Monitoring (
roles/monitoring.viewer
). Este rol proporciona acceso de solo lectura a la consola y a la API de Cloud Monitoring. - Rol Editor de métricas de Monitoring (
roles/monitoring.metricWriter
). Este rol permite escribir datos de monitorización. - Rol Escritor de registros (
roles/logging.logWriter
): este rol proporciona los permisos suficientes para escribir registros. - Rol Usuario de cuenta de servicio (
roles/iam.serviceAccountUser
). Este rol da acceso a las cuentas de servicio de un proyecto. En este tutorial, el procedimiento de inicialización suplanta la identidad de la cuenta de servicio para ejecutar operaciones con privilegios. - Rol Administrador de Compute (
roles/compute.admin
). Este rol proporciona control total sobre todos los recursos de Compute Engine. En este tutorial, la cuenta de servicio necesita este rol para adjuntar discos adicionales a los nodos del clúster.
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-gke
Crea 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 de la cuenta de servicio:
GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \ --format='value(email)' \ --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"
Asigna los roles de Gestió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/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
Preparar el clúster de GKE
En esta sección, inicia el clúster de GKE, concede permisos y completa la configuración del clúster.
En este tutorial, basta con un clúster con un número relativamente bajo de nodos pequeños de propósito general para demostrar el concepto. Crea un clúster con un grupo de nodos (el predeterminado). A continuación, etiqueta todos los nodos del grupo de nodos predeterminado con la etiqueta default-init
.
En Cloud Shell, crea e inicia un clúster de GKE regional:
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 \ --location us-central1 \ --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
Desplegar el DaemonSet
En esta sección, debes hacer lo siguiente:
- Crea el ConfigMap que almacena el procedimiento de inicialización.
- Despliega el DaemonSet que programa y ejecuta el procedimiento de inicialización.
DaemonSet hace lo siguiente:
- Configura un volumen que hace que el contenido de ConfigMap esté disponible para los contenedores que gestiona DaemonSet.
- Configura los volúmenes de las áreas del sistema de archivos privilegiadas del nodo de clúster subyacente. Estas áreas permiten que los contenedores que programa DaemonSet interactúen directamente con el nodo que los ejecuta.
- Programa y ejecuta un contenedor init que ejecuta el procedimiento de inicialización y, a continuación, se termina al completarse.
- Programa y ejecuta un contenedor que permanece inactivo y no consume recursos.
El contenedor inactivo asegura que un nodo se inicialice solo una vez. Los DaemonSets se han diseñado para que todos los nodos aptos ejecuten una copia de un pod. Si usas un contenedor normal, este ejecuta el procedimiento de inicialización y, a continuación, se cierra cuando se completa. Por diseño, el DaemonSet vuelve a programar el pod. Para evitar la reprogramación continua, DaemonSet primero ejecuta el procedimiento de inicialización en un contenedor init y, a continuación, deja un contenedor en ejecución.
El siguiente procedimiento de inicialización contiene operaciones con y sin privilegios. Con chroot
, puedes ejecutar comandos como si los estuvieras ejecutando directamente en el nodo, no solo dentro de un contenedor.
Te recomendamos que revises detenidamente cada procedimiento de inicialización, ya que podría alterar el estado de los nodos de tu clúster. Solo un pequeño grupo de personas debería tener derecho a modificar esos procedimientos, ya que pueden afectar en gran medida a la disponibilidad y la seguridad de tus clústeres.
Para desplegar el ConfigMap y el DaemonSet, haz lo siguiente:
En Cloud Shell, cambia el directorio de trabajo a
$HOME
:cd "$HOME"
Clona el repositorio de Git que contiene las secuencias de comandos y los archivos de manifiesto para implementar y configurar el procedimiento de inicialización:
git clone https://github.com/GoogleCloudPlatform/solutions-gke-init-daemonsets-tutorial
Cambia el directorio de trabajo por el directorio del repositorio recién clonado:
cd "$HOME"/solutions-gke-init-daemonsets-tutorial
Crea un ConfigMap para contener la secuencia de comandos de inicialización del nodo:
kubectl apply -f cm-entrypoint.yaml
Despliega el DaemonSet:
kubectl apply -f daemon-set.yaml
Verifica que se haya completado la inicialización del nodo:
kubectl get ds --watch
Espera a que se indique que el DaemonSet está listo y actualizado, como se muestra en un resultado similar al siguiente:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE node-initializer 3 3 3 3 3 <none> 2h
Validar y verificar el procedimiento de inicialización
Después de que cada nodo del clúster marcado con la etiqueta default-init
ejecute el procedimiento de inicialización, puede verificar los resultados.
En cada nodo, el procedimiento de verificación comprueba lo siguiente:
- Se ha conectado un disco adicional y está listo para usarse.
- Gestor de paquetes del sistema operativo del nodo que ha instalado los paquetes y las bibliotecas.
- Se cargan los módulos del kernel.
Ejecuta el procedimiento de verificación:
En Cloud Shell, ejecuta la secuencia de comandos de verificación:
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
Espera a que se ejecute la secuencia de comandos y comprueba que cada nodo se ha inicializado correctamente, tal como se indica en un resultado como el siguiente:
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)