Inicializar automaticamente os nós do GKE com o DaemonSets.


Neste tutorial, mostramos como personalizar os nós de um cluster do Google Kubernetes Engine (GKE) usando DaemonSets. Um DaemonSet garante que todos os nós (ou os nós selecionados) executem uma cópia de um pod. Essa abordagem permite usar as mesmas ferramentas para orquestrar as cargas de trabalho usadas para modificar os nós do GKE.

Se as ferramentas e os sistemas usados para inicializar os clusters forem diferentes das ferramentas e dos sistemas usados para executar as cargas de trabalho, você aumentará o esforço necessário para gerenciar o ambiente. Por exemplo, se você usa uma ferramenta de gerenciamento de configuração para inicializar os nós do cluster, você depende de um procedimento fora do ambiente de execução em que as outras cargas de trabalho são executadas.

O objetivo deste tutorial é ajudar administradores de sistemas, engenheiros de sistemas ou operadores de infraestrutura a simplificar a inicialização de clusters do Kubernetes.

Antes de ler esta página, você precisa conhecer:

Neste tutorial, você aprenderá a usar rótulos e seletores do Kubernetes para escolher qual procedimento de inicialização será executado com base nos rótulos aplicados a um nó. Nessas etapas, você implantará um DaemonSet que seja executado apenas em nós que tenham o rótulo default-init aplicado. No entanto, para demonstrar a flexibilidade desse mecanismo, crie outro pool de nós e aplique o rótulo alternative-init aos nós desse novo pool. No cluster, implante outro DaemonSet configurado para ser executado apenas em nós que tenham o rótulo alternative-init.

Além disso, é possível executar vários procedimentos de inicialização em cada nó, não apenas um. Aproveite esse mecanismo para estruturar melhor os procedimentos de inicialização, separando claramente as preocupações de cada um.

Neste tutorial, como exemplo, o procedimento de inicialização executa as seguintes ações em cada nó rotulado com o rótulo default-init:

  1. Anexa outro disco ao nó.
  2. Instala um conjunto de pacotes e bibliotecas usando o gerenciador de pacotes do sistema operacional do nó.
  3. Carrega um conjunto de módulos do kernel do Linux.

Objetivos

Neste tutorial, você realizará as seguintes ações:

  • Provisionar e configurar um cluster do GKE.
  • Preparar um descritor de DaemonSet para inicializar os nós no cluster.
  • Implantar o DaemonSet no cluster.
  • Verificar se os nós do cluster foram inicializados.

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.

Antes de começar

  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.

Inicializar o ambiente

Nesta seção, você realizará as ações a seguir:

  1. Ativar as APIs do Cloud necessárias.
  2. Provisionar uma conta de serviço com privilégios limitados para os nós no cluster do GKE.
  3. Preparar o cluster do GKE.
  4. Conceder privilégios de administração do cluster ao usuário.

Ativar APIs do Cloud

  1. Abra o Cloud Shell.

    ABRIR o Cloud Shell

  2. Selecione o projeto do Google Cloud:

    gcloud config set project project-id
    

    Substitua project-id pelo ID do projeto do Cloud que você criou ou selecionou para este tutorial.

  3. Ative a API Google Kubernetes Engine:

    gcloud services enable container.googleapis.com
    

Provisionar uma conta de serviço para gerenciar clusters do GKE

Nesta seção, você criará uma conta de serviço associada aos nós no cluster. Neste tutorial, os nós do GKE usam essa conta de serviço em vez da conta de serviço padrão. Como prática recomendada, conceda à conta de serviço apenas os papéis e as permissões de acesso necessários para executar o aplicativo.

Os papéis necessários para a conta de serviço são os seguintes:

  • Leitor do Monitoring (roles/monitoring.viewer). Esse papel fornece acesso somente leitura à API e ao console do Cloud Monitoring.
  • Gravador de métricas do Monitoring (roles/monitoring.metricWriter). Esse papel permite gravar dados de monitoramento.
  • Gravador de registros (roles/logging.logWriter). Esse papel concede apenas permissões suficientes para gravar registros.
  • Usuário da conta de serviço (roles/iam.serviceAccountUser). Esse papel concede acesso a contas de serviço em um projeto. Neste tutorial, o procedimento de inicialização representa a conta de serviço para executar operações com privilégios.
  • Administrador do Compute (roles/compute.admin). Esse papel fornece controle total de todos os recursos do Compute Engine. Neste tutorial, a conta de serviço precisa desse papel para anexar outros discos aos nós do cluster.

Para provisionar uma conta de serviço, siga estas etapas:

  1. No Cloud Shell, inicialize uma variável de ambiente que armazene o nome da conta de serviço:

    GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gke
    
  2. Crie uma conta de serviço:

    gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \
      --display-name="$GKE_SERVICE_ACCOUNT_NAME"
    
  3. Inicialize uma variável de ambiente que armazene o nome da conta de e-mail da conta de serviço:

    GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \
        --format='value(email)' \
        --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"
    
  4. Vincule os papéis de gerenciamento de identidade e acesso (IAM, na sigla em inglês) à conta de serviço:

    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 o cluster do GKE

