使用 DaemonSet 自動啟動 GKE 節點


本教學課程說明如何使用 DaemonSets 自訂 Google Kubernetes Engine (GKE) 叢集的節點。DaemonSet 可確保所有 (或選取的) 節點都執行 Pod 的副本。這種做法可讓您使用相同的工具來協調工作負載,就像修改 GKE 節點一樣。

如果您用來初始化叢集的工具和系統,與用來執行工作負載的工具和系統不同,管理環境所需的工作量就會增加。舉例來說,如果您使用設定管理工具初始化叢集節點,您會依賴程序,而該程序位於執行階段環境之外,其餘工作負載則是在該環境中執行。

本教學課程的目標是協助系統管理員、系統工程師或基礎架構操作員,簡化 Kubernetes 叢集的初始化作業。

閱讀本頁面之前,請先熟悉下列概念:

在本教學課程中,您將瞭解如何使用 Kubernetes 標籤和選取器,根據套用至節點的標籤選擇要執行的初始化程序。在這些步驟中,您會部署 DaemonSet,只在套用 default-init 標籤的節點上執行。不過,為了展示這項機制的彈性,您可以建立另一個節點集區,並將 alternative-init 標籤套用至這個新集區中的節點。然後在叢集中部署另一個 DaemonSet,並設定為只在具有 alternative-init 標籤的節點上執行。

此外,您可以在每個節點上執行多個初始化程序,而不只是單一程序。您可以運用這項機制,更妥善地建構初始化程序,清楚區分各程序的關注事項。

在本教學課程中,初始化程序會對標示 default-init 標籤的每個節點執行下列動作:

  1. 將額外磁碟連接至節點。
  2. 使用節點的作業系統套件管理員安裝一組套件和程式庫。
  3. 載入一組 Linux 核心模組。

目標

在本教學課程中,您將執行下列操作:

  • 佈建及設定 GKE 叢集。
  • 準備 DaemonSet 描述元,初始化叢集中的節點。
  • 在叢集中部署 DaemonSet。
  • 確認叢集節點已初始化。

費用

在本文件中,您會使用 Google Cloud的下列計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用資格。

完成本文所述工作後,您可以刪除已建立的資源,避免繼續計費。詳情請參閱清除所用資源一節。

事前準備

  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.

啟動環境

在本節中,執行以下操作:

  1. 啟用必要的 Cloud API
  2. 為 GKE 叢集中的節點佈建權限受限的服務帳戶
  3. 準備 GKE 叢集。
  4. 授予使用者叢集管理權限。

啟用 Cloud API

  1. 開啟 Cloud Shell。

    開啟 Cloud Shell

  2. 選取 Google Cloud 專案:

    gcloud config set project project-id
    

    project-id 替換為您為本教學課程建立或選取的Google Cloud 專案 ID。

  3. 啟用 Google Kubernetes Engine API:

    gcloud services enable container.googleapis.com
    

佈建服務帳戶以管理 GKE 叢集

在本節中,您將建立與叢集節點相關聯的服務帳戶。在本教學課程中,GKE 節點會使用此服務帳戶,而非預設服務帳戶。最佳做法是只授予服務帳戶執行應用程式所需的角色和存取權限

服務帳戶必須擁有以下角色:

  • Monitoring 檢視者角色 (roles/monitoring.viewer)。這個角色提供 Cloud Monitoring 主控台和 API 的唯讀存取權。
  • Monitoring 指標寫入者角色 (roles/monitoring.metricWriter)。這個角色允許寫入監控資料。
  • 記錄寫入者角色 (roles/logging.logWriter)。這個角色只會授予寫入記錄的足夠權限。
  • 服務帳戶使用者角色 (roles/iam.serviceAccountUser)。這個角色可授予專案中服務帳戶的存取權。在本教學課程中,初始化程序會模擬服務帳戶,以執行具備權限的操作。
  • Compute 管理員角色 (roles/compute.admin)。這個角色提供所有 Compute Engine 資源的完整控制權。在本教學課程中,服務帳戶需要這個角色,才能將額外磁碟附加至叢集節點。

如要佈建服務帳戶,請按照下列步驟操作:

  1. 在 Cloud Shell 中,初始化儲存服務帳戶名稱的環境變數:

    GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gke
    
  2. 建立服務帳戶:

    gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \
      --display-name="$GKE_SERVICE_ACCOUNT_NAME"
    
  3. 初始化儲存服務帳戶電子郵件名稱的環境變數:

    GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \
        --format='value(email)' \
        --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"
    
  4. 將 Identity and Access Management (IAM) 角色繫結至服務帳戶:

    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
    

