서비스와 파드의 DNS

서비스와 파드의 DNS (dns-pod-service)

워크로드는 DNS를 사용해서 클러스터 안의 Service를 발견할 수 있어요. 이 페이지는 그 동작 방식을 설명해 줍니다.

Kubernetes는 Service와 Pod용 DNS 레코드를 만들어요. IP 주소 대신 일관된 DNS 이름으로 Service에 접속할 수 있죠. Kubernetes는 DNS를 프로그래밍하는 데 사용되는 파드와 Service에 관한 정보를 게시해요. kubelet은 파드의 DNS를 구성해서 실행 중인 컨테이너가 IP가 아닌 이름으로 Service를 조회할 수 있게 해줘요.

클러스터에서 정의된 Service에는 DNS 이름이 할당돼요. 기본적으로 클라이언트 파드의 DNS 검색 목록에는 파드 자신의 네임스페이스와 클러스터의 기본 도메인이 포함돼요.

Service의 네임스페이스

DNS 쿼리는 쿼리를 하는 파드의 네임스페이스에 따라 다른 결과를 반환할 수 있어요. 네임스페이스를 명시하지 않은 DNS 쿼리는 파드의 네임스페이스로 제한돼요. DNS 쿼리에서 지정해서 다른 네임스페이스의 Service에 접근할 수 있어요.

예를 들어 test 네임스페이스에 파드가 있고, data Service는 prod 네임스페이스에 있다고 해볼게요. data에 대한 쿼리는 파드의 test 네임스페이스를 사용하므로 결과를 반환하지 않아요. data.prod에 대한 쿼리는 네임스페이스를 지정하므로 의도한 결과를 반환하죠.

DNS 쿼리는 파드의 /etc/resolv.conf를 사용해 확장될 수 있어요. kubelet은 각 파드에 대해 이 파일을 구성해요. 예를 들어 data만에 대한 쿼리는 data.test.svc.cluster.local로 확장될 수 있어요. search 옵션의 값이 쿼리를 확장하는 데 사용돼요. DNS 쿼리에 대해 더 알아보려면 resolv.conf 매뉴얼 페이지를 참고하세요.

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

요약하면, test 네임스페이스의 파드는 data.prod 또는 data.prod.svc.cluster.local을 성공적으로 해석할 수 있어요.

DNS 레코드

어떤 객체가 DNS 레코드를 받을까요?

  1. Service
  2. Pod

Service

A/AAAA 레코드

'일반'(헤드리스가 아닌) Service에는 Service의 IP 패밀리 또는 패밀리들에 따라 my-svc.my-namespace.svc.cluster-domain.example 형태의 이름으로 DNS A 및/또는 AAAA 레코드가 할당돼요. 이것은 Service의 클러스터 IP로 해석돼요.

헤드리스 Service(클러스터 IP 없음)에도 my-svc.my-namespace.svc.cluster-domain.example 형태의 이름으로 DNS A 및/또는 AAAA 레코드가 할당돼요. 일반 Service와 달리, 이것은 Service가 선택한 모든 파드의 IP 집합으로 해석돼요. 클라이언트는 이 집합을 소비하거나 집합에서 표준 라운드로빈 선택을 사용할 것으로 기대돼요.

SRV 레코드

SRV 레코드는 일반 또는 헤드리스 Service의 일부인 **이름이 지정된 포트(named port)**에 대해 생성돼요.

  • 각 명명된 포트에 대해 SRV 레코드는 _포트-이름._포트-프로토콜.my-svc.my-namespace.svc.cluster-domain.example 형태를 가져요.
  • 일반 Service의 경우 이 레코드는 포트 번호와 도메인 이름 my-svc.my-namespace.svc.cluster-domain.example으로 해석돼요.
  • 헤드리스 Service의 경우 이 레코드는 Service를 지원하는 각 파드마다 하나씩 여러 응답으로 해석되며, hostname.my-svc.my-namespace.svc.cluster-domain.example 형태의 파드의 포트 번호와 도메인 이름을 포함해요.

Pod

A/AAAA 레코드

DNS 사양 구현 이전의 Kube-DNS 버전은 다음과 같은 DNS 해석 규칙을 가졌어요.

<pod-IPv4-address>.<namespace>.pod.<cluster-domain>

