GKE Dataplane V2 사용


이 페이지에서는 Google Kubernetes Engine(GKE) 클러스터에 GKE Dataplane V2를 사용 설정하고 문제를 해결하는 방법을 설명합니다.

새 Autopilot 클러스터에는 1.22.7-gke.1500 이상 버전과 1.23.4-gke.1500 이상 버전의 GKE Dataplane V2가 사용 설정되어 있습니다. GKE Dataplane V2를 사용하는 데 문제가 있는 경우 문제 해결로 건너뛰세요.

GKE Dataplane V2로 GKE 클러스터 만들기

GKE 버전 1.20.6-gke.700 이상으로 새 클러스터를 만들 때 gcloud CLI나 GKE API를 사용하여 GKE Dataplane V2를 사용 설정할 수 있습니다. GKE 버전 1.17.9 이상을 사용하는 새 클러스터를 만들 때 미리보기에서 GKE Dataplane V2를 사용 설정할 수도 있습니다.

콘솔

GKE Dataplans V2로 새 클러스터를 만들려면 다음 작업을 수행하세요.

  1. Google Cloud 콘솔에서 Kubernetes 클러스터 만들기 페이지로 이동합니다.

    Kubernetes 클러스터 만들기로 이동

  2. 네트워킹 섹션에서 Dataplane V2 사용 설정 체크박스를 선택합니다. 네트워크 정책 적용이 GKE Dataplane V2에 내장되어 있으므로 Dataplane V2 사용 설정을 선택하면 Kubernetes 네트워크 정책 사용 설정 옵션이 사용 중지됩니다.

  3. 만들기를 클릭합니다.

gcloud

GKE Dataplane V2를 사용하여 새 클러스터를 만들려면 다음 명령어를 사용하세요.

gcloud container clusters create CLUSTER_NAME \
    --enable-dataplane-v2 \
    --enable-ip-alias \
    --release-channel CHANNEL_NAME \
    --location COMPUTE_LOCATION

다음을 바꿉니다.

  • CLUSTER_NAME: 새 클러스터의 이름입니다.
  • CHANNEL_NAME: GKE 버전 1.20.6-gke.700 이상을 포함하는 출시 채널입니다. 출시 채널을 사용하지 않으려면 버전 1.20.6-gke.700 이상을 지정하여 --release-channel 대신 --cluster-version 플래그를 사용할 수도 있습니다.
  • COMPUTE_LOCATION: 새 클러스터의 Compute Engine 위치입니다.

API

GKE Dataplane V2로 새 클러스터를 만들려면 클러스터 create 요청networkConfig 객체에서 datapathProvider 필드를 지정합니다.

다음 JSON 스니펫은 GKE Dataplane V2를 사용 설정하는 데 필요한 구성을 보여줍니다.

"cluster":{
   "initialClusterVersion":"VERSION",
   "ipAllocationPolicy":{
      "useIpAliases":true
   },
   "networkConfig":{
      "datapathProvider":"ADVANCED_DATAPATH"
   },
   "releaseChannel":{
      "channel":"CHANNEL_NAME"
   }
}

다음을 바꿉니다.

  • VERSION: 클러스터 버전이며 GKE 1.20.6-gke.700 이상이어야 합니다.
  • CHANNEL_NAME: GKE 버전 1.20.6-gke.700 이상을 포함하는 출시 채널입니다.

GKE Dataplane V2 문제 해결

