DaemonSet を使用して GKE ノードを自動的にブートストラップする


このチュートリアルでは、DaemonSet を使用して Google Kubernetes Engine(GKE)クラスタのノードをカスタマイズする方法について説明します。DaemonSet によって、すべての(または選択された)ノードで Pod のコピーが実行されるようになります。この方法では、GKE ノードを変更するために使用するのと同じツールを使用してワークロードのオーケストレーションを行えます。

クラスタの初期化に使用するツールとシステムが、ワークロードの実行に使用するツールとシステムとは異なる場合は、環境の管理にかかる労力が増えます。たとえば、構成管理ツールを使用してクラスタノードを初期化する場合は、残りのワークロードが実行されるランタイム環境外の手順に依存します。

このチュートリアルの目的は、システム管理者、システム エンジニア、インフラストラクチャ オペレーターが Kubernetes クラスタの初期化を合理化することです。

このページを読む前に、次のことを理解しておいてください。

このチュートリアルでは、Kubernetes のラベルとセレクタを使用して、ノードに適用されるラベルに基づいて実行する初期化手順を選択する方法を確認します。こうした手順では、default-init ラベルが適用されたノードでのみ実行するように DaemonSet をデプロイします。ただし、このメカニズムの柔軟性を示すために、別のノードプールを作成し、この新しいプール内のノードに alternative-init ラベルを適用できます。クラスタ内で、alternative-init ラベルを持つノードでのみ実行するように構成された別の DaemonSet をデプロイできます。

また、各ノードで、1 つだけではなく複数の初期化手順を行うこともできます。このメカニズムを利用して、初期化手順を効率的に構造化し、それぞれの懸念を明確に区別できます。

たとえば、このチュートリアルの初期化手順では default-init ラベルの付いた各ノードで次のアクションを実行します。

  1. 追加のディスクをノードにアタッチします。
  2. ノードのオペレーティング システムのパッケージ管理システムを使用して、一連のパッケージとライブラリをインストールします。
  3. 一連の Linux カーネル モジュールを読み込みます。

目標

このチュートリアルでは、次のことを行います。

  • GKE クラスタをプロビジョニングして構成する。
  • クラスタ内のノードを初期化する DaemonSet 記述子を準備する。
  • DaemonSet をクラスタにデプロイする。
  • クラスタノードが初期化されていることを確認する。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい 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 APIs を有効にする。
  2. GKE クラスタ内のノードに対する制限された権限を持つサービス アカウントをプロビジョニングする。
  3. GKE クラスタを準備する。
  4. ユーザーにクラスタ管理者権限を付与する。

Cloud APIs を有効にする

  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 ノードでデフォルトのサービス アカウントの代わりにこのサービス アカウントを使用します。ベスト プラクティスとして、アプリケーションの実行に必要なロールとアクセス権のみをサービス アカウントに付与することをおすすめします。

サービス アカウントに必要なロールは次のとおりです。

  • モニタリング閲覧者のロール(roles/monitoring.viewer)。このロールでは、Cloud Monitoring のコンソールと API への読み取り専用アクセス権が付与されます。
  • モニタリング指標の書き込みロール(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 クラスタを起動し、権限を付与して、クラスタ構成を終了します。

このチュートリアルのコンセプトのデモを行うには、汎用ノードの数が比較的少ない小規模なクラスタで十分です。1 つのノードプール(デフォルトのノードプール)があるクラスタを作成します。次に、デフォルトのノードプール内のすべてのノードに 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. 初期化手順を行う init コンテナのスケジュールを設定して実行し、完了時に終了します。
  4. アイドル状態を維持し、リソースを消費しないコンテナのスケジュールを設定して実行します。

アイドル状態のコンテナにより、ノードが 1 回だけ初期化されます。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.

次のステップ