GKE Sandbox로 워크로드 실행

이 페이지에서는 Pod의 컨테이너가 알 수 없는 또는 신뢰할 수 없는 코드를 실행하거나 노드에서 추가 격리가 필요한 경우 GKE Sandbox를 사용하여 노드의 호스트 커널을 보호하는 방법을 설명합니다.

GKE Sandbox 사용 설정

새 클러스터 또는 기존 클러스터에서 GKE Sandbox를 사용 설정할 수 있습니다.

시작하기 전에

이 작업을 준비하려면 다음 단계를 완료하세요.

  • Google Kubernetes Engine API가 사용 설정되었는지 확인합니다.
  • Google Kubernetes Engine API 사용 설정
  • Cloud SDK가 설치되었는지 확인합니다.
  • 기본 프로젝트 ID를 설정합니다.
    gcloud config set project [PROJECT_ID]
  • 영역 클러스터를 사용하는 경우 기본 컴퓨팅 영역을 설정합니다.
    gcloud config set compute/zone [COMPUTE_ZONE]
  • 리전 클러스터를 사용하는 경우 기본 컴퓨팅 리전을 설정합니다.
    gcloud config set compute/region [COMPUTE_REGION]
  • gcloud를 최신 버전으로 업데이트합니다.
    gcloud components update
  • GKE Sandbox를 사용하려면 클러스터 마스터 및 노드에 GKE v1.12.7-gke.17 이상 또는 v1.13.5-gke.15 이상이 필요합니다.
  • gcloud 명령어 버전이 243.0.0 이상인지 확인합니다.

새 클러스터에서

GKE Sandbox를 사용 설정하려면 노드 풀을 구성합니다. 기본 노드 풀(클러스터가 생성될 때 생성되는 클러스터의 첫 번째 노드 풀)은 GKE Sandbox를 사용할 수 없습니다. 클러스터 생성 중에 GKE Sandbox를 사용 설정하려면 클러스터를 만들 때 두 번째 노드 풀을 추가해야 합니다.

Console

클러스터를 보려면 Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

  1. Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

    Google Kubernetes Engine 메뉴로 이동

  2. 클러스터 만들기를 클릭합니다.

  3. 표준 클러스터 템플릿을 선택하거나 워크로드에 적합한 템플릿을 선택합니다.

  4. 선택사항이지만 권장됨: gVisor 메시지가 로깅되도록 Stackdriver Logging 및 Stackdriver Monitoring을 사용 설정합니다.

  5. 노드 풀 추가를 클릭합니다.

  6. 요구사항에 따라 노드 풀을 구성합니다. 노드 풀의 노드 풀 옵션 더보기를 클릭합니다. 다음 설정을 구성합니다.

    • 노드 버전은 v1.12.6-gke.8 이상을 선택합니다.
    • 노드 이미지의 경우 Containerd(cos_containerd)를 포함한 컨테이너 최적화 OS(베타)를 선택합니다.
    • gVisor가 포함된 샌드박스 사용 설정(베타)을 사용 설정합니다.
    • 노드 풀의 노드가 두 개 이상의 vCPU를 사용하는 경우 라벨 추가를 클릭합니다. 키를 cloud.google.com/gke-smt-disabled로 설정하고 값을 true로 설정합니다. 그 다음 보안 게시판의 안내에 따라 하이퍼 스레딩을 사용 중지합니다.

    필요에 따라 다른 노드 풀 설정을 구성합니다.

  7. 노드 풀 설정을 저장하고 클러스터를 계속 구성합니다.

gcloud

GKE Sandbox는 기본 노드 풀에 대해 사용 설정할 수 없습니다. 또한 gcloud 명령어를 실행하여 새 클러스터를 만드는 것과 동시에 추가 노드 풀을 만들 수는 없습니다. 대신 평소와 같이 클러스터를 만듭니다. 선택사항이지만 --enable-stackdriver-kubernetes 플래그를 추가하여 Stackdriver Logging 및 Stackdriver Monitoring을 사용 설정하는 것이 좋습니다. gVisor 메시지가 로깅됩니다.