이 섹션에서는 GKE Dataplane V2의 문제를 조사하고 해결하는 방법을 설명합니다.

  1. GKE Dataplane V2가 사용 설정되었는지 확인합니다.

    kubectl -n kube-system get pods -l k8s-app=cilium -o wide
    

    GKE Dataplane V2가 실행 중이면 출력은 프리픽스가 anetd-인 포드를 포함합니다. anetd는 GKE Dataplane V2의 네트워킹 컨트롤러입니다.

  2. 서비스 또는 네트워크 정책 적용과 관련된 문제라면 anetd 포드 로그를 확인합니다. Cloud Logging에서 다음 로그 선택기를 사용합니다.

    resource.type="k8s_container"
    labels."k8s-pod/k8s-app"="cilium"
    resource.labels.cluster_name="CLUSTER_NAME"
    
  3. 포드 만들기가 실패하면 kubelet 로그에서 단서를 찾아보세요. Cloud Logging에서 다음 로그 선택기를 사용합니다.

    resource.type="k8s_node"
    log_name=~".*/logs/kubelet"
    resource.labels.cluster_name="CLUSTER_NAME"
    

    CLUSTER_NAME을 클러스터 이름으로 바꾸거나 완전히 삭제하여 모든 클러스터의 로그를 확인합니다.

  4. anetd 포드가 실행되지 않는 경우 cilium-config ConfigMap에 변경 사항이 있는지 확인합니다. 이 ConfigMap의 기존 필드를 변경하면 클러스터가 불안정해지고 anetd에 문제가 발생할 수 있으므로 기존 필드는 절대 수정하지 마세요. ConfigMap은 새 필드가 추가된 경우에만 기본 상태로 자동 패치됩니다. 기존 필드를 수정한 경우에는 원래대로 복구되지 않습니다. 따라서 ConfigMap은 변경하거나 맞춤설정하지 않는 것이 좋습니다.

알려진 문제

GKE Dataplane V2 클러스터에서 NodePort 범위 충돌로 인해 간헐적인 연결 문제 발생

GKE Dataplane V2 클러스터에서는 마스커레이드된 트래픽이나 임시 포트를 사용하는 경우 간헐적인 연결 문제가 발생할 수 있습니다. 이러한 문제는 예약된 NodePort 범위와의 포트 충돌 가능성 때문에 발생하며 일반적으로 다음과 같은 상황에서 발생합니다.

  • 커스텀 ip-masq-agent: 클러스터에서 NodePort 또는 부하 분산기를 사용하는 경우 버전 2.10 이상의 커스텀 ip-masq-agent를 사용할 때 NodePort 범위와의 충돌로 인해 간헐적인 연결 문제가 발생할 수 있습니다. 버전 2.10부터는 ip-masq-agent--random-fully 인수가 기본적으로 내부 구현되어 있습니다. 이를 완화하려면 ip-masq-agent 구성에서 --random-fully=false(버전 2.11 이상에 적용 가능)를 명시적으로 설정해야 합니다. 구성에 관한 자세한 내용은 Standard 클러스터에서 IP 매스커레이드 에이전트 구성을 참조하세요.

  • 임시 포트 범위 겹침: GKE 노드에서 net.ipv4.ip_local_port_range로 정의된 임시 포트 범위가 NodePort 범위(30000~32767)와 겹치는 경우 연결 문제가 발생할 수 있습니다. 이 문제를 방지하려면 두 포트 범위가 서로 겹치지 않도록 설정해야 합니다.

ip-masq-agent 구성과 임시 포트 범위 설정을 검토하여 NodePort 범위와 충돌하지 않도록 하세요. 간헐적인 연결 문제가 발생한다면 이러한 가능한 원인들을 고려하여 구성을 조정하는 것이 좋습니다.

GKE Dataplane V2 클러스터에서 hostPort로 인한 연결 문제

영향을 받는 GKE 버전: 1.29 이상

