Amazon EKS 관련 DNS 오류 문제를 해결하려면 어떻게 해야 하나요?

7분 분량
0

Amazon Elastic Kubernetes Service(Amazon EKS) 클러스터에서 CoreDNS를 사용하는 애플리케이션 또는 포드가 내부 또는 외부 DNS 이름 확인에 실패합니다.

간략한 설명

Amazon EKS 클러스터 내에서 실행되는 포드는 CoreDNS 서비스의 클러스터 IP를 내부 및 외부 DNS 레코드를 쿼리하기 위한 기본 이름 서버로 사용합니다. CoreDNS 포드, 서비스 구성 또는 연결에 문제가 있는 경우 애플리케이션이 DNS 확인에 실패할 수 있습니다.

CoreDNS 포드가 kube-dns라는 서비스 객체에 의해 추상화됩니다. CoreDNS 포드 관련 문제를 해결하려면 kube-dns 서비스의 모든 구성 요소가 작동하는지 확인해야 합니다. 이러한 구성 요소에는 서비스 엔드포인트 옵션과 iptables 규칙이 포함되지만 이에 국한되지는 않습니다.

해결 방법

다음 해결 방법은 CoreDNS ClusterIP 10.100.0.10에 적용됩니다.

1.    CoreDNS 서비스의 ClusterIP를 가져옵니다.

kubectl get service kube-dns -n kube-system

2.    DNS 엔드포인트가 노출되고 CoreDNS 포드를 가리키는지 확인합니다.

kubectl -n kube-system get endpoints kube-dns

출력:

NAME       ENDPOINTS                                                        AGE
kube-dns   192.168.2.218:53,192.168.3.117:53,192.168.2.218:53 + 1 more...   90d

참고: 엔드포인트 목록이 비어 있는 경우 CoreDNS 포드의 포드 상태를 확인하세요.

3.    CoreDNS와 통신할 때 보안 그룹 또는 네트워크 액세스 제어 목록(네트워크 ACL)이 포드를 차단하고 있지 않은지 확인합니다.

자세한 내용은 Amazon EKS에서 다른 포드에 내 포드가 연결되지 않는 이유는 무엇입니까?를 참조하세요.

kube-proxy 포드가 작동하는지 확인

kube-proxy 포드가 클러스터의 API 서버에 액세스할 수 있는지 확인하려면, 로그를 점검하여 제어 영역에 대한 제한 시간 오류가 있는지 확인하세요. 또한 403 Unauthorized 오류가 있는지 확인하세요.

kube-proxy 로그를 가져옵니다.

kubectl logs -n kube-system --selector 'k8s-app=kube-proxy'

참고: kube-proxy는 제어 영역에서 엔드포인트를 가져오고 모든 노드에서 iptables 규칙을 생성합니다.

애플리케이션 포드에 연결하여 DNS 문제 해결

1.    애플리케이션 포드 내에서 명령을 실행하려면 다음 명령을 실행하여 실행 중인 포드 내의 셸에 액세스합니다.

$ kubectl exec -it your-pod-name -- sh

애플리케이션 포드에 사용 가능한 셸 바이너리가 없는 경우, 다음과 유사한 오류가 발생합니다.

OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown
command terminated with exit code 126

디버깅하려면 매니페스트 파일에 사용된 이미지를 busybox 이미지(Docker 웹 사이트)와 같은 다른 이미지로 업데이트합니다.

2.    kube-dns 서비스의 클러스터 IP가 포드의 /etc/resolv.conf에 있는지 확인하려면 포드 내부의 셸에서 다음 명령을 실행합니다.

cat /etc/resolv.conf

다음 예시 resolv.conf는 DNS 요청에 대해 10.100.0.10을 향하도록 구성된 포드를 보여 줍니다. IP는 kube-dns 서비스의 ClusterIP와 일치해야 합니다.

nameserver 10.100.0.10
search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal
options ndots:5

참고: 포드 사양에서 dnsPolicy 필드를 사용하여 포드의 DNS 구성을 관리할 수 있습니다. 이 필드가 채워지지 않으면 기본적으로 ClusterFirst DNS 정책이 사용됩니다.

3.    포드가 기본 ClusterIP를 사용하여 내부 도메인을 확인할 수 있는지 확인하려면 포드 내부의 셸에서 다음 명령을 실행합니다.

nslookup kubernetes.default 10.100.0.10

출력:

Server:     10.100.0.10
Address:    10.100.0.10#53
Name:       kubernetes.default.svc.cluster.local
Address:    10.100.0.1

