학습일지/kubernetes

Naver Engineering Day 2024 - Kubernetes에서 DNS 다루는 방법

inspirit941 2024. 6. 26. 10:38
반응형

 

https://d2.naver.com/helloworld/2905424

 

 

https://youtu.be/1UBgSARBdBc?si=07YbUP3GK5zpnGjT

 

 

 

문제

스크린샷 2024-06-26 오전 9 07 37스크린샷 2024-06-26 오전 9 10 27

 

k8s 클러스터 운영 도중, 일부 노드에서 특정 도메인 nslookup이 안 되는 현상 발생.

  • 원인: 해당 노드들의 망 구성이 달라서, 다른 nameserver 사용중이었음. nameserver는 변경할 수 없는 상황.
  • 특정 도메인일 경우에만 nameserver를 다르게 설정하려면 어떻게 해야 하나??

간단한 k8s 배경지식

스크린샷 2024-06-26 오전 9 12 22

 

  • pod는 고유한 ip를 갖는다.
  • pod는 동적으로 생성되며, 언제든 삭제될 수 있다. 재생성될 때, ip는 동적으로 변경된다.
  • Service를 사용해서, 동적으로 바뀌는 ip 집합인 여러 pod에 접근할 수 있는 단일 endpoint를 구성할 수 있다.

스크린샷 2024-06-26 오전 9 13 16

 

수많은 pod과 service를 직접 관리하기는 불편하기 때문에, domain name을 사용해서 pod나 service에 접근할 수 있게 되어 있음.

  • k8s 클러스터 내에 DNS 서버를 두고, pod과 service에 DNS record를 자동으로 생성, 관리.
  • 예시 - A record: ..svc.

Domain Resolving

스크린샷 2024-06-26 오전 9 15 01

 

pod 내부에서 도메인 조회하는 nslookup 명령어를 입력해보면

  • resolv.conf 에 정의된 nameserver ip주소를 토대로 DNS resolver 서버와 통신한다.

스크린샷 2024-06-26 오전 9 16 35

 

pod가 떠 있는 노드에 접근해서 nslookup 명령어를 입력해보면

  • resolv.conf에 저장된 nameserver ip주소가 pod과 다른 것을 확인할 수 있다.

스크린샷 2024-06-26 오전 9 18 02

 

pod에서 ip address로 검색해보면, 노드에서 DNS server로 사용한 Ip주소와 동일한 ip가 nodelocaldns 인터페이스에서 확인된다.

  • nodelocaldns: Nodelocal DNSCache 라는, k8s Daemonset으로부터 생성된 임시 인터페이스.

스크린샷 2024-06-26 오전 9 18 02스크린샷 2024-06-26 오전 9 19 46스크린샷 2024-06-26 오전 9 19 54스크린샷 2024-06-26 오전 9 19 59스크린샷 2024-06-26 오전 9 20 20

 

NodeLocalDNS는

  • 모든 노드에 Daemonset 형태로 실행되고
  • 모든 노드에서 로컬로 DNS query 실행해주기 위해 k8s Service도 배포되어 있고
  • 필요한 설정을 담고 있는 configmap도 배포되어 있다.

각 노드의 host network namespace에서 동작하고, nodelocaldns 라는 임시 인터페이스를 생성하고 있음.

스크린샷 2024-06-26 오전 9 23 03

 

정확히 뭘 실행하고 있는 건가? -> CoreDNS를 캐시 모드로 실행하고 있다.

  • coreDNS: DNS서버 역할을 할 수 있는 애플리케이션.
  • Corefile을 지정하면, 다양한 플러그인을 설정할 수 있다.

스크린샷 2024-06-26 오전 9 25 39

 

nodelocaldns의 configmap에 마운트되어 있는 Corefile을 확인해보면

  • cluster.local:53 = cluster.local 존의 53포트 (DNS) 로 들어오는 DNS query 처리하기 위한 설정.
    • cache: 성공한 응답 9984패킷은 30초 캐싱, 실패한 응답은 5초 캐싱.
    • bind: 169.254.20.10 주소로부터 온 DNS 쿼리를 처리한다. (pod 내부에서 조회할 수 있었던 nameserver 주소)
    • forward: 모든 DNS 쿼리를 10.96.0.10 TCP 통신으로 전송.

