NodeLocal DNSCache 설정


이 페이지에서는 NodeLocal DNSCache를 사용하여 Google Kubernetes Engine(GKE) 클러스터에서 DNS 조회 지연 시간을 개선하는 방법을 설명합니다.

GKE Autopilot 클러스터의 경우 NodeLocal DNSCache가 기본적으로 사용 설정되며 이 설정은 재정의할 수 없습니다.

아키텍처

NodeLocal DNSCache는 kube-dns 외에 실행할 수 있는 GKE 부가기능입니다.

GKE는 NodeLocal DNSCache를 클러스터의 각 노드에서 DNS 캐시를 실행하는 DaemonSet으로 구현합니다.

포드에서 DNS를 요청하면 요청은 Pod와 동일한 노드에서 실행 중인 DNS 캐시로 전달됩니다. 캐시에서 DNS 요청을 실행할 수 없는 경우 캐시는 요청을 쿼리 대상에 따라 다음 위치 중 하나로 전달합니다.

  • kube-dns: 클러스터 DNS 도메인(cluster.local)의 모든 쿼리가 kube-dns로 전달됩니다. node-local-dns 포드는 kube-dns-upstream 서비스를 사용하여 kube-dns 포드에 액세스합니다. 다음 다이어그램에서 kube-dns 서비스의 IP 주소는 10.0.0.10:53입니다.
  • 커스텀 스텁 도메인 또는 업스트림 네임서버: 쿼리는 NodeLocal DNSCache 포드에서 직접 전달됩니다.
  • Cloud DNS: 다른 모든 쿼리는 쿼리가 시작된 포드와 동일한 노드에서 실행되는 로컬 메타데이터 서버로 전달됩니다. 로컬 메타데이터 서버는 Cloud DNS에 액세스합니다.

이전 단락에 설명된 DNS 요청 경로입니다.

기존 클러스터에서 NodeLocal DNSCache를 사용 설정하면 GKE는 노드 업그레이드 프로세스에 따라 GKE 버전 1.15 이상을 실행하는 모든 클러스터 노드를 다시 만듭니다.

GKE에서 노드를 다시 만들면 GKE가 노드에 addon.gke.io/node-local-dns-ds-ready=true 라벨을 자동으로 추가합니다. 수동으로 클러스터 노드에 이 라벨을 추가하면 안 됩니다.

NodeLocal DNSCache의 이점

NodeLocal DNSCache에는 다음과 같은 이점이 있습니다.

  • 평균 DNS 조회 시간 감소
  • 포드에서 로컬 캐시로의 연결은 conntrack 테이블 항목을 만들지 않습니다. 이렇게 하면 conntrack 테이블 소진 및 경합 상태로 인해 연결이 끊기거나 거부되는 것을 방지할 수 있습니다.
  • GKE용 Cloud DNS와 함께 NodeLocal DNSCache를 사용할 수 있습니다.
  • 외부 URL(클러스터 리소스를 참조하지 않는 URL)에 대한 DNS 쿼리는 kube-dns를 거치지 않고 로컬 Cloud DNS 메타데이터 서버로 직접 전달됩니다.
  • 로컬 DNS 캐시는 kube-dns ConfigMap에 지정된 스텁 도메인과 업스트림 네임서버를 자동으로 선택합니다.

