Amazon EKS를 사용해 DNS 장애 문제를 해결하려면 어떻게 해야 하나요?

7분 분량
0

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

간략한 설명

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

서비스 개체 kube-dns는 CoreDNS 포드를 추상화합니다. CoreDNS 포드 문제를 해결하려면 서비스 엔드포인트 옵션 및 iptables 규칙과 같은 kube-dns 서비스 구성 요소의 작동 상태를 모두 확인하세요.

해결 방법

다음 해결 방법은 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이 있는지 확인하세요.

kube-proxy 로그 가져오기:

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

참고:****kube-proxy는 컨트롤 플레인에서 엔드포인트를 가져오고 모든 노드에 iptables 규칙을 생성합니다.

문제 발생 시 CoreDNS 포드의 CPU 사용률 확인

Amazon EKS CoreDNS 추가 기능에서 CoreDNS 포드의 메모리를 최대로 제한할 수 있는 용량은 170Mi입니다. CoreDNS 포드는 CPU를 제한하지 않기 때문에 컨테이너가 실행되는 노드에서 사용 가능한 모든 CPU 리소스를 사용할 수 있습니다. 노드 CPU 사용률이 100%에 도달하면 Amazon EKS 애플리케이션 로그에 DNS 시간 초과 오류가 발생할 수 있습니다. CoreDNS 포드에 DNS 쿼리를 모두 처리할 수 있는 충분한 CPU 리소스가 없기 때문에 이와 같은 오류가 발생합니다.

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

다음 단계를 완료하세요.

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

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

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

    “OCI 런타임 실행 실패: 실행 실패: container_linux.go:348: 컨테이너 프로세스 시작으로 인해 "exec: \"sh\ 발생: $PATH에서 실행 파일을 찾을 수 없습니다.”: 알 수 없는 명령으로 인해 종료 코드 126으로 종료됨

    디버그하려면 매니페스트 파일에 사용된 이미지를 다른 이미지(예: Docker 웹 사이트의 busybox 이미지)로 업데이트하세요.

  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 정책이 사용됩니다. ClusterFirst DNS 정책에 대한 자세한 내용은 Kubernetes 웹사이트에서 포드의 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_IPkubectl get 엔드포인트의 엔드포인트 IP 주소 중 하나로 바꾸세요.

디버깅할 CoreDNS 포드에서 더 상세한 로그 가져오기

다음 단계를 완료하세요.

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

    kubectl -n kube-system edit configmap coredns

    **참고:**자세한 내용은 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 값 업데이트

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는 쿼리된 도메인에서 점 다섯 개를 찾습니다. 포드가 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 포드에 부담을 줄 수 있습니다.

이 문제를 해결하려면 ndots1로 변경해 점을 하나만 찾도록 하세요. 쿼리하거나 사용하는 도메인 끝에 점(.)을 추가하세요.

nslookup example.com.

VPC 확인자(AmazonProvidedDNS) 제한 고려

Amazon Virtual Private Cloud(VPC) 확인자는 네트워크 인터페이스 한 개에 초당 최대 1024패킷만 허용하도록 엄격히 제한되어 있습니다. CoreDNS 포드 둘 이상이 동일한 노드에 있는 경우 외부 도메인 쿼리가 이 한도에 도달할 가능성이 높아집니다.

PodAntiAffinity 규칙을 사용해 CoreDNS 포드를 별도의 인스턴스에 스케줄링하려면 CoreDNS 배포에 다음 옵션을 추가하세요.

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

참고:****PodAntiAffinity에 대한 자세한 내용은 Kubernetes 웹사이트에서 포드 간 선호도 및 비선호도를 참고하세요.

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

tcpdump 도구를 사용해 패킷을 캡처하면 DNS 확인 문제를 진단하는 데 도움이 됩니다.

  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

    CoreDNS 서비스 IP 주소에도 동일한 쿼리를 실행합니다.

    nslookup amazon.com COREDNS_SERVICE_IP

    각 CoreDNS 포드 IP 주소에 쿼리를 실행합니다.

    nslookup amazon.com COREDNS\_POD\_IP

    **참고:**CoreDNS 포드를 여러 개 실행하는 경우, 여러 쿼리를 실행해 최소 쿼리 한 개가 트래픽을 캡처하려는 포드에 전송되도록 하세요.

  8. 패킷 캡처 결과를 검토하세요.

    모니터링 중인 CoreDNS 포드에서 DNS 쿼리 제한 시간이 초과되고 패킷 캡처에 쿼리가 표시되지 않는 경우 네트워크 연결을 확인하세요. 워커 노드 간 네트워크 연결성을 확인해야 합니다.

    캡처하지 않는 포드 IP 주소에 DNS 쿼리 제한 시간 초과가 표시되면 관련 워커 노드에서 패킷을 다시 캡처하세요.

    패킷 캡처 결과를 저장하려면 tcpdump 명령에 -w FILE_NAME 플래그를 추가합니다. 다음 예시에서는 capture.pcap이라는 파일에 결과를 씁니다.

    tcpdump -w capture.pcap udp port 53

관련 정보

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

(Kubernetes 웹사이트)

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