이 튜토리얼에서는 DaemonSets를 사용하여 Google Kubernetes Engine (GKE) 클러스터의 노드를 맞춤설정하는 방법을 보여줍니다. DaemonSet는 모든 노드 또는 선택한 노드에서 포드의 복사본이 실행되도록 합니다. 클러스터에 새 노드가 추가되면 DaemonSet의 포드도 실행됩니다.
클러스터의 초기화에 사용하는 도구 및 시스템이 워크로드 실행에 사용하는 도구 및 시스템과 다를 경우 환경 관리 시간이 늘어날 수 있습니다. 예를 들어 구성 관리 도구를 사용하여 클러스터 노드를 초기화하면 나머지 워크로드가 실행되는 런타임 환경 범위를 벗어난 절차를 사용하게 됩니다. DaemonSet를 사용하면 GKE 노드를 수정할 때와 동일한 도구를 사용하여 워크로드를 조정할 수 있습니다.
이 가이드의 목표는 시스템 관리자, 시스템 엔지니어 또는 인프라 운영자가 Kubernetes 클러스터 초기화를 간소화하도록 돕는 것입니다.
이 페이지를 읽기 전에 다음 사항을 숙지해야 합니다.
이 튜토리얼에서는 Kubernetes taint 및 톨러레이션(toleration)을 사용하여 애플리케이션 워크로드를 노드에 예약하기 전에 DaemonSet로 노드를 구성하는 방법을 알아봅니다.
목표
이 튜토리얼에서는 다음과 같은 작업을 수행하게 됩니다.
- GKE 클러스터를 프로비저닝합니다.
- 노드 구성을 적용하기 전에 워크로드 예약이 되지 않도록 노드 풀에 taint를 적용합니다.
- 노드를 구성하고 taint를 삭제하는 DaemonSet를 배포합니다.
- 클러스터 노드가 구성되고 taint가 삭제되었는지 확인합니다.
비용
이 문서에서는 비용이 청구될 수 있는 구성요소를 사용합니다 Google Cloud.
프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요.
이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.
시작하기 전에
- 계정에 로그인합니다. Google Cloud 를 처음 사용하는 경우 Google Cloud 계정을 만들어 실제 시나리오에서 제품이 어떻게 작동하는지 평가하세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $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 기능을 부여할 수 있습니다. 이 접근 방식은 광범위한 권한을 부여하는 것보다 권장되는 최소 권한 원칙을 따릅니다. - 범위 제한: 컨테이너가 손상된 경우 잠재적 영향을 포함하도록 전용으로 사용되며 taint가 적용될 수 있는 노드 풀에서만 권한이 있는 DaemonSet를 실행합니다.
- 정책 적용: 정책 컨트롤러 또는 Gatekeeper와 같은 도구를 사용하여 권한이 있는 컨테이너 배포를 제한, 감사 또는 정당화해야 하는 정책을 만듭니다.
- 신뢰할 수 있는 이미지 검사 및 사용: 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을 사용하여 노드에서 taint를 삭제하는 권한이 있는 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를 허용하는 포드만 이 노드 풀에 예약할 수 있습니다.
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에 노드에서 taint를 삭제할 수 있는 권한을 부여하기 위해 ServiceAccount, ClusterRole, ClusterRoleBinding을 만듭니다. DaemonSet는
configuring:NoScheduletaint를 허용하는 각 노드에 포드를 배포합니다. 이 포드는sysctl구성 (vm.max_map_count=262144)을 적용하고 노드 taint를 삭제하는 권한이 있는 init 컨테이너를 실행하여 노드를 예약할 수 있도록 합니다. 그런 다음 일시중지 컨테이너가 포드를 계속 실행하기 시작합니다.init 컨테이너는 보안 영향을 미치는 권한이 있는 모드에서 실행됩니다. 자세한 내용은 권한이 있는 DaemonSet 절충안 및 보안 제한사항을 참조하세요.
매니페스트를 적용합니다.
kubectl apply -f auto-untaint-daemonset.yamlDaemonSet 포드가 생성되었는지 확인하고
Running상태가 될 때까지 기다립니다.kubectl get pods -l app=auto-untaint-configurator -o wideRunning상태는 init 컨테이너가 성공적으로 완료되었음을 나타냅니다. 다음 섹션에서 초기화를 확인할 수 있도록 포드 이름을 기록해 둡니다.
초기화 절차의 검증 및 확인
노드 구성이 완료되면 로그를 확인하여 결과를 확인할 수 있습니다.
포드 중 하나의 init 컨테이너 로그를 확인하여 출력을 확인합니다.
kubectl logs POD_NAME -c configure-and-untaintPOD_NAME을 포드 이름으로 바꿉니다.구성 및 노드 taint 해제가 성공했음을 나타내는 출력이 표시되어야 합니다.
taint가 삭제되었는지 확인합니다.
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 아키텍처 센터 살펴보기