그 다음 gcloud beta container node-pools create 명령어를 사용하고 --sandbox 플래그를 type=gvisor로 설정합니다. 대괄호 안의 값을 해당 값으로 바꾸고 v1.12.6-gke.8 이상의 노드 버전을 지정해야 합니다.

gcloud beta container node-pools create [NODE_POOL_NAME] \
  --cluster=[CLUSTER_NAME] \
  --node-version=[NODE_VERSION] \
  --image-type=cos_containerd \
  --sandbox type=gvisor \
  --enable-autoupgrade

gvisor RuntimeClass는 노드가 생성될 때, 이 노드에서 워크로드가 예약되기 전에 인스턴스화됩니다. 다음 명령어를 사용하여 gvisor RuntimeClass의 존재 여부를 확인할 수 있습니다.

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

기존 클러스터에서

새 노드 풀을 추가하고 해당 노드 풀의 기능을 사용 설정하거나 기본이 아닌 기존 노드 풀을 수정하여 기존 클러스터에서 GKE Sandbox를 사용 설정할 수 있습니다.

Console

  1. Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

    Google Kubernetes Engine 메뉴로 이동

  2. 클러스터의 수정 버튼(연필 모양)을 클릭합니다.

  3. 필요한 경우 노드 풀 추가를 클릭하여 노드 풀을 추가합니다. 기존 노드 풀을 편집하려면 노드 풀의 수정 버튼을 클릭합니다. 기본 노드 풀에서 gVisor가 포함된 샌드박스(베타)를 사용 설정하지 마세요.

  4. gVisor가 포함된 샌드박스(베타)를 사용 설정한 다음 완료를 클릭합니다.

  5. 필요한 경우 추가로 클러스터 구성을 변경한 다음 저장을 클릭합니다.

gcloud

GKE Sandbox가 사용 설정된 노드 풀을 만들려면 다음과 같은 명령어를 사용합니다.

gcloud beta container node-pools create [NODE_POOL_NAME] \
  --cluster=[CLUSTER_NAME] \
  --image-type=cos_containerd \
  --sandbox type=gvisor \
  --enable-autoupgrade

기존 노드 풀에서 GKE Sandbox를 사용 설정하려면 다음과 같은 명령어를 사용합니다. 기본 노드 풀에서 --sandbox type=gvisor를 사용 설정하지 마세요.

 gcloud beta container node-pools update [NODE_POOL_NAME] \
  --sandbox type=gvisor

gvisor RuntimeClass는 노드가 생성될 때, 이 노드에서 워크로드가 예약되기 전에 인스턴스화됩니다. 다음 명령어를 사용하여 gvisor RuntimeClass의 존재 여부를 확인할 수 있습니다.

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

선택사항: Stackdriver Logging 및 Stackdriver Monitoring 사용 설정

선택사항이지만 클러스터에서 Stackdriver Logging 및 Stackdriver Monitoring을 사용 설정하여 gVisor 메시지가 로깅되도록 하는 것이 좋습니다. Google Cloud Console을 사용하여 기존 클러스터에서 이러한 기능을 사용 설정해야 합니다.

  1. Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

    Google Kubernetes Engine 메뉴로 이동

  2. 클러스터의 수정 버튼(연필 모양)을 클릭합니다.

  3. Stackdriver Logging 및 Stackdriver Monitoring을 사용 설정합니다.

  4. 필요한 경우 추가로 클러스터 구성을 변경한 다음 저장을 클릭합니다.

GKE Sandbox 작업

샌드박스에서 애플리케이션 실행

GKE Sandbox가 사용 설정된 노드에서 배포 실행을 강제하려면 배포에 대한 이 매니페스트에서 볼 수 있듯이 노드의 spec.template.spec.runtimeClassNamegvisor로 설정합니다.

# httpd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      runtimeClassName: gvisor
      containers:
      - name: httpd
        image: httpd

