Inicia automáticamente los nodos de GKE con DaemonSets.


En este instructivo, se muestra cómo personalizar los nodos de un clúster de Google Kubernetes Engine (GKE) mediante DaemonSets. Un DaemonSet garantiza que todos los nodos (o los nodos seleccionados) ejecuten una copia de un Pod. Este enfoque te permite usar las mismas herramientas a fin de organizar las cargas de trabajo que usas para modificar los nodos de GKE.

Si las herramientas y los sistemas que usas cuando inicializas los clústeres son diferentes a las herramientas y a los sistemas que usas a fin de 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 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 etiquetas y selectores de Kubernetes a fin de elegir qué procedimiento de inicialización ejecutar en función de las etiquetas que se aplican a un nodo. En estos pasos, debes implementar un DaemonSet para ejecutarlo solo en los nodos que tienen aplicada la etiqueta default-init. Sin embargo, a fin de demostrar la flexibilidad de este mecanismo, puedes crear otro grupo de nodos y aplicarles la etiqueta alternative-init. En el clúster, podrías implementar otro DaemonSet configurado para ejecutarse solo en los nodos que tengan la etiqueta alternative-init.

Además, puedes ejecutar varios procedimientos de inicialización en cada nodo, no solo uno. Puedes aprovechar este mecanismo para estructurar mejor los procedimientos de inicialización y separar de forma clara las prioridades de cada uno.

En este instructivo, como ejemplo, el procedimiento de inicialización realiza las siguientes acciones en cada nodo con la etiqueta default-init:

  1. Conecta un disco adicional al nodo.
  2. Instala un conjunto de paquetes y bibliotecas mediante el administrador de paquetes del sistema operativo del nodo.
  3. Carga un conjunto de módulos de kernel de Linux.

Objetivos

En este instructivo, harás lo que se indica a continuación:

  • Aprovisionar y configurar un clúster de GKE
  • Preparar un descriptor DaemonSet para inicializar los nodos en el clúster
  • Implementar el DaemonSet en el clúster
  • Verificar que se hayan inicializado los nodos del clúster

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. Es posible que los usuarios nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure 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.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

Inicia el entorno

En esta sección, harás lo siguiente:

  1. Habilita las API de Cloud necesarias.
  2. Aprovisiona una cuenta de servicio con privilegios limitados para los nodos en el clúster de GKE.
  3. Prepara el clúster de GKE.
  4. Otorga al usuario privilegios de administrador de clústeres.

Habilita las API de Cloud

  1. Abre Cloud Shell

    Abrir Cloud Shell

  2. Selecciona el proyecto de Google Cloud:

    gcloud config set project project-id
    

    Reemplaza project-id por el ID del proyecto de Google Cloud que creaste o seleccionaste para este instructivo.

  3. Habilita la API de Google 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.

Los roles 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 la API y la consola de Cloud Monitoring.
  • 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 los permisos suficientes para escribir registros.
  • Función de usuario de cuenta de servicio (roles/iam.serviceAccountUser). Esta función otorga acceso a las cuentas de servicio en un proyecto. En este instructivo, el procedimiento de inicialización usa la identidad de la cuenta de servicio para ejecutar operaciones privilegiadas.
  • La función de administrador de Compute (roles/compute.admin). Esta función proporciona control total sobre todos los recursos de Compute Engine. En este instructivo, la cuenta de servicio necesita esta función para conectar discos adicionales a los nodos del clúster.

Para aprovisionar una cuenta de servicio, sigue estos pasos:

  1. 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
    
  2. Crea una cuenta de servicio:

    gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \
      --display-name="$GKE_SERVICE_ACCOUNT_NAME"
    
  3. 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")"
    
  4. 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/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 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). Luego, debes etiquetar todos los nodos en el 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 \
        --region us-central1 \
        --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
    

Implementa el DaemonSet

En esta sección, harás lo siguiente:

  1. Crear el ConfigMap que almacene el procedimiento de inicialización
  2. Implementar el DaemonSet que programe y ejecute el procedimiento de inicialización

El DaemonSet hace lo siguiente:

  1. Configura un volumen que hace que el contenido de ConfigMap esté disponible para los contenedores que controla DaemonSet.
  2. Configura los volúmenes para las áreas del sistema de archivos privilegiadas del nodo del clúster subyacente. Estas áreas permiten que los contenedores que programa DaemonSet interactúen directamente con el nodo que los ejecuta.
  3. Programa y ejecuta un contenedor init que ejecute el procedimiento de inicialización y, luego, finalice cuando se complete.
  4. Programa y ejecuta un contenedor que permanezca inactivo y no consuma recursos.

El contenedor inactivo garantiza que un nodo se inicialice solo una vez. Los DaemonSets están diseñados para que todos los nodos aptos ejecuten una copia de un Pod. Si usas un contenedor normal, ese contenedor ejecutará el procedimiento de inicialización y, luego, finalizará cuando se complete. Por diseño, el DaemonSet reprograma el Pod. Para evitar la “reprogramación continua”, el DaemonSet primero ejecuta el procedimiento de inicialización en un contenedor init y, luego, deja un contenedor en ejecución.

El siguiente procedimiento de inicialización contiene operaciones con y sin privilegios. Mediante chroot, puedes ejecutar comandos como si los ejecutaras directamente en el nodo, no solo dentro de un contenedor.

# 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
...

Te recomendamos que revises con cuidado cada procedimiento de inicialización, ya que podría alterar el estado de los nodos del clúster. Solo un pequeño grupo de personas debe tener derecho a modificar esos procedimientos, debido a que estos pueden afectar en gran medida la disponibilidad y la seguridad de los clústeres.

Para implementar el ConfigMap y el DaemonSet, haz lo siguiente:

  1. En Cloud Shell, cambia el directorio de trabajo al directorio $HOME:

    cd "$HOME"
    
  2. 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
    
  3. Cambia el directorio de trabajo al directorio del repositorio recién clonado:

    cd "$HOME"/solutions-gke-init-daemonsets-tutorial
    
  4. Crea un ConfigMap para guardar la secuencia de comandos de inicialización del nodo:

    kubectl apply -f cm-entrypoint.yaml
    
  5. Implementa el DaemonSet:

    kubectl apply -f daemon-set.yaml
    
  6. Verifica si se completó la inicialización del nodo:

    kubectl get ds --watch
    

    Espera a que se notifique que el DaemonSet está listo y actualizado, como lo indica 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
    

Valida y verifica 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, puedes verificar los resultados.

Para cada nodo, el procedimiento de verificación comprobará la siguiente información:

  1. Que haya un disco adicional conectado y listo para usar.
  2. Que el administrador de paquetes del sistema operativo del nodo haya instalado los paquetes y las bibliotecas.
  3. Que estén cargados los módulos de 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 la secuencia de comandos se ejecute y verifica que cada nodo se haya inicializado de forma correcta, como lo indica el resultado que se ve de la siguiente manera:

    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)
    

Realiza una limpieza

Para evitar que se apliquen cargos a la cuenta de Google Cloud por los recursos que usaste en este instructivo, puedes borrar el proyecto que creaste. 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.

  1. En Cloud Shell, borra el clúster de GKE:

    gcloud container clusters delete ds-init-tutorial --quiet --region us-central1
    
  2. Borra los discos adicionales que creaste como parte de este procedimiento de inicialización de ejemplo:

    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. Borra la cuenta de servicio:

    gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
    
  4. Borra el directorio del repositorio clonado:

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

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Próximos pasos