이 페이지에서는 Google Kubernetes Engine (GKE)에서 kube-dns 관련 문제를 해결하는 방법을 보여줍니다.
kube-dns에서 DNS 문제의 출처 식별
dial tcp: i/o timeout
, no such
host
, Could not resolve host
과 같은 오류는 종종 kube-dns의 쿼리 확인 기능에 문제가 있음을 나타냅니다.
이러한 오류 중 하나가 표시되었지만 원인을 모르는 경우 다음 섹션을 참고하여 원인을 찾으세요. 다음 섹션은 가장 도움이 될 만한 단계부터 시작되도록 정렬되어 있으므로 각 섹션을 순서대로 시도해 보세요.
kube-dns 포드가 실행 중인지 확인
Kube-dns Pod는 클러스터 내에서 이름을 확인하는 데 중요합니다. 실행되지 않으면 DNS 확인에 문제가 있을 수 있습니다.
kube-dns 포드가 최근에 다시 시작되지 않고 실행 중인지 확인하려면 다음 포드의 상태를 확인합니다.
kubectl get pods -l k8s-app=kube-dns -n kube-system
출력은 다음과 비슷합니다.
NAME READY STATUS RESTARTS AGE
kube-dns-POD_ID_1 5/5 Running 0 16d
kube-dns-POD_ID_2 0/5 Terminating 0 16d
이 출력에서 POD_ID_1
및 POD_ID_2
는 kube-dns 포드에 자동으로 추가되는 고유 식별자를 나타냅니다.
출력에 kube-dns 포드 중 Running
상태가 아닌 포드가 있는 경우 다음 단계를 따르세요.
관리자 활동 감사 로그를 사용하여 클러스터 또는 노드 풀 버전 업그레이드, kube-dns ConfigMap 변경 등 최근 변경사항이 있는지 조사합니다. 감사 로그에 관한 자세한 내용은 GKE 감사 로깅 정보를 참고하세요. 변경사항이 있는 경우 되돌리고 포드의 상태를 다시 확인합니다.
최근에 관련된 변경사항을 찾을 수 없는 경우 kube-dns 포드가 실행되는 노드에서 OOM 오류가 발생하는지 조사합니다. Cloud Logging 로그 메시지에 다음과 유사한 오류가 표시되면 이러한 포드에 OOM 오류가 발생한 것입니다.
Warning: OOMKilling Memory cgroup out of memory
이 오류를 해결하려면 오류 메시지: 'Warning: OOMKilling Memory cgroup out of memory'를 참고하세요.
OOM 오류 메시지가 표시되지 않으면 kube-dns 배포를 다시 시작합니다.
kubectl rollout restart deployment/kube-dns --namespace=kube-system
배포를 다시 시작한 후 kube-dns Pod가 실행 중인지 확인합니다.
이 단계를 수행해도 문제가 해결되지 않거나 모든 kube-dns 포드의 상태가 Running
이지만 DNS 문제가 계속 발생하는 경우 /etc/resolv.conf
파일이 올바르게 구성되어 있는지 확인합니다.
/etc/resolv.conf
가 올바르게 구성되었는지 확인
DNS 문제가 발생한 포드의 /etc/resolv.conf
파일을 검토하고 포함된 항목이 올바른지 확인합니다.
포드의
/etc/resolv.conf
파일을 확인합니다.kubectl exec -it POD_NAME -- cat /etc/resolv.conf
POD_NAME을 DNS 문제가 발생한 Pod의 이름으로 바꿉니다. 문제가 발생한 Pod가 여러 개인 경우 각 Pod에 대해 이 섹션의 단계를 반복합니다.
Pod 바이너리가
kubectl exec
명령어를 지원하지 않으면 이 명령어가 실패할 수 있습니다. 이 경우 테스트 환경으로 사용할 간단한 Pod를 만듭니다. 이 절차를 통해 문제가 있는 포드와 동일한 네임스페이스에서 테스트 포드를 실행할 수 있습니다./etc/resolv.conf
파일의 네임서버 IP 주소가 올바른지 확인합니다.- 호스트 네트워크를 사용하는 포드는 노드의
/etc/resolv.conf
파일의 값을 사용해야 합니다. 네임서버 IP 주소는169.254.169.254
여야 합니다. 호스트 네트워크를 사용하지 않는 포드의 경우 kube-dns 서비스 IP 주소는 네임서버 IP 주소와 동일해야 합니다. IP 주소를 비교하려면 다음 단계를 완료하세요.
kube-dns 서비스의 IP 주소를 가져옵니다.
kubectl get svc kube-dns -n kube-system
출력은 다음과 비슷합니다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 192.0.2.10 <none> 53/UDP,53/TCP 64d
클러스터 IP 열의 값을 기록해 둡니다. 이 예시에서는
192.0.2.10
입니다.kube-dns 서비스 IP 주소를
/etc/resolv.conf
파일의 IP 주소와 비교합니다.# cat /etc/resolv.conf search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_NAME google.internal nameserver 192.0.2.10 options ndots:5
이 예에서는 두 값이 일치하므로 잘못된 이름 서버 IP 주소가 문제의 원인이 아닙니다.
그러나 IP 주소가 일치하지 않으면 애플리케이션 Pod의 매니페스트에
dnsConfig
필드가 구성되어 있는 것입니다.dnsConfig.nameservers
필드의 값이 올바르면 DNS 서버를 조사하여 제대로 작동하는지 확인합니다.맞춤 네임서버를 사용하지 않으려면 필드를 삭제하고 포드를 롤링 다시 시작합니다.
kubectl rollout restart deployment POD_NAME
POD_NAME
을 포드 이름으로 바꿉니다.
- 호스트 네트워크를 사용하는 포드는 노드의
/etc/resolv.conf
에서search
및ndots
항목을 확인합니다. 맞춤법 오류, 비활성 구성이 없고 실패한 요청이 올바른 네임스페이스의 기존 서비스를 가리키는지 확인합니다.
DNS 조회 수행
/etc/resolv.conf
가 올바르게 구성되고 DNS 레코드가 올바른지 확인한 후 dig 명령줄 도구를 사용하여 DNS 오류를 보고하는 Pod에서 DNS 조회를 실행합니다.
포드 내에서 셸을 열어 포드를 직접 쿼리합니다.
kubectl exec -it POD_NAME -n NAMESPACE_NAME -- SHELL_NAME
다음을 바꿉니다.
POD_NAME
: DNS 오류를 보고하는 포드의 이름입니다.NAMESPACE_NAME
: 포드가 속한 네임스페이스입니다.SHELL_NAME
: 열려 있는 셸의 이름입니다. 예를 들면sh
또는/bin/bash
입니다.
포드가
kubectl exec
명령어를 허용하지 않거나 포드에 dig 바이너리가 없는 경우 이 명령어가 실패할 수 있습니다. 이 경우 dig가 설치된 이미지로 테스트 포드를 만듭니다.kubectl run "test-$RANDOM" ti --restart=Never --image=thockin/dnsutils - bash
포드가 클러스터의 내부 DNS 서비스를 올바르게 확인할 수 있는지 확인합니다.
dig kubernetes
/etc/resolv.conf
파일이 kube-dns 서비스 IP 주소를 가리키므로 이 명령어를 실행하면 DNS 서버가 kube-dns 서비스가 됩니다.Kubernetes API 서비스의 IP 주소 (일반적으로
10.96.0.1
)가 포함된 성공적인 DNS 응답이 표시됩니다.SERVFAIL
이 표시되거나 응답이 없으면 일반적으로 kube-dns 포드가 내부 서비스 이름을 확인할 수 없음을 나타냅니다.kube-dns 서비스가 외부 도메인 이름을 확인할 수 있는지 확인합니다.
dig example.com
DNS 쿼리에 응답하는 특정 kube-dns 포드에 문제가 있는 경우 해당 포드가 외부 도메인 이름을 확인할 수 있는지 확인합니다.
dig example.com @KUBE_DNS_POD_IP
KUBE_DNS_POD_IP
를 kube-dns Pod의 IP 주소로 바꿉니다. 이 IP 주소의 값을 모르는 경우 다음 명령어를 실행합니다.kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
IP 주소는
IP
열에 있습니다.명령어의 확인이 성공하면 다음 예와 같이
status: NOERROR
및 A 레코드의 세부정보가 표시됩니다.; <<>> DiG 9.16.27 <<>> example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31256 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;example.com. IN A ;; ANSWER SECTION: example.com. 30 IN A 93.184.215.14 ;; Query time: 6 msec ;; SERVER: 10.76.0.10#53(10.76.0.10) ;; WHEN: Tue Oct 15 16:45:26 UTC 2024 ;; MSG SIZE rcvd: 56
셸을 종료합니다.
exit
이러한 명령어 중 하나라도 실패하면 kube-dns 배포를 롤링 다시 시작합니다.
kubectl rollout restart deployment/kube-dns --namespace=kube-system
다시 시작을 완료한 후 dig 명령어를 다시 시도하여 이제 실행되는지 확인합니다. 그래도 실패하면 패킷 캡처를 진행합니다.
패킷 캡처 수행
패킷 캡처를 사용하여 DNS 쿼리가 kube-dns 포드에서 수신되고 적절하게 응답되는지 확인합니다.
SSH를 사용하여 kube-dns 포드를 실행하는 노드에 연결합니다. 예를 들면 다음과 같습니다.
Google Cloud 콘솔에서 VM 인스턴스 페이지로 이동합니다.
연결하려는 노드를 찾습니다. kube-dns 포드의 노드 이름을 모르는 경우 다음 명령어를 실행합니다.
kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
노드 이름은 노드 열에 표시됩니다.
연결 열에서 SSH를 클릭합니다.
터미널에서 사전 설치된 디버그 도구인 toolbox를 시작합니다.
toolbox
루트 프롬프트에서
tcpdump
패키지를 설치합니다.apt update -y && apt install -y tcpdump
tcpdump
를 사용하여 DNS 트래픽의 패킷 캡처를 수행합니다.tcpdump -i eth0 port 53" -w FILE_LOCATION
FILE_LOCATION
를 캡처를 저장할 위치의 경로로 바꿉니다.패킷 캡처를 검토합니다. kube-dns 서비스 IP 주소와 일치하는 대상 IP 주소가 있는 패킷이 있는지 확인합니다. 이렇게 하면 DNS 요청이 올바른 대상에 도달하여 확인됩니다. 올바른 포드에 도착하는 DNS 트래픽이 표시되지 않으면 요청을 차단하는 네트워크 정책이 있음을 나타낼 수 있습니다.
네트워크 정책 확인
제한적인 네트워크 정책으로 인해 DNS 트래픽이 중단될 수 있습니다. kube-system 네임스페이스에 네트워크 정책이 있는지 확인하려면 다음 명령어를 실행합니다.
kubectl get networkpolicy -n kube-system
네트워크 정책을 찾으면 정책을 검토하고 정책에서 필요한 DNS 통신을 허용하는지 확인합니다. 예를 들어 모든 이그레스 트래픽을 차단하는 네트워크 정책이 있는 경우 이 정책은 DNS 요청도 차단합니다.
출력이 No resources found in kube-system namespace
이면 네트워크 정책이 없으므로 이 문제를 문제의 원인으로 배제할 수 있습니다. 로그를 조사하면 더 많은 오류 지점을 찾을 수 있습니다.
임시 DNS 쿼리 로깅 사용 설정
잘못된 DNS 응답과 같은 문제를 식별하는 데 도움이 되도록 일시적으로 DNS 쿼리의 디버그 로깅을 사용 설정합니다.
이는 리소스 집약적인 절차이므로 적절한 로그 샘플을 수집한 후에는 이 로깅을 사용 중지하는 것이 좋습니다.
kube-dns 포드 조사
Cloud Logging을 사용하여 kube-dns 포드가 DNS 쿼리를 수신하고 확인하는 방법을 검토합니다.
kube-dns 포드와 관련된 로그 항목을 보려면 다음 단계를 완료하세요.
Google Cloud 콘솔에서 로그 탐색기 페이지로 이동합니다.
쿼리 창에 다음 필터를 입력하여 kube-dns 컨테이너와 관련된 이벤트를 확인합니다.
resource.type="k8s_container" resource.labels.namespace_name="kube-system" resource.labels.Pod_name:"kube-dns" resource.labels.cluster_name="CLUSTER_NAME" resource.labels.location="CLUSTER_LOCATION"
다음을 바꿉니다.
CLUSTER_NAME
: kube-dns 포드가 속한 클러스터의 이름입니다.CLUSTER_LOCATION
: 클러스터의 위치입니다.
쿼리 실행을 클릭합니다.
출력을 검토합니다. 다음 출력 예는 표시될 수 있는 오류 중 하나를 보여줍니다.
{ "timestamp": "2024-10-10T15:32:16.789Z", "severity": "ERROR", "resource": { "type": "k8s_container", "labels": { "namespace_name": "kube-system", "Pod_name": "kube-dns", "cluster_name": "CLUSTER_NAME", "location": "CLUSTER_LOCATION" } }, "message": "Failed to resolve 'example.com': Timeout." },
이 예에서 kube-dns는 적절한 시간 내에
example.com
를 확인할 수 없습니다. 이 유형의 오류는 여러 문제로 인해 발생할 수 있습니다. 예를 들어 업스트림 서버가 kube-dns ConfigMap에서 잘못 구성되었거나 네트워크 트래픽이 많을 수 있습니다.
Cloud Logging을 사용 설정하지 않은 경우 대신 Kubernetes 로그를 확인하세요.
Pod=$(kubectl get Pods -n kube-system -l k8s-app=kube-dns -o name | head -n1)
kubectl logs -n kube-system $Pod -c dnsmasq
kubectl logs -n kube-system $Pod -c kubedns
kubectl logs -n kube-system $Pod -c sidecar
kube-dns ConfigMap의 최근 변경사항 조사
클러스터에서 갑자기 DNS 확인 실패가 발생하는 경우 그 원인 중 하나는 kube-dns ConfigMap에 잘못된 구성 변경사항이 적용되었기 때문일 수 있습니다. 특히 스텁 도메인 및 업스트림 서버 정의의 구성 변경으로 인해 문제가 발생할 수 있습니다.
스텁 도메인 설정의 업데이트를 확인하려면 다음 단계를 완료하세요.
Google Cloud 콘솔에서 로그 탐색기 페이지로 이동합니다.
쿼리 창에 다음 쿼리를 입력합니다.
resource.labels.cluster_name="clouddns" resource.type="k8s_container" resource.labels.namespace_name="kube-system" labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated stubDomains to"
쿼리 실행을 클릭합니다.
출력을 검토합니다. 업데이트가 있으면 출력은 다음과 비슷합니다.
Updated stubDomains to map[example.com: [8.8.8.8 8.8.4.4 1.1.3.3 1.0.8.111]]
업데이트가 표시되면 결과를 펼쳐 변경사항에 관해 자세히 알아보세요. 스텁 도메인과 해당하는 업스트림 DNS 서버가 올바르게 정의되었는지 확인합니다. 여기에서 잘못된 항목을 입력하면 해당 도메인의 확인 실패가 발생할 수 있습니다.
업스트림 서버의 변경사항을 확인하려면 다음 단계를 완료하세요.
Google Cloud 콘솔에서 로그 탐색기 페이지로 이동합니다.
쿼리 창에 다음 쿼리를 입력합니다.
resource.labels.cluster_name="clouddns" resource.type="k8s_container" resource.labels.namespace_name="kube-system" labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated upstreamNameservers to"
쿼리 실행을 클릭합니다.
출력을 검토합니다. 변경사항이 있으면 출력은 다음과 비슷합니다.
Updated upstreamNameservers to [8.8.8.8]
결과를 펼쳐 변경사항에 대해 자세히 알아보세요. 업스트림 DNS 서버 목록이 정확하고 클러스터에서 이러한 서버에 연결할 수 있는지 확인합니다. 이러한 서버를 사용할 수 없거나 잘못 구성된 경우 일반적인 DNS 확인에 실패할 수 있습니다.
스텁 도메인 및 업스트림 서버의 변경사항을 확인했지만 결과가 없으면 다음 필터로 모든 변경사항을 확인하세요.
resource.type="k8s_cluster"
protoPayload.resourceName:"namespaces/kube-system/configmaps/kube-dns"
protoPayload.methodName=~"io.k8s.core.v1.configmaps."
표시된 변경사항을 검토하여 오류의 원인인지 확인합니다.
클라우드 고객 지원에 문의
이전 섹션을 진행했지만 문제의 원인을 파악할 수 없는 경우 Cloud Customer Care에 문의하세요.
일반적인 문제 해결
특정 오류나 문제가 발생한 경우 다음 섹션의 안내를 따르세요.
문제: 간헐적인 DNS 시간 초과
DNS 트래픽이 증가하거나 영업 시간이 시작될 때 간헐적으로 DNS 확인 시간 초과가 발생하는 경우 다음 솔루션을 사용하여 DNS 성능을 최적화해 보세요.
클러스터에서 실행 중인 kube-dns 포드 수를 확인하고 총 GKE 노드 수와 비교합니다. 리소스가 충분하지 않으면 kube-dns 포드를 확장해 보세요.
평균 DNS 조회 시간을 개선하려면 NodeLocal DNS Cache를 사용 설정하세요.
외부 이름에 대한 DNS 확인으로 인해 kube-dns 포드에 오버로드가 발생할 수 있습니다. 쿼리 수를 줄이려면
/etc/resolv.conf
파일에서ndots
설정을 조정합니다.ndots
는 초기 절대 쿼리 전에 쿼리를 확인하기 위해 도메인 이름에 표시되어야 하는 점의 수를 나타냅니다.다음 예는 애플리케이션 Pod의
/etc/resolv.conf
파일입니다.search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_ID.internal google.internal nameserver 10.52.16.10 options ndots:5
이 예에서 kube-dns는 쿼리된 도메인에서 점 5개를 찾습니다. 포드가
example.com
에 대한 DNS 확인을 호출하면 로그는 다음 예와 비슷합니다."A IN example.com.default.svc.cluster.local." NXDOMAIN "A IN example.com.svc.cluster.local." NXDOMAIN "A IN example.com.cluster.local." NXDOMAIN "A IN example.com.google.internal." NXDOMAIN "A IN example.com.c.PROJECT_ID.internal." NXDOMAIN "A IN example.com." NOERROR
이 문제를 해결하려면 ndots 값을
1
로 변경하여 단일 점만 찾거나 쿼리하거나 사용하는 도메인의 끝에 점 (.
)을 추가합니다. 예를 들면 다음과 같습니다.dig example.com.
문제: 일부 노드에서 DNS 쿼리가 간헐적으로 실패함
일부 노드에서 DNS 쿼리가 간헐적으로 실패하는 경우 다음과 같은 증상이 나타날 수 있습니다.
- kube-dns 서비스 IP 주소 또는 포드 IP 주소에 dig 명령어를 실행하면 DNS 쿼리가 시간 초과와 함께 간헐적으로 실패합니다.
- kube-dns 포드와 동일한 노드의 포드에서 dig 명령어를 실행하면 실패합니다.
이 문제를 해결하려면 다음 단계를 완료하시기 바랍니다.
- 연결 테스트를 실행합니다. 문제가 있는 포드 또는 노드를 소스로, 대상을 kube-dns 포드의 IP 주소로 설정합니다. 이렇게 하면 이 트래픽을 허용하는 데 필요한 방화벽 규칙이 설정되어 있는지 확인할 수 있습니다.
테스트가 실패하고 방화벽 규칙에 의해 트래픽이 차단되는 경우 Cloud Logging을 사용하여 방화벽 규칙에 수동으로 변경한 사항을 나열합니다. 특정 유형의 트래픽을 차단하는 변경사항을 찾습니다.
Google Cloud 콘솔에서 로그 탐색기 페이지로 이동합니다.
쿼리 창에 다음 쿼리를 입력합니다.
logName="projects/project-name/logs/cloudaudit.googleapis.com/activity" resource.type="gce_firewall_rule"
쿼리 실행을 클릭합니다. 쿼리의 출력을 사용하여 변경사항이 있는지 확인합니다. 오류가 발견되면 오류를 수정하고 방화벽 규칙을 다시 적용합니다.
자동 방화벽 규칙은 변경하지 마세요.
방화벽 규칙이 변경되지 않은 경우 노드 풀 버전을 확인하고 컨트롤 플레인 및 다른 작동하는 노드 풀과 호환되는지 확인합니다. 클러스터의 노드 풀 중 컨트롤 플레인보다 오래된 부 버전이 2개 초과이면 문제가 발생할 수 있습니다. 이 비호환성에 관한 자세한 내용은 노드 버전이 제어 영역 버전과 호환되지 않음을 참고하세요.
요청이 올바른 kube-dns 서비스 IP로 전송되는지 확인하려면 문제가 있는 노드에서 네트워크 트래픽을 캡처하고 포트 53 (DNS 트래픽)을 필터링합니다. kube-dns 포드 자체에서 트래픽을 캡처하여 요청이 의도한 포드에 도달하고 있는지, 요청이 성공적으로 확인되는지 확인합니다.
다음 단계
- Kubernetes DNS 문제 진단에 대한 일반적인 정보는 DNS 변환 디버깅을 참조하세요.
- 추가 지원이 필요하면 Cloud Customer Care에 연락합니다.