배포를 생성하려면 kubectl create 명령어를 사용합니다.

kubectl create -f httpd.yaml

Pod는 GKE Sandbox가 사용 설정된 노드 풀의 노드에 배포됩니다. 확인하려면 kubectl get pods 명령어를 사용하여 Pod가 배포된 노드를 찾습니다.

kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
httpd-db5899bc9-dk7lk   1/1     Running   0          24s

출력에서 Pod의 이름을 찾은 후 다음 명령어를 실행하여 RuntimeClass의 값을 확인합니다.

kubectl get pods [NAME-OF-POD] -o jsonpath='{.spec.runtimeClassName}'
gvisor

또는 각 Pod의 RuntimeClass를 나열하고 gvisor로 설정된 항목을 찾을 수 있습니다.

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'
[NAME-OF-POD]: gvisor

Pod가 샌드박스에서 실행 중인지 확인하는 이 방법은 샌드박스 자체의 데이터에 의존하지 않으므로 신뢰할 수 있습니다. 샌드박스 내에서 보고되는 내용은 결함이 있거나 악성일 수 있으므로 신뢰할 수 없습니다.

샌드박스 처리된 Pod와 일반 Pod 함께 실행

노드 풀에서 GKE Sandbox를 사용 설정한 후에는 노드 taint 및 내결함성을 사용하여 샌드박스를 사용하지 않고도 이러한 노드에서 신뢰할 수 있는 애플리케이션을 실행할 수 있습니다. 샌드박스 처리된 Pod와 구분하기 위해 이러한 Pod를 '일반 Pod'라고 합니다.

일반 Pod는 샌드박스 처리된 Pod와 마찬가지로 다른 Google Cloud 서비스나 클러스터 메타데이터에 액세스할 수 없습니다. 이러한 액세스 차단은 노드 구성의 일부입니다. 일반 Pod 또는 샌드박스 처리된 Pod에서 Google Cloud 서비스에 액세스해야 하는 경우 워크로드 아이덴티티를 사용합니다.

GKE Sandbox는 샌드박스 처리된 Pod를 실행할 수 있는 노드에 다음 라벨과 taint를 추가합니다.

labels:
  sandbox.gke.io: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io
  value: gvisor

Pod 매니페스트의 노드 어피니티 및 내결함성 설정 외에, GKE Sandbox는 다음 노드 어피니티 및 내결함성을 RuntimeClassgvisor로 설정된 모든 Pod에 적용합니다.

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: sandbox.gke.io/runtime
          operator: In
          values:
          - gvisor
tolerations:
  - effect: NoSchedule
    key: sandbox.gke.io/runtime
    operator: Equal
    value: gvisor

GKE Sandbox가 사용 설정된 노드에서 일반 Pod를 예약하려면 위의 노드 어피니티 및 내결함성을 Pod 매니페스트에 수동으로 적용합니다.

  • GKE Sandbox가 사용 설정된 노드에서 Pod를 실행할 수 있는 경우 내결함성을 추가합니다.
  • GKE Sandbox가 사용 설정된 노드에서 Pod를 실행해야 하는 경우 노드 어피니티와 내결함성을 모두 추가합니다.

예를 들어 다음 매니페스트는 runtimeClass를 제거하고 위의 taint와 내결함성을 모두 추가하여 샌드박스에서 애플리케이션 실행에 사용된 매니페스트를 수정하여 샌드박스 처리된 Pod가 있는 노드에서 일반 Pod로 실행됩니다.

# httpd-no-sandbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-no-sandbox
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: sandbox.gke.io/runtime
                operator: In
                values:
                - gvisor
      tolerations:
        - effect: NoSchedule
          key: sandbox.gke.io/runtime
          operator: Equal
          value: gvisor

먼저 샌드박스에서 배포가 실행 중이 아닌지 확인합니다.

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'
httpd-db5899bc9-dk7lk: gvisor
httpd-no-sandbox-5bf87996c6-cfmmd:

