DaemonSet으로 GKE 노드를 자동으로 부트스트랩

Project: /architecture/_project.yaml Book: /architecture/_book.yaml Refresh_date: 2023-11-03 Hide_from_catalogs: True

이 가이드에서는 DamonSet를 사용하여 Google Kubernetes Engine(GKE) 클러스터의 노드를 맞춤설정하는 방법을 보여줍니다. DaemonSet는 모든 노드 또는 선택한 노드에서 Pod의 복사본이 실행되도록 합니다. 이 접근 방식을 사용하면 GKE 노드를 수정할 때와 동일한 도구를 사용하여 워크로드를 조정할 수 있습니다.

클러스터의 초기화에 사용하는 도구 및 시스템이 워크로드 실행에 사용하는 도구 및 시스템과 다를 경우 환경 관리 시간이 늘어날 수 있습니다. 예를 들어 구성 관리 도구를 사용하여 클러스터 노드를 초기화하면 나머지 워크로드가 실행되는 런타임 환경 범위를 벗어난 절차를 사용하게 됩니다.

이 가이드의 목표는 시스템 관리자, 시스템 엔지니어 또는 인프라 운영자가 Kubernetes 클러스터 초기화를 간소화하도록 돕는 것입니다.

이 가이드를 진행하려면 다음 도구에 익숙해야 합니다.

이 가이드에서는 Kubernetes 라벨 및 선택기를 사용하여 노드에 적용되는 라벨을 기반으로 실행할 초기화 절차를 선택하는 방법을 알아봅니다. 이 단계에서는 default-init 라벨이 적용된 노드에서만 실행되도록 DaemonSet를 배포합니다. 그러나 이 메커니즘의 유연성을 입증하기 위해 또 다른 노드 풀을 만들고 이 풀의 노드에 alternative-init 라벨을 적용할 수 있습니다. 그런 다음 클러스터에서 alternative-init 라벨이 있는 노드에서만 실행되도록 구성된 또 다른 DaemonSet를 배포할 수 있습니다.

또한 한 개의 노드가 아닌 각 노드에서 여러 초기화 절차를 실행할 수 있습니다. 이 메커니즘을 활용하면 보다 원활하게 초기화 절차를 구성하고 각 절차의 우려사항을 명확하게 구분할 수 있습니다.

예를 들어 이 가이드에서 초기화 절차는 default-init 라벨이 지정된 각 노드에서 다음 작업을 수행합니다.

  1. 노드에 추가 디스크를 연결합니다.
  2. 노드의 운영체제 패키지 관리자를 사용하여 패키지 및 라이브러리 세트를 설치합니다.
  3. Linux 커널 모듈 세트를 로드합니다.

목표

이 가이드에서는 다음과 같은 작업을 수행하게 됩니다.

  • GKE 클러스터를 프로비저닝하고 구성합니다.
  • 클러스터에서 노드를 초기화하기 위해 DaemonSet 설명자를 준비합니다.
  • 클러스터에 DaemonSet를 배포합니다.
  • 클러스터 노드가 초기화되었는지 확인합니다.

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  4. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  5. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

환경 부트스트랩

이 섹션에서는 다음과 같은 작업을 수행하게 됩니다.

  1. 필요한 Cloud API를 사용 설정합니다.
  2. GKE 클러스터의 노드에서 제한된 권한을 가진 서비스 계정을 프로비저닝합니다.
  3. GKE 클러스터를 준비합니다.
  4. 사용자 클러스터 관리 권한을 부여합니다.

Cloud API 사용 설정

  1. Cloud Shell을 엽니다.

    Cloud Shell 열기

  2. Google Cloud 프로젝트를 선택합니다.

    gcloud config set project project-id
    

    이 튜토리얼용으로 만들거나 선택한 Google Cloud 프로젝트의 ID로 project-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 클러스터를 실행하고, 권한을 부여하고, 클러스터 구성을 완료합니다.

이 가이드에서는 비교적 적은 수의 작은 범용 노드가 있는 클러스터만으로도 이 가이드의 개념을 보여줄 수 있습니다. 한 개의 노드 풀(기본값)로 클러스터를 만듭니다. 그런 다음 기본 노드 풀의 모든 노드에 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는 우선 초기화 컨테이너에서 초기화 절차를 실행한 다음 컨테이너를 실행 상태로 둡니다.

다음 초기화 절차에는 권한 있는 작업과 권한이 없는 작업이 포함되어 있습니다. 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. Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

다음 단계