GKE Dataplane V2를 사용하는 클러스터에서는 트래픽이 노드의 IP:포트(여기서 포트는 포드에 정의된 hostPort임)로 전달될 때 연결 오류가 발생할 수 있습니다. 이러한 문제는 다음 두 가지 기본 시나리오에서 발생합니다.

  • 패스 스루 네트워크 부하 분산기 뒤에 있는 hostPort 노드:

    hostPort는 특정 노드의 포트에 포드를 고정시키며, 패스 스루 네트워크 부하 분산기는 트래픽을 모든 노드에 분산시킵니다. hostPort와 패스 스루 네트워크 부하 분산기를 함께 사용하여 포드를 인터넷에 노출하는 경우 부하 분산기가 해당 포드가 실행되고 있지 않은 노드로 트래픽을 전달할 수 있으며, 이로 인해 연결 실패가 발생할 수 있습니다. 이 문제는 GKE Dataplane V2의 알려진 제한사항으로, 패스스루 네트워크 부하 분산기 트래픽이 hostPort 포드로 일관되게 전달되지 않는 문제에서 비롯됩니다.

    해결 방법: 포드의 hostPort를 패스 스루 네트워크 부하 분산기가 연결된 노드에서 노출하려는 경우 해당 포드의 hostIP 필드에 해당 네트워크 부하 분산기의 내부 또는 외부 IP 주소를 지정합니다.

    ports:
    - containerPort: 62000
      hostPort: 62000
      protocol: TCP
      hostIP: 35.232.62.64
    - containerPort: 60000
      hostPort: 60000
      protocol: TCP
      hostIP: 35.232.62.64
      # Assuming 35.232.62.64 is the external IP address of a passthrough Network Load Balancer.
    
  • hostPort가 예약된 NodePort 범위와 충돌하는 경우:

    포드의 hostPort가 예약된 NodePort 범위(30000~32767)와 충돌하면 Cilium이 해당 포드로 트래픽을 전달하지 못할 수 있습니다. 이 현상은 클러스터 버전 1.29 이상에서 관찰되며, 해당 버전부터는 Cilium이 기존의 Portmap 방식 대신 hostPort 기능을 직접 관리하기 때문입니다. 이 동작은 Cilium의 예상되는 동작이며 해당 내용은 공식 문서에도 명시되어 있습니다.

이러한 제한사항은 향후 버전에서도 수정될 예정이 없습니다. 이러한 문제의 근본 원인은 Cilium의 동작 방식과 관련되어 있으며, 이는 GKE에서 직접 제어할 수 있는 범위를 벗어납니다.

권장사항: 더 높은 안정성을 위해 hostPort 대신 NodePort 서비스로 마이그레이션하는 것이 좋습니다. NodePort 서비스는 유사한 기능을 제공합니다.

네트워크 정책의 포트 범위가 적용되지 않음

GKE Dataplane V2가 사용 설정된 클러스터의 네트워크 정책에 endPort 필드를 지정하면 적용되지 않습니다.

GKE 1.22부터 Kubernetes 네트워크 정책 API를 사용하면 네트워크 정책이 적용되는 포트 범위를 지정할 수 있습니다. 이 API는 Calico 네트워크 정책이 있는 클러스터에서 지원되지만 GKE Dataplane V2가 있는 클러스터에서는 지원되지 않습니다.

NetworkPolicy 객체를 API 서버에 작성한 후 다시 읽어 해당 객체의 동작을 확인할 수 있습니다. 객체에 여전히 endPort 필드가 포함되어 있으면 기능이 적용됩니다. endPort 필드가 누락되면 이 기능이 적용되지 않습니다. 어떤 경우든 API 서버에 저장된 객체는 네트워크 정책의 정보 소스입니다.

자세한 내용은 KEP-2079: 포트 범위를 지원하는 네트워크 정책을 참조하세요.

포드에 failed to allocate for range 0: no IP addresses available in range set 오류 메시지 표시

영향을 받는 GKE 버전: 1.22 ~ 1.25

containerd를 사용하고 GKE Dataplane V2가 사용 설정된 노드 풀을 실행하는 GKE 클러스터는 IP 주소 누출 문제가 발생할 수 있고 한 노드에서 포드 IP 주소를 모두 소진할 수 있습니다. 영향을 받는 노드에서 예약된 포드는 다음과 비슷한 오류 메시지를 표시합니다.

failed to allocate for range 0: no IP addresses available in range set: 10.48.131.1-10.48.131.62

이 문제에 대한 자세한 내용은 containerd 문제 #5768을 참조하세요.

수정된 버전

이 문제를 해결하려면 다음 GKE 버전 중 하나로 클러스터를 업그레이드합니다.

  • 1.22.17-gke.3100 이상
  • 1.23.16-gke.200 이상
  • 1.24.9-gke.3200 이상
  • 1.25.6-gke.200 이상

표준 GKE 클러스터의 해결 방법

노드의 누출된 포드 IP 주소를 삭제하여 이 문제를 완화할 수 있습니다.