예를 들어 default 네임스페이스의 파드가 IP 주소 172.17.0.3을 갖고, 클러스터 도메인 이름이 cluster.local이라면, 그 파드는 172-17-0-3.default.pod.cluster.local이라는 DNS 이름을 가져요.

CoreDNS 같은 일부 클러스터 DNS 메커니즘은 다음에 대한 A 레코드도 제공해요.

<pod-ipv4-address>.<service-name>.<my-namespace>.svc.<cluster-domain.example>

예를 들어 cafe 네임스페이스의 파드가 IP 주소 172.17.0.3을 갖고, barista라는 이름의 Service의 엔드포인트이며, 클러스터 도메인 이름이 cluster.local이라면, 그 파드는 172-17-0-3.barista.cafe.svc.cluster.local이라는 서비스 범위 DNS A 레코드를 가져요.

파드의 hostname과 subdomain 필드

현재 파드가 생성될 때 (파드 내부에서 관찰되는) 호스트네임은 파드의 metadata.name 값이에요.

Pod spec에는 선택적인 hostname 필드가 있어서 다른 호스트네임을 지정할 수 있어요. 지정되면 (다시 파드 내부에서 관찰되는) 호스트네임으로 파드 이름보다 우선해요.

Pod spec에는 선택적인 subdomain 필드도 있어서 파드가 네임스페이스의 하위 그룹에 속함을 나타낼 수 있어요. 예를 들어 spec.hostname"foo"로, spec.subdomain"bar"로 설정된, my-namespace 네임스페이스의 파드는...

파드와 같은 네임스페이스에 서브도메인과 같은 이름의 헤드리스 Service가 존재하면, 클러스터 DNS 서버는 파드의 정규화된 호스트네임에 대한 A 및/또는 AAAA 레코드도 반환해요.

apiVersion: v1
kind: Service
metadata:
  name: busybox-subdomain
spec:
  selector:
    name: busybox
  clusterIP: None
  ports:
  - name: foo # 이름은 단일 포트 Service에는 필수가 아님
    port: 1234
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox1
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: busybox-subdomain
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox2
  labels:
    name: busybox
spec:
  hostname: busybox-2
  subdomain: busybox-subdomain
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox

위의 "busybox-subdomain" Service와 spec.subdomain"busybox-subdomain"으로 설정한 파드가 주어지면, 첫 번째 파드는 자신의 FQDN을 "busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example"로 보게 돼요. DNS는 그 이름에 A 및/또는 AAAA 레코드를 제공하고, 파드의 IP를 가리켜요. "busybox1"과 "busybox2" 두 파드 모두 각자의 주소 레코드를 가지게 돼요.

참고:

파드에 hostname이 없으면 파드 이름에 대한 A 및 AAAA 레코드는 생성되지 않아요. hostname 없이 subdomain만 있는 파드는 헤드리스 Service(busybox-subdomain.my-namespace.svc.cluster-domain.example)에 대한 A 또는 AAAA 레코드만 생성하며, 이 레코드는 파드들의 IP 주소를 가리켜요. 또한 Service에 publishNotReadyAddresses=True가 설정되지 않으면 파드는 레코드를 가지려면 ready 상태여야 해요.

파드의 setHostnameAsFQDN 필드

파드가 정규화된 도메인 이름(FQDN)을 가지도록 구성되면, 그 호스트네임은 짧은 호스트네임이에요. 예를 들어 FQDN busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example를 가진 파드가 있다면, 기본적으로 파드 안의 hostname 커맨드는 busybox-1을 반환하고 hostname --fqdn 커맨드는 FQDN을 반환해요.

Pod spec에 setHostnameAsFQDN: true를 설정하면 kubelet이 그 파드의 네임스페이스에 대한 호스트네임에 FQDN을 기록해요. 이 경우 hostnamehostname --fqdn 모두 파드의 FQDN을 반환해요.

참고:

파드가 이 기능을 활성화하고 FQDN이 64자를 초과하면 시작에 실패해요. 파드는 Pending 상태(kubectl로 보면 ContainerCreating)로 남아 'Failed to construct FQDN from Pod hostname and cluster domain' 같은 오류 이벤트를 생성해요. FQDN long-FQDN이 너무 깁니다(최대 64자, 요청된 것은 70자). 이 시나리오에서 사용자 경험을 개선하는 한 가지 방법은 사용자가 Deployment 같은 최상위 객체를 만들 때 FQDN 크기를 제어하는 어드미션 웹훅 컨트롤러를 만드는 거예요.