4.    포드가 기본 ClusterIP를 사용하여 외부 도메인을 확인할 수 있는지 확인하려면 포드 내부의 셸에서 다음 명령을 실행합니다.

nslookup amazon.com 10.100.0.10

출력:

Server:     10.100.0.10
Address:    10.100.0.10#53
Non-authoritative answer:
Name:   amazon.com
Address: 176.32.98.166
Name:    amazon.com
Address: 205.251.242.103
Name:    amazon.com
Address: 176.32.103.205

5.    포드가 CoreDNS 포드의 IP 주소를 사용하여 직접 확인할 수 있는지 확인하려면 포드 내부의 셸에서 다음 명령을 실행합니다.

nslookup kubernetes COREDNS_POD_IP

nslookup amazon.com COREDNS_POD_IP

참고: COREDNS_POD_IP를 이전에 사용한 kubectl 가져오기 엔드포인트의 엔드포인트 IP 중 하나로 바꿉니다.

디버깅을 위해 CoreDNS 포드에서 상세 로그 가져오기

1.    CoreDNS 포드의 디버그 로그를 켜고 CoreDNS ConfigMap에 로그 플러그인을 추가합니다.

kubectl -n kube-system edit configmap coredns

2.    출력에 나타나는 편집기 화면에서 로그 문자열을 추가합니다. 예를 들면 다음과 같습니다.

kind: ConfigMap
apiVersion: v1
data:
  Corefile: |
    .:53 {
        log    # Enabling CoreDNS Logging
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          upstream
          fallthrough in-addr.arpa ip6.arpa
        }
        ...
...

참고: 구성 CoreDNS를 다시 로드하는 데 몇 분 소요됩니다. 변경 사항을 즉시 적용하려면 포드를 하나씩 다시 시작합니다.

3.    CoreDNS 로그가 실패하거나 애플리케이션 포드에서 적중이 발생하는지 확인합니다.

kubectl logs --follow -n kube-system --selector 'k8s-app=kube-dns'

ndots 값 업데이트

DNS는 이름 확인을 위해 nameserver를 사용하며, 이는 일반적으로 kube-dns 서비스의 ClusterIP입니다. DNS는 정규화된 도메인 이름에 대한 쿼리 이름을 작성하기 위해 검색을 사용합니다. ndots 값은 초기 절대 쿼리가 수행되기 전에 쿼리를 해결하기 위해 이름에 표시되어야 하는 점의 수입니다.

예를 들어 정규화되지 않은 도메인 이름에서 ndots 옵션을 기본값 5로 설정할 수 있습니다. 그러면 내부 도메인 cluster.local에 속하지 않는 모든 외부 도메인이 쿼리 전에 검색 도메인에 추가됩니다.

애플리케이션 포드의 /etc/resolv.conf 설정과 함께 다음 예시를 참조하세요.

nameserver 10.100.0.10
search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal
options ndots:5

CoreDNS는 쿼리되는 도메인에서 점 5개를 찾습니다. 포드가 amazon.com에 대한 DNS 확인을 호출하는 경우 로그가 다음과 같이 표시됩니다.

[INFO] 192.168.3.71:33238 - 36534 "A IN amazon.com.default.svc.cluster.local. udp 54 false 512" NXDOMAIN qr,aa,rd 147 0.000473434s
[INFO] 192.168.3.71:57098 - 43241 "A IN amazon.com.svc.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000066171s
[INFO] 192.168.3.71:51937 - 15588 "A IN amazon.com.cluster.local. udp 42 false 512" NXDOMAIN qr,aa,rd 135 0.000137489s
[INFO] 192.168.3.71:52618 - 14916 "A IN amazon.com.ec2.internal. udp 41 false 512" NXDOMAIN qr,rd,ra 41 0.001248388s
[INFO] 192.168.3.71:51298 - 65181 "A IN amazon.com. udp 28 false 512" NOERROR qr,rd,ra 106 0.001711104s

참고: NXDOMAIN은 도메인 레코드를 찾을 수 없음을 의미하고, NOERROR는 도메인 레코드를 찾았음을 의미합니다.

마지막에 절대 도메인에서 최종 호출이 이루어지기 전에 모든 검색 도메인 앞에 amazon.com이 추가됩니다. 최종 도메인 이름 끝에 점(.)이 추가되어 정규화된 도메인 이름이 됩니다. 즉, 모든 외부 도메인 이름 쿼리에 대해 4~5개의 추가 호출이 있을 수 있으며, 이로 인해 CoreDNS 포드에 과부하가 발생할 수 있습니다.