누출된 포드 IP 주소를 삭제하려면 클러스터에 대해 인증 사용자 인증 정보를 가져오고 다음 단계를 실행하여 단일 노드를 삭제합니다(이름을 알고 있는 경우).

  1. 다음 셸 스크립트를 cleanup.sh 파일에 저장합니다.

    for hash in $(sudo find /var/lib/cni/networks/gke-pod-network -iregex '/var/lib/cni/networks/gke-pod-network/[0-9].*' -exec head -n1 {} \;); do hash="${hash%%[[:space:]]}"; if [ -z $(sudo ctr -n k8s.io c ls | grep $hash | awk '{print $1}') ]; then sudo grep -ilr $hash /var/lib/cni/networks/gke-pod-network; fi; done | sudo xargs -r rm
    
  2. 클러스터 노드에서 스크립트를 실행합니다.

    gcloud compute ssh --zone "ZONE" --project "PROJECT" NODE_NAME --command "$(cat cleanup.sh)"
    

    NODE_NAME을 노드의 이름으로 바꿉니다.

이 스크립트의 DaemonSet 버전을 실행하여 모든 노드에서 한 번에 동시에 실행할 수도 있습니다.

  1. 다음 매니페스트를 cleanup-ips.yaml이라는 파일에 저장합니다.

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: cleanup-ipam-dir
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          name: cleanup-ipam
      template:
        metadata:
          labels:
            name: cleanup-ipam
        spec:
          hostNetwork: true
          securityContext:
            runAsUser: 0
            runAsGroup: 0
          containers:
          - name: cleanup-ipam
            image: gcr.io/gke-networking-test-images/ubuntu-test:2022
            command:
              - /bin/bash
              - -c
              - |
                while true; do
                for hash in $(find /hostipam -iregex '/hostipam/[0-9].*' -mmin +10 -exec head -n1 {} \; ); do
                hash="${hash%%[[:space:]]}"
                if [ -z $(ctr -n k8s.io c ls | grep $hash | awk '{print $1}') ]; then
                grep -ilr $hash /hostipam
                fi
                done | xargs -r rm
                echo "Done cleaning up /var/lib/cni/networks/gke-pod-network at $(date)"
                sleep 120s
                done
            volumeMounts:
            - name: host-ipam
              mountPath: /hostipam
            - name: host-ctr
              mountPath: /run/containerd
          volumes:
          - name: host-ipam
            hostPath:
              path: /var/lib/cni/networks/gke-pod-network
          - name: host-ctr
            hostPath:
              path: /run/containerd
    
  2. 클러스터에서 daemonset을 실행합니다.

    kubectl apply -f cleanup-ips.yaml
    

    이 명령어를 실행하려면 클러스터의 관리자로서 kubectl 액세스 권한이 있어야 합니다.

  3. 실행 중인 DaemonSet의 로그를 확인합니다.

    kubectl -n kube-system logs -l name=cleanup-ipam
    

잘못된 연결 추적 조회로 인해 네트워크 정책이 연결을 중단

클라이언트 포드가 내부 패스 스루 네트워크 부하 분산기의 서비스나 가상 IP 주소를 통해 자체에 연결되면 응답 패킷은 데이터 영역의 잘못된 conntrack 조회로 인해 기존 연결의 일부로 식별되지 않습니다. 즉, 포드의 인그레스 트래픽을 제한하는 네트워크 정책이 패킷에 잘못 적용됩니다.

이 문제의 영향은 서비스에 구성된 포드 수에 따라 다릅니다. 예를 들어 서비스에 백엔드 포드가 1개 있으면 연결이 항상 실패합니다. 서비스에 백엔드 포드가 2개 있는 경우 연결의 50%가 실패합니다.

수정된 버전

이 문제를 해결하려면 다음 GKE 버전 중 하나로 클러스터를 업그레이드합니다.

  • 1.28.3-gke.1090000 이상

해결 방법

서비스 매니페스트에서 portcontainerPort를 동일한 값으로 구성하여 이 문제를 완화할 수 있습니다.

헤어핀 연결 흐름을 위한 패킷 삭제

포드가 서비스를 사용하여 자체 TCP 연결을 만들면(예: 포드가 연결의 소스이자 대상인 경우), GKE Dataplane V2 eBPF 연결 추적은 연결 상태를 잘못 추적하여 conntrack 항목의 유출로 이어지게 됩니다.