스크린샷 2024-06-26 오전 9 29 02

 

cluster.local 외의 DNS query는 노드에 정의된 /etc/resolv.conf 설정을 따라간다.

즉, kubernetes 내부 DNS query는 10.96.0.10이라는 ip로 TCP 포워딩하고
kubernetes 외부의 DNS query는 노드에 정의된 /etc/resolv.conf 설정을 따라간다.

pod에서 외부 DNS로 query 요청 시

스크린샷 2024-06-26 오전 9 32 28스크린샷 2024-06-26 오전 9 32 36스크린샷 2024-06-26 오전 9 34 31

 

Pod에서 외부 도메인으로 query 요청 시

  • Pod에 있는 nodelocaldns에 query 전달
    • cache 있을 경우 pod 내에서 처리
    • cache 없을 경우, pod가 배포된 node에 있는 Nameserver로 DNS query가 전달된다.

pod에서 내부 DNS로 query 요청 시

스크린샷 2024-06-26 오전 9 35 33스크린샷 2024-06-26 오전 9 36 00스크린샷 2024-06-26 오전 9 35 44스크린샷 2024-06-26 오전 9 38 47

 

pod에서 내부 도메인으로 query 요청 시 (예컨대 UDP)

  • Pod에 있는 nodelocaldns에 query 전달
    • cache 있을 경우 응답
    • cache 없을 경우, 요청을 TCP로 전환해서 10.96.0.10 (k8s service) 으로 포워딩.
    • 목적지 pod에서 응답을 받으면, pod내부의 nodelocaldns가 UDP로 전환해서 pod에 전달해준다.

의문점

스크린샷 2024-06-26 오전 9 39 40

 

  • 10.96.0.10은 뭐하는 녀석인가
  • 왜 TCP로 변환해주나?

스크린샷 2024-06-26 오전 9 41 00

 

10.96.0.10: kube-system에 배포된 kube-dns라는 k8s Service의 ip주소.

  • 이 Service는 어떤 pod들을 관리하고 있는지 selector로 확인해보면 {"k8s-app":"kube-dns"}를 확인할 수 있고
  • 이 label값을 가진 pod는 coreDNS deployment에서 관리중이다.

CoreDNS Deployment

스크린샷 2024-06-26 오전 9 42 56

 

k8s 클러스터 내부의 기본 DNS 서버. 클러스터 애드온으로, k8s 설치될 때 자동으로 배포 / 시작된다.

  • service나 pod 정보가 바뀌면, k8s apiserver 상태 변경을 확인해서 해당 리소스의 DNS record를 업데이트한다.
  • 클러스터 내부 / 외부 통신을 위한 DNS query를 처리하는 역할.

스크린샷 2024-06-26 오전 9 46 20스크린샷 2024-06-26 오전 9 46 38

 

k8s 1.13 이전 버전까지는 kubeDNS라는 걸 썼었기 때문에, 하위호환을 위해 Service 이름은 kube-dns로 유지되고 있음.

  • DNS 서버의 추상화 의미도 있음. 구현체 무관하게 kube-dns로.
  • nodelocaldns와 마찬가지로 configmap으로 설정파일 관리중.

CoreDNS의 Corefile

스크린샷 2024-06-26 오전 9 48 45

 

nodelocaldns와 달리, 모든 DNS query를 처리할 수 있게 cluster.local 설정이 없다.

  • kubernetes: k8s apiserver와 통신해서 리소스 변경을 실시간으로 감지하고, DNS record를 변경한다.
  • hosts: 특정 호스트명과 ip를 static하게 매핑할 수도 있음. 노드의 /etc/hosts 파일에 값을 입력해주면 된다.
  • 노드에 있는 /etc/resolv.conf 설정파일을 참고해서 외부 DNS서버로 query 포워딩한다.

스크린샷 2024-06-26 오전 9 51 52

 