Nesta seção, você iniciará o cluster do GKE, concederá permissões e finalizará a configuração do cluster.

Para demonstrar o conceito deste tutorial, um cluster com um número relativamente baixo de nós pequenos e de uso geral é suficiente. Crie um cluster com um pool de nós (o padrão). Em seguida, rotule todos os nós no pool de nós padrão com o rótulo default-init.

  • No Cloud Shell, crie e inicie um cluster do 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"
    

Implante o DaemonSet:

Nesta seção, você realizará as ações a seguir:

  1. Criar o ConfigMap que armazena o procedimento de inicialização.
  2. Implantar o DaemonSet que programa e executa o procedimento de inicialização.

O DaemonSet realiza as seguintes ações:

  1. Configura um volume que disponibiliza o conteúdo do ConfigMap para os contêineres que o DaemonSet processa.
  2. Configura os volumes para áreas de sistema de arquivos com privilégios do nó do cluster subjacente. Essas áreas permitem que os contêineres programados pelo DaemonSet interajam diretamente com o nó que os executa.
  3. Programa e executa um contêiner de inicialização que executa o procedimento de inicialização e é encerrado após a conclusão.
  4. Programa e executa um contêiner que permanece ocioso e não consome recursos.

O contêiner ocioso garante que um nó seja inicializado apenas uma vez. Os DaemonSets são projetados para que todos os nós qualificados executem uma cópia de um pod. Se você usar um contêiner normal, ele executará o procedimento de inicialização e será encerrado após a conclusão. Por questões de projeto, o DaemonSet reprograma o pod. Para evitar a "reprogramação contínua", o DaemonSet executa primeiro o procedimento de inicialização em um contêiner de inicialização e, em seguida, deixa um contêiner em execução.

O procedimento de inicialização a seguir contém operações com privilégios e sem privilégios. Ao usar chroot, é possível executar comandos como se estivesse executando-os diretamente no nó, não apenas dentro de um contêiner.

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

Recomendamos que você analise cuidadosamente cada procedimento de inicialização, porque o procedimento pode alterar o estado dos nós do cluster. Somente um pequeno grupo de indivíduos deve ter o direito de modificar esses procedimentos, porque eles podem afetar consideravelmente a disponibilidade e a segurança dos clusters.

Para implantar o ConfigMap e o DaemonSet, faça o seguinte:

  1. No Cloud Shell, altere o diretório de trabalho para o diretório $HOME:

    cd "$HOME"
    
  2. Clone o repositório do Git que contém os scripts e os arquivos de manifesto para implantar e configurar o procedimento de inicialização:

    git clone https://github.com/GoogleCloudPlatform/solutions-gke-init-daemonsets-tutorial
    
  3. Altere o diretório de trabalho para o diretório do repositório recém-clonado:

    cd "$HOME"/solutions-gke-init-daemonsets-tutorial
    
  4. Crie um ConfigMap para manter o script de inicialização do nó:

    kubectl apply -f cm-entrypoint.yaml
    
  5. Implante o DaemonSet:

    kubectl apply -f daemon-set.yaml
    
  6. Verifique se a inicialização do nó está concluída:

    kubectl get ds --watch
    

    Aguarde até que o DaemonSet seja reportado como pronto e atualizado, conforme indicado por uma resposta semelhante a esta:

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

Validar e verificar o procedimento de inicialização

Depois que cada nó do cluster marcado com o rótulo default-init executa o procedimento de inicialização, é possível verificar os resultados.

Para cada nó, o procedimento de verificação confere se:

  1. outro disco está anexado e pronto para ser usado;
  2. o gerenciador de pacotes do sistema operacional do nó instalou pacotes e bibliotecas;
  3. os módulos do kernel são carregados.

Execute o procedimento de verificação:

  • No Cloud Shell, execute o script de verificação:

    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
    

    Aguarde a execução do script e verifique se cada nó foi inicializado corretamente, conforme indicado por uma resposta como esta:

    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)
    

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, exclua o projeto criado para este tutorial. Se você criou um projeto dedicado para este tutorial, é possível excluí-lo totalmente. Se você usou um projeto existente, mas não quer excluí-lo, siga as etapas a seguir para limpar o projeto.

Limpar o projeto

Para limpar um projeto sem excluí-lo, remova os recursos criados neste tutorial.

  1. No Cloud Shell, exclua o cluster do GKE:

    gcloud container clusters delete ds-init-tutorial --quiet --region us-central1
    
  2. Exclua os outros discos que você criou como parte deste exemplo de procedimento de inicialização:

    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. Exclua a conta de serviço:

    gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
    
  4. Exclua o diretório do repositório clonado:

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

Excluir o projeto

A maneira mais fácil de eliminar o faturamento é excluir o projeto que você criou para o tutorial.

  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.

A seguir