이 튜토리얼에서는 DaemonSets를 사용하여 Google Kubernetes Engine(GKE) 클러스터의 노드를 맞춤설정하는 방법을 보여줍니다. DaemonSet는 모든 노드 또는 선택한 노드에서 포드의 복사본이 실행되도록 합니다. 클러스터에 새 노드가 추가되면 DaemonSet의 포드도 실행됩니다.
클러스터의 초기화에 사용하는 도구 및 시스템이 워크로드 실행에 사용하는 도구 및 시스템과 다를 경우 환경 관리 시간이 늘어날 수 있습니다. 예를 들어 구성 관리 도구를 사용하여 클러스터 노드를 초기화하면 나머지 워크로드가 실행되는 런타임 환경 범위를 벗어난 절차를 사용하게 됩니다. DaemonSet를 사용하면 GKE 노드를 수정하는 데 사용하는 것과 동일한 도구를 사용하여 워크로드를 오케스트레이션할 수 있습니다.
이 가이드의 목표는 시스템 관리자, 시스템 엔지니어 또는 인프라 운영자가 Kubernetes 클러스터 초기화를 간소화하도록 돕는 것입니다.
이 페이지를 읽기 전에 다음 사항을 숙지해야 합니다.
이 튜토리얼에서는 Kubernetes taint 및 톨러레이션을 사용하여 애플리케이션 워크로드가 노드에 예약되기 전에 DaemonSet에 의해 노드가 구성되도록 하는 방법을 알아봅니다.
목표
이 튜토리얼에서는 다음과 같은 작업을 수행하게 됩니다.
- GKE 클러스터를 프로비저닝합니다.
- 노드 구성을 적용하기 전에 워크로드가 예약되지 않도록 노드 풀에 taint를 설정합니다.
- 노드를 구성하고 taint를 삭제하는 DaemonSet를 배포합니다.
- 클러스터 노드가 구성되고 테인트가 삭제되었는지 확인합니다.
비용
이 문서에서는 비용이 청구될 수 있는 Google Cloud구성요소를 사용합니다.
프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요.
이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.
시작하기 전에
- Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
권한이 있는 DaemonSet 보안 영향
DaemonSet (또는 모든 포드)에서 securityContext: privileged: true 설정을 사용하는 것은 강력하지만 해당 포드의 대부분의 컨테이너 격리 경계를 사용 중지하므로 심각한 보안 문제가 발생할 수 있습니다. 다음과 같은 보안 제한사항과 이로 인해 발생하는 위험에 유의해야 합니다.
- 컨테이너 이스케이프 또는 호스트 손상: 권한이 있는 컨테이너 애플리케이션 또는 이미지 내의 취약점으로 인해 호스트 노드에서 루트 액세스가 직접 발생할 수 있습니다.
- 최소 권한 위반: 권한 모드는 모든 기능을 부여하며, 이는 특정 작업에 필요한 것보다 훨씬 많을 수 있습니다. 이러한 광범위한 액세스는 컨테이너가 손상될 경우 잠재적인 피해를 증가시킵니다.
- 노드 불안정화: 잘못된
sysctl값 또는rm -rf /host/boot와 같은 명령어 등 우발적이거나 악의적인 명령어가 권한이 있는 컨테이너 내에서 실행될 수 있습니다. 이러한 유형의 명령어는 호스트 노드 운영체제를 다운시키거나 손상시킬 수 있습니다. - 측면 이동: 권한이 있는 DaemonSet를 통해 한 노드를 손상시키면 공격자가 다른 노드, Kubernetes 컨트롤 플레인 또는 연결된 시스템을 공격할 수 있는 강력한 발판을 마련할 수 있습니다.
- 데이터 노출: 호스트 파일 시스템(
/)에 대한 무제한 액세스는 사용자 인증 정보, 키 또는 다른 포드에 속한 데이터(hostPath 볼륨을 사용하는 경우)를 포함하여 노드에 저장된 민감한 정보를 노출할 수 있습니다. - 공격 표면 증가: 권한이 있는 모드는 컨테이너 내에서 잠재적인 악용에 더 많은 호스트 커널 시스템 호출 및 기능을 노출합니다.
보안 위험을 방지하려면 다음 권장사항과 완화 조치를 숙지해야 합니다.
- 독점 모드 사용 방지: 가장 안전한 방법은
privileged: true설정을 완전히 피하는 것입니다. - Linux 기능 사용: 권한 상승이 필요한 경우 전체 권한 대신
securityContext.capabilities.add필드에서NET_ADMIN,SYS_ADMIN,SYS_MODULE과 같은 특정 Linux 기능을 부여할 수 있습니다. 이 접근 방식은 최소 권한의 원칙을 따르며, 광범위한 권한을 부여하는 것보다 권장됩니다. - 범위 제한: 컨테이너가 손상된 경우 잠재적 영향을 방지하기 위해 전용 노드 풀(오염되었을 수 있음)에서만 권한이 있는 DaemonSet을 실행합니다.
- 정책 시행: 정책 컨트롤러 또는 게이트키퍼와 같은 도구를 사용하여 권한이 있는 컨테이너 배포를 제한하거나, 감사하거나, 정당화해야 하는 정책을 만듭니다.
- 신뢰할 수 있는 이미지 스캔 및 사용: Binary Authorization 및 엄격한 이미지 스캔을 사용하여 검증되고 신뢰할 수 있는 컨테이너 이미지만 승격된 권한으로 실행되도록 합니다.
- 호스트 마운트 최소화: 필요한 특정 호스트 경로만 마운트하고 가능한 경우
readOnly: true를 사용합니다. 전체 루트 파일 시스템 (/)을 마운트하지 마세요. - 정기적으로 감사 실행:
privileged: true설정으로 실행되는 모든 워크로드를 정기적으로 검토합니다.
환경 부트스트랩
이 섹션에서는 다음과 같은 작업을 수행하게 됩니다.
- 필요한 Cloud API를 사용 설정합니다.
- GKE 클러스터의 노드에 대해 제한된 권한을 가진 서비스 계정을 프로비저닝합니다.
- GKE 클러스터를 준비합니다.
- 사용자 클러스터 관리 권한을 부여합니다.
Cloud API 사용 설정
Cloud Shell을 엽니다.
Google Cloud 프로젝트를 선택합니다.
gcloud config set project project-id
project-id를 이 튜토리얼용으로 만들거나 선택한Google Cloud 프로젝트의 ID로 바꿉니다.Kubernetes Engine API를 사용 설정합니다.
gcloud services enable container.googleapis.com
GKE 클러스터를 관리하기 위한 서비스 계정 프로비저닝
이 섹션에서는 클러스터의 노드와 연결된 서비스 계정을 만듭니다. 이 가이드에서 GKE 노드는 기본 서비스 계정 대신 이 서비스 계정을 사용합니다. 애플리케이션을 실행하는 데 필요한 역할과 액세스 권한을 서비스 계정에 부여하는 것이 가장 좋습니다.
서비스 계정에 필요한 역할은 다음과 같습니다.
- 모니터링 뷰어 역할 (
roles/monitoring.viewer). 이 역할은 모니터링 데이터에 대한 읽기 전용 액세스 권한을 부여합니다. - 모니터링 측정항목 작성자 역할(
roles/monitoring.metricWriter): 이 역할은 모니터링 데이터 쓰기를 허용합니다. - 로그 작성자 역할 (
roles/logging.logWriter): 이 역할은 로그를 작성할 수 있는 권한을 부여합니다.
서비스 계정을 프로비저닝하려면 다음 단계를 따르세요.
Cloud Shell에서 서비스 계정 이름을 저장하는 환경 변수를 초기화합니다.
GKE_SERVICE_ACCOUNT_NAME=ds-init-tutorial-gke서비스 계정을 만듭니다.
gcloud iam service-accounts create "$GKE_SERVICE_ACCOUNT_NAME" \ --display-name="$GKE_SERVICE_ACCOUNT_NAME"서비스 계정 이메일 계정 이름을 저장할 환경 변수를 초기화합니다.
GKE_SERVICE_ACCOUNT_EMAIL="$(gcloud iam service-accounts list \ --format='value(email)' \ --filter=displayName:"$GKE_SERVICE_ACCOUNT_NAME")"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/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
GKE 클러스터 준비
이 섹션에서는 GKE 클러스터를 실행하고, 권한을 부여하고, 클러스터 구성을 완료합니다.
이 튜토리얼에서는 비교적 적은 수의 작은 범용 노드가 있는 클러스터만으로도 이 튜토리얼의 개념을 보여줄 수 있습니다. 한 개의 노드 풀(기본값)로 클러스터를 만듭니다.
Cloud Shell에서 리전 GKE 클러스터를 만들고 실행합니다.
gcloud container clusters create ds-init-tutorial \ --enable-ip-alias \ --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 \ --location us-central1 \ --service-account="$GKE_SERVICE_ACCOUNT_EMAIL"
DaemonSet을 사용하여 노드 구성 적용
이 섹션에서는 노드 풀에 taint를 적용하여 구성이 완료되기 전에 워크로드가 노드에서 실행되지 않도록 합니다. 그런 다음 다음 작업을 실행하는 DaemonSet을 배포합니다.
- taint에 대한 톨러레이션(toleration)을 사용하여 taint된 노드에 포드를 예약합니다.
- 먼저
sysctl를 사용하여 노드 구성을 적용한 다음kubectl를 사용하여 노드에서 테인트를 삭제하는 권한이 있는 init 컨테이너를 실행합니다. taint를 삭제하면 워크로드에 대해 노드를 예약할 수 있습니다. - 구성하는 데 사용되는 포드가 DaemonSet에 의해 다시 예약되지 않도록 유휴 상태로 유지되며 리소스를 사용하지 않는 일시중지 컨테이너를 예약하고 실행합니다.
이 튜토리얼에서는 vm.max_map_count=262144 커널 매개변수를 예시 구성으로 적용합니다.
기본 노드 풀에 taint를 적용합니다.
gcloud container node-pools update default-pool \ --cluster=ds-init-tutorial \ --node-taints=node.config.status/stage=configuring:NoSchedule \ --region=us-central1이 taint를 사용하면 DaemonSet 포드와 같이 taint를 허용하는 포드만 이 노드 풀에 예약할 수 있습니다.
테인트가 적용되었는지 확인합니다.
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep Taints노드 상태에
node.config.status/stage=configuring:NoSchedule가 표시되어야 합니다.다음 매니페스트를
auto-untaint-daemonset.yaml로 저장합니다.# WARNING: This DaemonSet runs as privileged, which has significant # security implications. Only use this on clusters where you have # strict controls over what is deployed. --- apiVersion: v1 kind: ServiceAccount metadata: name: node-config-sa namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: node-patcher-role rules: - apiGroups: [""] resources: ["nodes"] # Permissions needed to read and remove a taint from the node. verbs: ["get", "patch", "update"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: node-config-binding subjects: - kind: ServiceAccount name: node-config-sa namespace: default roleRef: kind: ClusterRole name: node-patcher-role apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: DaemonSet metadata: name: auto-untaint-daemonset labels: app: auto-untaint-configurator spec: selector: matchLabels: app: auto-untaint-configurator updateStrategy: type: RollingUpdate template: metadata: labels: app: auto-untaint-configurator spec: serviceAccountName: node-config-sa hostPID: true # Toleration now matches the taint on your node. tolerations: - key: "node.config.status/stage" operator: "Equal" value: "configuring" effect: "NoSchedule" volumes: - name: host-root-fs hostPath: path: / initContainers: - name: configure-and-untaint image: ubuntu:22.04 # Using a standard container image. securityContext: privileged: true # Required for chroot and sysctl. env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName volumeMounts: - name: host-root-fs mountPath: /host command: ["/bin/bash", "-c"] args: - | # Using explicit error checking for each critical command. # Define the configuration and taint details. SYSCTL_PARAM="vm.max_map_count" SYSCTL_VALUE="262144" TAINT_KEY="node.config.status/stage" echo "Running configuration on node: ${NODE_NAME}" # 1. APPLY CONFIGURATION echo "--> Applying ${SYSCTL_PARAM}=${SYSCTL_VALUE}..." if ! chroot /host sysctl -w "${SYSCTL_PARAM}=${SYSCTL_VALUE}"; then echo "ERROR: Failed to apply sysctl parameter." >&2 exit 1 fi echo "--> Configuration applied successfully." # 2. UNTAINT THE NODE # This command removes the taint from the node this Pod is running on. echo "--> Untainting node ${NODE_NAME} by removing taint ${TAINT_KEY}..." if ! /host/home/kubernetes/bin/kubectl taint node "${NODE_NAME}" "${TAINT_KEY}:NoSchedule-"; then echo "ERROR: Failed to untaint the node." >&2 exit 1 fi echo "--> Node has been untainted and is now schedulable." # The main container is minimal; it just keeps the Pod running. containers: - name: pause-container image: registry.k8s.io/pause:3.9이 매니페스트는 노드에서 테인트를 삭제할 권한을 DaemonSet에 부여하는 ServiceAccount, ClusterRole, ClusterRoleBinding을 만듭니다. DaemonSet는
configuring:NoScheduletaint를 허용하는 각 노드에 포드를 배포합니다. 이 포드는sysctl구성 (vm.max_map_count=262144)을 적용하고 노드 테인트를 삭제하는 권한 있는 init 컨테이너를 실행하여 노드를 예약 가능하게 만듭니다. 그러면 일시중지 컨테이너가 포드를 계속 실행하기 시작합니다.init 컨테이너는 권한 모드에서 실행되므로 보안에 영향을 미칩니다. 자세한 내용은 권한이 있는 DaemonSet 장단점 및 보안 제한사항을 참조하세요.
매니페스트를 적용합니다.
kubectl apply -f auto-untaint-daemonset.yamlDaemonSet 포드가 생성되었는지 확인하고
Running상태가 될 때까지 기다립니다.kubectl get pods -l app=auto-untaint-configurator -o wideRunning상태는 init 컨테이너가 성공적으로 완료되었음을 나타냅니다. 다음 섹션에서 초기화를 확인할 수 있도록 포드 이름을 기록해 둡니다.
초기화 절차의 검증 및 확인
노드 구성이 완료되면 로그를 확인하여 결과를 확인할 수 있습니다.
포드 중 하나의 초기화 컨테이너 로그를 확인하여 출력을 확인합니다.
kubectl logs POD_NAME -c configure-and-untaintPOD_NAME을 포드 이름으로 바꿉니다.구성 성공 및 노드 테인트 해제를 나타내는 출력이 표시됩니다.
테인트가 삭제되었는지 확인합니다.
kubectl describe nodes -l cloud.google.com/gke-nodepool=default-pool | grep Taints노드 상태에
Taints: <none>가 표시되거나node.config.status/stage키가 있는 taint가 표시되어야 합니다.
삭제
이 튜토리얼에서 사용한 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 이 튜토리얼에서 만든 프로젝트를 삭제하면 됩니다. 이 가이드 전용으로 프로젝트를 만들었으면 전체 프로젝트를 삭제해도 됩니다. 기존 프로젝트를 사용했지만 삭제하지 않으려면 다음 단계를 수행하여 프로젝트를 정리합니다.
프로젝트 정리
프로젝트를 삭제하지 않고 정리하려면 이 가이드에서 만든 리소스를 삭제해야 합니다.
Cloud Shell에서 GKE 클러스터를 삭제합니다.
gcloud container clusters delete ds-init-tutorial --quiet --region us-central1서비스 계정을 삭제합니다.
gcloud iam service-accounts delete "$GKE_SERVICE_ACCOUNT_EMAIL" --quiet
프로젝트 삭제
청구되지 않도록 하는 가장 쉬운 방법은 가이드에서 만든 프로젝트를 삭제하는 것입니다.
- Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.
- 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
- 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.
다음 단계
- GKE 자세히 알아보기
- 보안 소프트웨어 공급망 구현
- GKE 클러스터의 보안을 강화하는 방법 알아보기
- Google Cloud에 대한 참조 아키텍처, 다이어그램, 권장사항 살펴보기 Cloud 아키텍처 센터 살펴보기