요구사항 및 제한사항

  • NodeLocal DNSCache는 클러스터의 각 노드에서 컴퓨팅 리소스를 사용합니다.
  • NodeLocal DNSCache는 Windows Server 노드 풀에서 지원되지 않습니다.
  • NodeLocal DNSCache에는 GKE 버전 1.15 이상이 필요합니다.
  • NodeLocal DNSCache는 TCP를 사용하여 kube-dns 포드에 액세스합니다.
  • NodeLocal DNSCache는 GKE 버전 1.18 이상에서 TCP 및 UDP를 사용하여 upstreamServersstubDomains에 액세스합니다. TCP 및 UDP를 사용하여 DNS 서버에 연결할 수 있어야 합니다.
  • DNS 레코드는 다음 기간 동안 캐시됩니다.
    • 레코드의 TTL(수명) 또는 TTL이 30초를 초과하는 경우 30초
    • DNS 응답이 NXDOMAINNXDOMAIN인 경우 5초
  • NodeLocal DNSCache 포드는 노드의 포트 53, 9253, 9353, 8080에서 리슨합니다. 다른 hostNetwork 포드를 실행하거나 이러한 포트로 hostPorts을 구성하면 NodeLocal DNSCache가 실패하고 DNS 오류가 발생합니다. NodeLocal DNSCache 포드는 GKE Dataplane V2GKE용 Cloud DNS를 사용할 때 hostNetwork 모드를 사용하지 않습니다.
  • 로컬 DNS 캐시는 GKE 버전 1.15 이상을 실행하는 노드 풀에서만 실행됩니다. 이전 버전을 실행하는 노드가 있는 클러스터에서 NodeLocal DNSCache를 사용 설정하면 해당 노드의 포드가 kube-dns를 사용합니다.

NodeLocal DNSCache 사용 설정

Autopilot 클러스터의 경우 NodeLocal DNSCache가 기본적으로 사용 설정되며 이 설정은 재정의할 수 없습니다.

Standard 클러스터의 경우 Google Cloud CLI를 사용하여 새 클러스터 또는 기존 클러스터에서 NodeLocal DNSCache를 사용 설정할 수 있습니다. Google Cloud 콘솔을 사용하여 새 클러스터에서 NodeLocal DNSCache를 사용 설정할 수 있습니다.

gcloud

새 클러스터에 NodeLocal DNSCache 사용 설정

새 클러스터에서 NodeLocal DNSCache를 사용 설정하려면 NodeLocalDNS 인수와 함께 --addons 플래그를 사용합니다.

gcloud container clusters create CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --addons=NodeLocalDNS

다음을 바꿉니다.

  • CLUSTER_NAME: 새 클러스터의 이름입니다.
  • COMPUTE_LOCATION: 클러스터의 Compute Engine 위치입니다.

기존 클러스터에 NodeLocal DNSCache 사용 설정

기존 클러스터에서 NodeLocal DNSCache를 사용 설정하려면 NodeLocalDNS=ENABLED 인수와 함께 --update-addons 플래그를 사용합니다.

gcloud container clusters update CLUSTER_NAME \
    --update-addons=NodeLocalDNS=ENABLED

다음을 바꿉니다.

  • CLUSTER_NAME: 클러스터 이름입니다.

콘솔

새 클러스터에서 NodeLocal DNSCache를 사용 설정하려면 다음 단계를 따르세요.

  1. Google Cloud 콘솔에서 Google Kubernetes Engine 페이지로 이동합니다.

    Google Kubernetes Engine으로 이동

  2. '표준' 옆의 구성을 클릭합니다.

  3. 원하는 대로 클러스터를 구성합니다.

  4. 탐색창에서 네트워킹을 클릭합니다.

  5. 고급 네트워킹 옵션 섹션에서 NodeLocal DNSCache 사용 설정 체크박스를 선택합니다.

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

NodeLocal DNSCache가 사용 설정되어 있는지 확인

node-local-dns 포드를 나열하여 NodeLocal DNSCache가 실행 중인지 확인할 수 있습니다.

kubectl get pods -n kube-system -o wide | grep node-local-dns

출력은 다음과 비슷합니다.

node-local-dns-869mt    1/1   Running   0   6m24s   10.128.0.35   gke-test-pool-69efb6b8-5d7m   <none>   <none>
node-local-dns-htx4w    1/1   Running   0   6m24s   10.128.0.36   gke-test-pool-69efb6b8-wssk   <none>   <none>
node-local-dns-v5njk    1/1   Running   0   6m24s   10.128.0.33   gke-test-pool-69efb6b8-bhz3   <none>   <none>

GKE 버전 1.15 이상을 실행하는 각 노드의 node-local-dns 포드가 출력에 표시됩니다.

NodeLocal DNSCache 사용 중지

다음 명령어를 사용하여 NodeLocal DNSCache를 사용 중지할 수 있습니다.