準備 GKE 叢集

在本節中,您將啟動 GKE 叢集、授予權限並完成叢集設定。

在本教學課程中,叢集只要有相對較少的節點,且節點屬於小型一般用途,就足以說明教學課程的概念。您建立的叢集會包含一個節點集區 (預設節點集區)。然後使用 default-init 標籤,為預設節點集區中的所有節點加上標籤。

  • 在 Cloud Shell 中建立並啟動地區 GKE 叢集:

    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"
    

部署 DaemonSet

在本節中,執行以下操作:

  1. 建立儲存初始化程序的 ConfigMap
  2. 部署 DaemonSet,排定並執行初始化程序。

DaemonSet 會執行下列作業:

  1. 設定磁碟區,讓 DaemonSet 處理的容器可存取 ConfigMap 的內容。
  2. 設定基礎叢集節點的受保護檔案系統區域磁碟區。這些區域可讓 DaemonSet 排程的容器直接與執行這些容器的節點互動。
  3. 排定及執行初始化容器,該容器會執行初始化程序,完成後即終止。
  4. 排定及執行閒置容器,不會耗用任何資源。

閒置容器可確保節點只會初始化一次。DaemonSet 的設計是讓所有符合資格的節點都執行 Pod 副本。如果您使用一般容器,該容器會執行初始化程序,完成後就會終止。根據設計,DaemonSet 會重新排定 Pod 的時間。為避免「持續重新排程」,DaemonSet 會先在 init 容器中執行初始化程序,然後讓容器保持執行狀態。

下列初始化程序包含具備和不具備權限的操作。使用 chroot 時,您可以執行指令,就像直接在節點上執行指令一樣,而不只是在容器內執行。

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

建議您仔細檢查每個初始化程序,因為程序可能會變更叢集節點的狀態。只有少數人有權修改這些程序,因為這些程序會大幅影響叢集的可用性和安全性。

如要部署 ConfigMap 和 DaemonSet,請執行下列步驟:

  1. 在 Cloud Shell 中,將工作目錄變更為 $HOME 目錄:

    cd "$HOME"
    
  2. 複製 Git 存放區,當中包含用於部署及設定初始化程序的指令碼和資訊清單檔案:

    git clone https://github.com/GoogleCloudPlatform/solutions-gke-init-daemonsets-tutorial
    
  3. 將工作目錄變更為新複製的存放區目錄:

    cd "$HOME"/solutions-gke-init-daemonsets-tutorial
    
  4. 建立 ConfigMap 以保存節點初始化指令碼:

    kubectl apply -f cm-entrypoint.yaml
    
  5. 部署 DaemonSet:

    kubectl apply -f daemon-set.yaml
    
  6. 確認已完成節點初始化:

    kubectl get ds --watch
    

    等待 DaemonSet 已備妥且為最新版本的通知,其輸出如下:

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

驗證並確認初始化程序

標示 default-init 標籤的叢集節點執行初始化程序後,您就可以驗證結果。

驗證程序會檢查每個節點是否符合下列條件:

  1. 已連接其他磁碟,隨時可供使用。
  2. 節點的作業系統套件管理員安裝的套件和程式庫。
  3. 已載入核心模組。

執行驗證程序:

  • 在 Cloud Shell 中執行驗證指令碼:

    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
    

    等待指令碼執行完畢,並確認每個節點都已正確初始化,如以下輸出內容所示:

    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)
    

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的相關費用,請刪除您為本教學課程建立的專案。如果您是特地為本教學課程建立專案,可以將其完全刪除。如果您使用的是現有專案,但不想刪除專案,請按照下列步驟清理專案

清除專案

如要在不刪除專案的情況下清除資源,請移除您在本教學課程中建立的資源。

  1. 在 Cloud Shell 中刪除 GKE 叢集:

    gcloud container clusters delete ds-init-tutorial --quiet --region us-central1
    
  2. 刪除您在本範例初始化程序中建立的額外磁碟:

    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. 刪除服務帳戶:

    gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
    
  4. 刪除複製的存放區目錄:

    rm -rf "$HOME"/solutions-gke-init-daemonsets-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.

後續步驟