이 문제를 해결하려면 ndots를 점 하나만 표시되는 1로 변경합니다. 또는 쿼리하거나 사용하는 도메인의 끝에 점(.)을 추가합니다. 예를 들면 다음과 같습니다.

nslookup example.com.

VPC 해석기(AmazonProvidedDNS) 제한 고려

Amazon Virtual Private Cloud(Amazon VPC) 해석기는 네트워크 인터페이스 하나에 초당 1,024개의 패킷의 최대 하드 제한만 허용할 수 있습니다. 동일한 노드에 2개 이상의 CoreDNS 포드가 있으면 외부 도메인 쿼리의 경우 이 제한에 도달할 확률이 더 높습니다.

PodAntiAffinity(Kubernetes 웹 사이트 제공) 규칙을 사용하여 별도의 인스턴스에서 CoreDNS 포드를 예약하려면 CoreDNS 배포에 다음 옵션을 추가합니다.

podAntiAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - podAffinityTerm:
      labelSelector:
        matchExpressions:
        - key: k8s-app
          operator: In
          values:
          - kube-dns
      topologyKey: kubernetes.io/hostname
    weight: 100

tcpdump를 사용하여 Amazon EKS 워커 노드에서 CoreDNS 패킷을 캡처

tcpdump 도구를 사용하여 DNS 확인 문제를 진단하는 데 도움이 되는 패킷 캡처를 수행합니다. 이 도구는 DNS 요청에 대한 네트워크 트래픽이 CoreDNS 포드에 도달하는지 여부와 기본 네트워크 연결 문제가 있는지 확인하는 데 도움이 됩니다. tcpdump를 사용하려면 다음 단계를 완료합니다.

1.    CoreDNS 포드가 실행 중인 작업자 노드를 찾습니다.

kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide

2.    SSH를 사용하여 CoreDNS 포드가 실행 중인 작업자 노드에 연결하고 tcpdump 도구를 설치합니다.

sudo yum install tcpdump –y

3.    작업자 노드에서 CoreDNS 포드 프로세스 ID를 찾습니다.

ps ax | grep coredns

4.    작업자 노드에서 CoreDNS 포드 네트워크의 패킷 캡처를 수행하여 UDP 포트 53의 네트워크 트래픽을 모니터링합니다.

sudo nsenter -n -t PID tcpdump udp port 53

5.    별도의 터미널에서 CoreDNS 서비스와 포드 IP를 가져옵니다.

kubectl describe svc kube-dns -n kube-system

참고: 'IP' 필드에 있는 서비스 IP와 '엔드포인트' 필드에 있는 포드 IP를 기록해 둡니다.

6.    DNS 서비스를 테스트할 포드를 시작합니다. 다음 예시에서는 Ubuntu 컨테이너 이미지를 사용합니다.

kubectl run ubuntu --image=ubuntu sleep 1d

kubectl exec -it ubuntu sh

7.    nslookup 도구를 사용하여 amazon.com과 같은 도메인에 대한 DNS 쿼리를 수행합니다.

nslookup amazon.com

5단계부터 CoreDNS 서비스 IP에 대해 동일한 쿼리를 명시적으로 수행합니다.

nslookup amazon.com COREDNS_SERVICE_IP

5단계의 각 CoreDNS 포드 IP에 대해 쿼리를 수행합니다.

nslookup amazon.com COREDNS_POD_IP

참고: 여러 CoreDNS 포드가 실행 중인 경우 트래픽을 캡처하는 포드로 하나 이상의 쿼리가 전송되도록 여러 쿼리를 수행합니다.

8.    패킷 캡처 결과를 검토합니다.

모니터링 중인 CoreDNS 포드에 DNS 쿼리 제한 시간이 발생하고 패킷 캡처에 쿼리가 표시되지 않는 경우 네트워크 연결 문제가 있을 수 있습니다. 작업자 노드 간의 네트워크 연결 가능성을 확인합니다.

캡처하지 않는 포드 IP에 대한 DNS 쿼리 제한 시간이 관찰되면 2~4단계에 따라 관련 워커 노드에서 다른 패킷 캡처를 수행합니다.

나중에 참조할 수 있도록 패킷 캡처 결과를 저장하려면 tcpdump 명령에 -w FILE_NAME 플래그를 추가합니다. 다음 예시에서는 capture.pcap라는 파일에 결과를 기록합니다.

tcpdump -w capture.pcap udp port 53

관련 정보

Kubernetes 클러스터 DNS용 CoreDNS 정식 버전

AWS 공식
AWS 공식업데이트됨 8달 전