gcloud container clusters update CLUSTER_NAME \
    --update-addons=NodeLocalDNS=DISABLED

다음을 바꿉니다.

  • CLUSTER_NAME: 업그레이드할 클러스터의 이름입니다.

NodeLocal DNSCache 문제 해결

Kubernetes DNS 문제 진단에 대한 일반적인 정보는 DNS 변환 디버깅을 참조하세요.

NodeLocal DNSCache가 즉시 사용 설정되지 않음

기존 클러스터에 NodeLocal DNSCache를 사용 설정할 때 클러스터에 유지보수 기간 또는 유지보수 제외가 구성된 경우 GKE가 노드를 즉시 업데이트하지 못할 수 있습니다. 자세한 내용은 노드 재생성 및 유지보수 기간 주의사항을 참조하세요.

기다리지 않으려면 gcloud container clusters upgrade 명령어를 호출하고 --cluster-version 플래그를 노드 풀에서 이미 실행 중인 동일한 GKE 버전으로 전달하여 수동으로 노드에 변경사항을 적용할 수 있습니다. 이 해결 방법에 Google Cloud CLI를 사용해야 합니다.

Cloud DNS를 사용한 NodeLocal DNSCache

Cloud DNS에서 NodeLocal DNSCache를 사용하는 경우 클러스터는 다음 다이어그램과 같이 네임서버 IP 주소 169.254.20.10을 사용합니다.

Cloud DNS 아키텍처를 사용하는 NodeLocal DNSCache

따라서 kube-dns 서비스의 IP 주소가 포드에서 사용하는 네임서버 IP 주소와 다를 수 있습니다. Cloud DNS가 올바르게 작동하려면 169.254.20.10 네임서버 IP 주소가 필요하므로 이러한 IP 주소 차이는 예상된 것입니다.

IP 주소를 확인하려면 다음 명령어를 실행합니다.

  1. kube-dns 서비스의 IP 주소를 확인합니다.

    kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
    

    출력은 10.0.0.10:53과 같은 kube-dns의 IP 주소입니다.

  2. 포드에서 셸 세션을 엽니다.

    kubectl exec -it POD_NAME -- /bin/bash
    
  3. 포드 셸 세션에서 /etc/resolv.conf 파일의 콘텐츠를 읽습니다.

    cat /etc/resolv.conf
    

    출력은 169.254.20.10입니다.

NodeLocal DNSCache를 사용한 네트워크 정책

NodeLocal DNSCache에서 네트워크 정책을 사용하고 Cloud DNS 또는 GKE Dataplane V2를 사용하지 않는 경우 워크로드 및 node-local-dns 포드가 DNS 쿼리를 전송하도록 규칙을 구성해야 합니다.

매니페스트에서 ipBlock 규칙을 사용하여 포드와 kube-dns 간의 통신을 허용합니다.

다음 매니페스트는 ipBlock 규칙을 사용하는 네트워크 정책을 설명합니다.

spec:
  egress:
  - ports:
    - port: 53
      protocol: TCP
    - port: 53
      protocol: UDP
    to:
    - ipBlock:
        cidr: KUBE_DNS_SVC_CLUSTER_IP/32
  podSelector: {}
  policyTypes:
    - Egress

KUBE_DNS_SVC_CLUSTER_IP를 kube-dns 서비스의 IP 주소로 바꿉니다. 다음 명령어를 사용하여 kube-dns 서비스의 IP 주소를 가져올 수 있습니다.

kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"

알려진 문제

NodeLocal DNSCache 및 GKE Dataplane V2를 사용할 때 ClusterFirstWithHostNet dnsPolicy의 DNS 제한 시간

GKE Dataplane V2 및 NodeLocal DNSCache를 사용하는 클러스터에서 hostNetworktrue로 설정되고 dnsPolicyClusterFirstWithHostNet으로 설정된 포드는 클러스터 DNS 백엔드에 도달할 수 없습니다. DNS 로그에 다음과 비슷한 항목이 포함될 수 있습니다.

nslookup: write to 'a.b.c.d': Operation not permitted

;; connection timed out; no servers could be reached