연결 튜플(프로토콜, 소스/대상 IP, 소스/대상 포트)이 유출되면 동일한 연결 튜플을 사용하는 새 연결로 인해 반환 패킷이 삭제될 수 있습니다.

수정된 버전

이 문제를 해결하려면 다음 GKE 버전 중 하나로 클러스터를 업그레이드합니다.

  • 1.28.3-gke.1090000 이상
  • 1.27.11-gke.1097000 이상

해결 방법

이때 다음 해결방법 중 하나를 사용해 보세요.

  • 서비스를 사용하여 자체적으로 통신할 수 있는 포드에서 실행되는 애플리케이션에 TCP 재사용(연결 유지)을 사용 설정합니다. 이렇게 하면 TCP FIN 플래그가 발급되지 않고 conntrack 항목의 유출이 방지됩니다.

  • 단기 연결을 사용할 때는 게이트웨이와 같은 프록시 부하 분산기를 사용하여 포드를 노출하여 서비스를 노출하세요. 이렇게 하면 연결 요청의 대상이 부하 분산기의 IP 주소로 설정되어 GKE Dataplane V2가 루프백 IP 주소로 SNAT를 수행하는 것을 방지할 수 있습니다.

GKE 컨트롤 플레인 업그레이드 시 anetd 포드 교착 상태 발생

GKE Dataplane V2(고급 데이터 경로)가 사용 설정된 GKE 클러스터를 버전 1.27에서 1.28로 업그레이드할 경우 교착 상태가 발생할 수 있습니다. 이로 인해 이전 포드를 종료하거나 anetd와 같은 필수 구성요소를 예약하지 못하게 되어, 워크로드가 중단되는 문제가 발생할 수 있습니다.

원인

클러스터 업그레이드 과정에서는 GKE Dataplane V2 구성요소의 리소스 요구량이 증가합니다. 이러한 리소스 사용량 증가는 리소스 경합을 유발할 수 있으며, 그 결과 Cilium 컨테이너 네트워크 인터페이스(CNI) 플러그인과 Cilium 데몬 간의 통신이 중단될 수 있습니다.

증상

다음과 같은 증상이 발생할 수 있습니다.

  • anetd 포드가 Pending 상태에서 멈춰 있는 현상
  • 워크로드 포드가 Terminating 상태에서 종료되지 않는 현상
  • Cilium 통신 오류 관련 메시지(예: failed to connect to Cilium daemon)
  • 포드 샌드박스의 네트워크 리소스를 정리하는 중 발생하는 오류(예: 다음과 같은 메시지)

    1rpc error: code = Unknown desc = failed to destroy network for sandbox "[sandbox_id]": plugin type="cilium-cni" failed (delete): unable to connect to Cilium daemon... connection refused
    

해결 방법

Standard 클러스터: 문제를 해결하고 anetd 포드를 예약할 수 있도록 하려면 영향을 받은 노드의 할당 가능한 리소스를 일시적으로 증가시켜야 합니다.

  1. 영향을 받은 노드를 식별하고 해당 노드의 할당 가능한 CPU 및 메모리를 확인하려면 다음 명령어를 실행하세요.

    kubectl get nodes $NODE_NAME -o json | jq '.status.allocatable | {cpu, memory}'
    
  2. 할당 가능한 CPU 및 메모리를 일시적으로 증가시키려면 다음 명령어를 실행하세요.

    kubectl patch
    

Autopilot 클러스터: Autopilot 클러스터에서 교착 상태 문제를 해결하려면 영향을 받은 포드를 강제로 삭제하여 리소스를 확보하세요.

kubectl delete pod POD_NAME -n NAMESPACE --grace-period=0 --force

다음을 바꿉니다.

  • POD_NAME: 포드의 이름입니다.
  • NAMESPACE: 포드의 네임스페이스입니다.

노드의 할당 가능한 리소스를 증가시키고 GKE 버전 1.27에서 1.28로의 업그레이드가 완료되면 anetd 포드가 최신 버전에서 실행됩니다.

다음 단계