NodeLocal DNSCache 설정

이 문서에서는 NodeLocal DNSCache를 사용하여 Google Kubernetes Engine (GKE) 클러스터에서 DNS 조회 지연 시간을 줄이고 애플리케이션의 성능을 개선하는 방법을 설명합니다.

NodeLocal DNSCache는 각 클러스터 노드에서 DNS 캐시를 DaemonSet으로 직접 실행하여 DNS 성능을 개선하는 GKE 부가기능입니다. 포드가 DNS 요청을 수행하면 요청은 먼저 동일한 노드의 로컬 캐시로 이동합니다. 요청을 로컬로 처리하면 평균 DNS 조회 시간이 크게 줄어들고 kube-dns 또는 GKE용 Cloud DNS와 같은 클러스터의 중앙 DNS 제공업체에 대한 부하가 줄어듭니다. DNS 아키텍처 및 NodeLocal DNSCache의 이점에 대한 자세한 설명은 서비스 검색 정보를 참고하세요.

GKE Autopilot 클러스터에서는 NodeLocal DNSCache가 기본적으로 사용 설정되며 사용 중지할 수 없습니다. 버전 1.33.1 이상을 실행하는 GKE Standard 클러스터에서는 NodeLocal DNSCache가 기본적으로 사용 설정되지만 사용 중지할 수 있습니다.

이 문서는 개발자, 관리자, 설계자를 비롯한 GKE 사용자를 대상으로 합니다. Google Cloud의 일반적인 역할과 예시 태스크에 대해 자세히 알아보려면 일반 GKE Enterprise 사용자 역할 및 태스크를 참고하세요.

이 문서에서는 사용자가 다음 사항을 잘 알고 있다고 가정합니다.

아키텍처

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

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

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

  • kube-dns: 클러스터 DNS 도메인 (cluster.local)의 모든 쿼리가 kube-dns로 전달됩니다. node-local-dns 포드는 kube-dns-upstream 서비스를 사용하여 kube-dns 포드에 액세스합니다.
  • 커스텀 스텁 도메인 또는 업스트림 네임서버: 쿼리는 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를 거치지 않습니다.
  • 로컬 DNS 캐시는 스텁 도메인에 커스텀 리졸버 추가 섹션에 지정된 스텁 도메인과 업스트림 네임서버를 자동으로 선택합니다.

요구사항 및 제한사항

  • 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 V2를 사용하고 GKE용 Cloud DNS를 사용하지 않는 경우 hostNetwork 모드를 사용하지 않습니다.
  • 로컬 DNS 캐시는 GKE 버전 1.15 이상을 실행하는 노드 풀에서만 실행됩니다. 이전 버전을 실행하는 노드가 있는 클러스터에서 NodeLocal DNSCache를 사용 설정하면 해당 노드의 포드가 kube-dns를 사용합니다.

시작하기 전에

시작하기 전에 다음 태스크를 수행했는지 확인합니다.

  • Google Kubernetes Engine API를 사용 설정합니다.
  • Google Kubernetes Engine API 사용 설정
  • 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치했으면 gcloud components update 명령어를 실행하여 최신 버전을 가져옵니다. 이전 gcloud CLI 버전에서는 이 문서의 명령어를 실행하지 못할 수 있습니다.
  • 기존 Autopilot 또는 Standard 클러스터가 있는지 확인합니다. 필요한 경우 Autopilot 클러스터를 만듭니다. Autopilot 클러스터의 경우 NodeLocal DNSCache가 기본적으로 사용 설정되며 이 설정은 재정의할 수 없습니다.

NodeLocal DNSCache 사용 설정

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

gcloud

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

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

다음을 바꿉니다.

콘솔

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

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

    Kubernetes 클러스터로 이동

  2. 수정할 클러스터의 이름을 클릭합니다.

  3. 네트워킹DNS 제공업체 필드에서 DNS 제공업체 수정을 클릭합니다.

  4. NodeLocal DNSCache 사용 설정 체크박스를 선택합니다.

  5. 변경사항 저장을 클릭합니다.

이 변경사항을 적용하려면 노드를 다시 만들어야 하므로 실행 중인 워크로드가 중단될 수 있습니다. 이 특정 변경사항에 관한 자세한 내용은 노드 업그레이드 전략을 사용하고 유지보수 정책을 준수하여 노드를 다시 만드는 수동 변경사항 표에서 해당 행을 찾으세요. 노드 업데이트에 대한 자세한 내용은 노드 업데이트 중단 계획을 참조하세요.

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 \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=DISABLED

다음을 바꿉니다.

  • CLUSTER_NAME: 업그레이드할 클러스터의 이름입니다.
  • COMPUTE_LOCATION: 클러스터의 Compute Engine 위치입니다.

이 변경사항을 적용하려면 노드를 다시 만들어야 하므로 실행 중인 워크로드가 중단될 수 있습니다. 이 특정 변경사항에 관한 자세한 내용은 노드 업그레이드 전략을 사용하고 유지보수 정책을 준수하여 노드를 다시 만드는 수동 변경사항 표에서 해당 행을 찾으세요. 노드 업데이트에 대한 자세한 내용은 노드 업데이트 중단 계획을 참조하세요.

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과 같은 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_IPkube-dns 서비스의 IP 주소로 바꿉니다. 다음 명령어를 사용하여 kube-dns 서비스의 IP 주소를 가져올 수 있습니다.

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

알려진 문제

이 섹션에는 NodeLocal DNSCache와 관련된 알려진 문제가 나열되어 있습니다.

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

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

dnslookup: 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:
     - NAMESPACE.svc.cluster.local
     - svc.cluster.local
     - 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 복제본 수를 늘리는 것입니다.

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))

ConfigMap에서 minmax 필드를 정의하면 복제본이 이러한 값으로 제한됩니다. 확장하려면 nodesPerReplica 필드의 값을 더 작은 값으로 변경하고 max 필드의 값을 포함합니다.

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

이 구성은 클러스터의 노드 8개마다 kube-dns 포드 하나를 만듭니다. 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}'

다음 단계