따라서 pod에서 외부 DNS로 query를 보낼 경우

  • pod가 떠 있는 노드의 nodelocaldns에는 로그가 남지만, coreDNS에는 로그가 남지 않는다.
  • 즉 클러스터 외부로 나가는 query는 coreDNS가 아니라, 해당 pod가 배포된 노드의 nameserver가 처리한다.

스크린샷 2024-06-26 오전 9 54 41스크린샷 2024-06-26 오전 9 54 53스크린샷 2024-06-26 오전 9 55 59

 

pod에서 내부 DNS로 query를 보낼 경우

  • pod의 nodelocaldns 캐시가 있을 경우 바로 응답.
  • nodelocaldns에 캐시가 없을 경우 coreDNS가 처리한다.

의문점

Q. 어차피 결국 coreDNS에서 도메인 관련 내용 전부 처리하는데.. nodelocal의 DNSCache는 왜 필요한가?

  • 내부 DNS 정보도 응답해주고, 외부 DNS의 경우 노드의 nameserver로 넘겨주는 로직이 다 있으니

A. 그래서 Nodelocal DNSCache 컴포넌트는 필수 구성요소가 아니다. 그럼에도 쓸만한 이유는..

스크린샷 2024-06-26 오전 10 02 08

 

성능

  • 클러스터 규모가 커지면, 매번 네트워크 통신으로 ip / domain 정보 확인할수록 성능이 떨어진다.
  • 네트워크 거쳐가는 것보다, 노드 내에서 캐시된 값을 받는 게 DNS 응답속도가 훨씬 빠르다.

스크린샷 2024-06-26 오전 10 02 01

 

안정성

  • coreDNS에 장애가 발생해도, 캐시된 DNS정보를 활용하면 서비스 중단 가능성을 줄일 수 있다.
  • DNS query로 들어오는 트래픽을 분산하는 역할
    • 일단 각 노드에 캐시된 걸로 처리... 트래픽 분산 / 과부하 방지.

스크린샷 2024-06-26 오전 10 03 20

 

  • 리눅스에서 SNAT 사용했을 때의 문제 중 하나인 conntrack race condition 완화.
  • TCP 프로토콜 활용 -> 패킷손실 발생 시 재시도 가능.

DNS query 감당하기 위한 CoreDNS pod 개수는 어떻게 설정하는 게 좋을까?

스크린샷 2024-06-26 오전 10 05 41스크린샷 2024-06-26 오전 10 06 05스크린샷 2024-06-26 오전 10 07 48

 

cluster-proportional-autoscaler를 활용한다.

  • 클러스터 노드 / core 개수 기반으로 coreDNS pod개수 조정
    • autoscale을 위한 metric 확인 / pod개수 조정을 위한 RBAC 권한을 부여받는다. (serviceAccount)
  • 다양한 파라미터 조건을 조합해서 autoscale이 동작하도록 만들 수 있다.

Pod가 DNS에 안정적으로 query할 수 있도록 하는 정책들

스크린샷 2024-06-26 오전 10 23 06스크린샷 2024-06-26 오전 10 21 07스크린샷 2024-06-26 오전 10 22 25

 

네 가지 Policy가 있음.

  • default: pod가 배포된 노드 설정을 따라간다.
  • clusterFirst: 클러스터의 DNS서버를 활용한다. 따로 설정해주지 않을 경우 이게 기본 policy로 설정됨.

일반 Pod는 ClusterFirst 쓰면 되고, coreDNS와 nodelocaldns cache pod의 경우 default를 써야 한다.

  • 얘네는 DNS 작업을 처리하는 애들이므로, 배포된 노드의 DNS nameserver 세팅을 따라가야 하기 때문.

문제 해결

스크린샷 2024-06-26 오전 10 25 08

 

외부 DNS query는 nodelocal DNSCache에서 담당하므로, 노드의 Corefile을 수정한다.

  • 예컨대 abcxyz.com 이 문제라면, 이 도메인의 DNS query가 들어올 경우 관련 nameserver를 명시하는 식으로.

스크린샷 2024-06-26 오전 10 27 22

 

만약 nodelocal DNSCache를 안 쓰고 있다면?

  • coreDNS가 참조하는 Corefile을 변경해주면 된다.
반응형