출력은 DNS 요청이 백엔드 서버에 도달할 수 없음을 나타냅니다.

hostNetwork 포드에 dnsPolicydnsConfig를 설정하면 이 문제를 해결할 수 있습니다.

spec:
 dnsPolicy: "None"
 dnsConfig:
   nameservers:
     - KUBE_DNS_UPSTREAM
   searches:
     - cluster.local
     - svc.cluster.local
     - NAMESPACE.svc.cluster.local
     - c.PROJECT_ID.internal
     - google.internal
   options:
     - name: ndots
       value: "5"

다음을 바꿉니다.

  • NAMESPACE: hostNetwork 포드의 네임스페이스입니다.
  • PROJECT_ID: Google Cloud 프로젝트의 ID입니다.
  • KUBE_DNS_UPSTREAM: 업스트림 kube-dns 서비스의 ClusterIP입니다. 다음 명령어를 사용하여 이 값을 가져올 수 있습니다.

    kubectl get svc -n kube-system kube-dns-upstream -o jsonpath="{.spec.clusterIP}"
    

포드의 DNS 요청이 이제 kube-dns에 도달하고 NodeLocal DNSCache를 우회할 수 있습니다.

NodeLocal DNSCache 제한 시간 오류

NodeLocal DNSCache가 사용 설정된 클러스터의 로그에는 다음과 비슷한 항목이 포함될 수 있습니다.

[ERROR] plugin/errors: 2 <hostname> A: read tcp <node IP: port>-><kubedns IP>:53: i/o timeout

출력에는 kube-dns-upstream 클러스터 IP 서비스의 IP 주소가 포함됩니다. 이 예시에서 DNS 요청에 대한 응답은 2초 내에 kube-dns에서 수신되지 않았습니다. 다음 중 하나가 원인일 수 있습니다.

  • 기본 네트워크 연결 문제
  • 워크로드에서 발생한 DNS 쿼리 또는 노드 풀 업스케일링으로 인한 DNS 쿼리가 크게 증가했습니다.

따라서 기존 kube-dns 포드는 모든 요청을 제때 처리할 수 없습니다. 해결 방법은 자동 확장 매개변수를 조정하여 kube-dns 복제본 수를 늘리는 것입니다.

kube-dns 수직 확장

nodesPerReplica에 더 낮은 값을 사용하여 클러스터 노드가 확장될 때 더 많은 kube-dns 포드가 생성되도록 할 수 있습니다. Kubernetes API를 보는 다수의 kube-dns 포드로 인해 GKE 제어 영역 가상 머신(VM)이 과부하되지 않도록 명시적인 max 값을 설정하는 것이 좋습니다.

max를 클러스터의 노드 수로 설정할 수 있습니다. 클러스터에 노드가 500개 이상 있으면 max를 500으로 설정합니다.

Standard 클러스터의 경우 kube-dns-autoscaler ConfigMap을 수정하여 kube-dns 복제본 수를 수정할 수 있습니다. 이 구성은 Autopilot 클러스터에서 지원되지 않습니다.

kubectl edit configmap kube-dns-autoscaler --namespace=kube-system

출력은 다음과 비슷합니다.

linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'

kube-dns 복제본 수는 다음 수식을 사용하여 계산됩니다.

replicas = max( ceil( cores × 1/coresPerReplica ) , ceil( nodes × 1/nodesPerReplica ), maxValue )

확장하려면 nodesPerReplica를 더 작은 값으로 변경하고 max 값을 포함합니다.

linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'

이 구성은 클러스터의 노드 8개마다 kube-dns 포드 1개를 만듭니다. 24노드 클러스터에는 복제본이 3개, 40노드 클러스터에는 5개가 있습니다. 클러스터에서 노드가 120개를 넘어도 kube-dns 복제본 수는 max 값인 15를 초과하여 증가하지 않습니다.

클러스터에서 DNS 가용성의 기준 수준을 확인하려면 kube-dns에 대한 최소 복제본 수를 설정합니다.

min 필드가 있는 kube-dns-autoscaler ConfigMap 출력은 다음과 유사합니다.

linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'

다음 단계