파드의 DNS 정책

DNS 정책은 파드 단위로 설정할 수 있어요. 현재 Kubernetes는 다음 파드별 DNS 정책을 지원해요. 이 정책들은 Pod spec의 dnsPolicy 필드에 지정돼요.

  • "Default": 파드가 실행되는 노드에서 이름 해석 구성을 상속받아요. 관련 논의를 참고하세요.
  • "ClusterFirst": 클러스터 도메인 접미사와 일치하지 않는 DNS 쿼리(예: "www.kubernetes.io")는 업스트림으로 전달돼요.
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: busybox
  restartPolicy: Always
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet

파드의 DNS 구성

기능 상태: Kubernetes v1.14부터 Stable

파드의 DNS 구성은 사용자에게 파드의 DNS 설정에 대한 더 많은 제어권을 줘요. dnsConfig 필드는 선택 사항이며 어떤 dnsPolicy 설정과도 함께 동작해요. 단, 파드의 dnsPolicy가 "None"으로 설정되면 dnsConfig 필드를 반드시 지정해야 해요.

  • nameservers: 파드의 DNS 서버로 사용될 IP 주소 목록이에요. 최대 3개의 IP 주소를 지정할 수 있어요. 파드의 dnsPolicy가 "None"으로 설정되면 목록은 최소 하나의 IP 주소를 포함해야 해요. 그 외에는 이 속성은 선택 사항이에요.
  • searches: 선택한 DNS 정책에서 생성된 기본 검색 도메인 이름에 병합되는 DNS 검색 도메인 목록이에요. 중복 도메인 이름은 제거돼요. Kubernetes는 최대 32개의 검색 도메인을 허용해요.
  • options: 선택적인 객체 목록인데, 각 객체는 name 속성(필수)과 value 속성(선택)을 가질 수 있어요.

다음은 사용자 지정 DNS 설정을 가진 파드의 예시예요.

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
  - name: test
    image: nginx
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
    - 192.0.2.1 # this is an example
    searches:
    - ns1.svc.cluster-domain.example
    - my.dns.search.suffix
    options:
    - name: ndots
      value: "2"
    - name: edns0

위 파드가 생성되면 test 컨테이너는 /etc/resolv.conf 파일에 다음 내용을 가지게 돼요.

nameserver 192.0.2.1
search ns1.svc.cluster-domain.example my.dns.search.suffix
options ndots:2 edns0

IPv6 설정의 경우 검색 경로와 이름 서버는 이렇게 설정돼요.

DNS 검색 도메인 목록 제한

Kubernetes 자체는 검색 도메인 목록의 길이가 32를 초과하거나 모든 검색 도메인의 총 길이가 2048을 초과할 때까지 DNS 구성에 제한을 두지 않아요. 이 제한은 노드의 리졸버 구성 파일, 파드의 DNS 구성, 병합된 DNS 구성에 각각 적용돼요.

참고:

일부 이전 버전의 컨테이너 런타임은 DNS 검색 도메인의 수에 자체 제한이 있을 수 있어요. 컨테이너 런타임 환경에 따라, DNS 검색 도메인이 많은 파드는 pending 상태에 갇힐 수 있어요. containerd v1.5.5 이하와 CRI-O v1.21 이하가 이 문제가 있는 것으로 알려져 있어요.

Windows 노드의 DNS 해석

Windows에서는 DNS 접미사를 1개만 가질 수 있어요. 이것은 그 파드의 네임스페이스와 연관된 DNS 접미사(예: mydns.svc.cluster.local)예요. Windows는 이 단일 접미사로 해석할 수 있는 FQDN, Service, 또는 네트워크 이름을 해석할 수 있어요. 예를 들어 default 네임스페이스에서 생성된 파드는 DNS 접미사 default.svc.cluster.local를 가져요. Windows 파드 내부에서는 kubernetes.default.svc.cluster.localkubernetes를 모두 해석할 수 있지만, 부분 정규화된 이름(kubernetes.default 또는 kubernetes.default.svc)은 해석할 수 없어요.