runtimeClass가 gvisor이므로 이전에 생성된 httpd 배포는 샌드박스에서 실행 중입니다. httpd-no-sandbox 배포에는 runtimeClass의 값이 없으므로 샌드박스에서 실행 중이 아닙니다.

다음 명령어를 실행하여 GKE Sandbox가 있는 노드에서 샌드박스 처리되지 않은 배포가 실행 중인지 확인합니다.

kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'

노드 풀의 이름은 nodeName 값에 삽입됩니다. Pod가 GKE Sandbox가 사용 설정된 노드 풀의 노드에서 실행 중인지 확인합니다.

메타데이터 보호 확인

샌드박스 처리된 Pod를 실행할 수 있는 노드에서 메타데이터가 보호된다는 어설션을 검증하려면 테스트를 실행합니다.

  1. kubectl apply -f를 사용하여 다음 매니페스트에서 샌드박스 처리된 배포를 만듭니다. 여기서는 curl 명령어가 포함된 fedora 이미지를 사용합니다. Pod는 /bin/sleep 명령어를 실행하여 배포가 10000초 동안 실행되는지 확인합니다.

    # sandbox-metadata-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: fedora
      labels:
        app: fedora
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: fedora
      template:
        metadata:
          labels:
            app: fedora
        spec:
          runtimeClassName: gvisor
          containers:
          - name: fedora
            image: fedora
            command: ["/bin/sleep","10000"]
    
  2. kubectl get pods를 사용하여 Pod 이름을 가져온 다음 kubectl exec를 사용하여 대화형으로 Pod에 연결합니다.

    kubectl exec -it [POD-NAME] /bin/sh
    

    /bin/sh 세션에서 Pod에서 실행 중인 컨테이너에 연결됩니다.

  3. 대화형 세션 내에서 다음과 같이 클러스터 메타데이터를 반환하는 URL에 액세스를 시도합니다.

    curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env" -H "Metadata-Flavor: Google"
    

    아무런 표시 없이 패킷이 누락되므로 명령어 실행이 멈추고 결국 타임아웃됩니다.

  4. Ctrl+C를 눌러 curl 명령어를 종료하고 exit를 입력하여 Pod 연결을 해제합니다.

  5. YAML 매니페스트에서 RuntimeClass 줄을 삭제하고 kubectl apply -f [FILENAME]을 사용하여 Pod를 다시 배포합니다. 샌드박스 처리된 Pod가 종료되고 GKE Sandbox가 없는 노드에서 다시 생성됩니다.

  6. 새 Pod 이름을 가져오고 kubectl exec를 사용하여 연결하고 curl 명령어를 다시 실행합니다. 이번에는 결과가 반환됩니다. 이 예시 출력은 잘립니다.

    ALLOCATE_NODE_CIDRS: "true"
    API_SERVER_TEST_LOG_LEVEL: --v=3
    AUTOSCALER_ENV_VARS: kube_reserved=cpu=60m,memory=960Mi,ephemeral-storage=41Gi;...
    ...
    

    exit를 입력하여 Pod 연결을 해제합니다.

  7. 배포를 삭제합니다.

    kubectl delete deployment fedora
    

GKE Sandbox 사용 중지

현재 노드 풀을 업데이트하여 GKE Sandbox를 사용 중지할 수 없습니다. 기존 노드 풀에서 GKE Sandbox를 사용 중지하려면 다음 중 하나를 수행합니다.

  • 이전에 샌드박스 처리된 Pod를 삭제합니다. 그렇지 않으면 GKE Sandbox를 사용 중지한 후 GKE Sandbox가 사용 설정된 사용 가능한 노드가 없는 경우 이러한 Pod가 일반 Pod로 실행됩니다. 그런 다음 GKE Sandbox가 사용 설정된 노드 풀을 삭제합니다. 또는
  • 노드 풀의 크기를 0노드로 조정합니다. 또는
  • RuntimeClassName의 값을 지정하지 않고 Pod를 다시 만듭니다.

다음 단계