콘텐츠로 이동

10. 클러스터 DNS

이름이 IP가 되는 과정

Terminal window
kubectl get deploy coredns -n kube-system
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get svc kube-dns -n kube-system
# NAME TYPE CLUSTER-IP PORT(S)
# kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP

특별한 시스템이 아니라 그냥 Deployment + Service다. 그래서 똑같이 고장 나고 똑같이 고친다.

flowchart LR
    POD["앱 Pod<br/>/etc/resolv.conf 의<br/>nameserver 10.96.0.10"]
    POD --> SVC["Service kube-dns<br/>ClusterIP 10.96.0.10"]
    SVC --> EP["EndpointSlice"]
    EP --> C1["CoreDNS Pod 1"]
    EP --> C2["CoreDNS Pod 2"]
    C1 --> K["kubernetes 플러그인<br/>Service · Pod 이름 해석"]
    C1 --> F["forward 플러그인<br/>그 밖의 도메인 → 노드 리졸버"]

    classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef dns fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class SVC key
    class C1,C2 dns
    class POD,EP,K,F mute
  • CoreDNS는 평범한 Deployment다. 보통 2개의 레플리카로 돈다
  • 앞에 kube-dns라는 Service가 있다 (이름이 옛날 그대로다)
  • 그 ClusterIP가 모든 Pod의 네임서버로 들어간다

Service의 정식 이름(FQDN)은 이렇게 생겼다.

flowchart LR
    A["web-svc"] --> B["prod"] --> C["svc"] --> D["cluster.local"]
    A1["서비스 이름"] -.-> A
    B1["네임스페이스"] -.-> B
    C1["리소스 종류<br/>svc 또는 pod"] -.-> C
    D1["클러스터 도메인<br/>기본값"] -.-> D

    classDef part fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef label fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class A,B,C,D part
    class A1,B1,C1,D1 label
어디서 부르나 쓸 수 있는 이름
같은 네임스페이스 web-svc
다른 네임스페이스 web-svc.prod
어디서나 (완전한 이름) web-svc.prod.svc.cluster.local

headless Service의 Pod별 이름

파드이름.서비스이름.네임스페이스.svc.cluster.local
예: db-0.db-headless.default.svc.cluster.local

Terminal window
kubectl exec -it web -- cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
  • nameserverkube-dns Service의 ClusterIP
  • search — 짧은 이름을 순서대로 붙여본다
  • ndots:5 — 점이 5개 미만인 이름은 search 도메인을 먼저 시도한다
flowchart TD
    Q["web-svc 를 조회"] --> N{"점이 5개 이상인가<br/>ndots:5"}
    N -->|"아니다 · 점 0개"| S1["① web-svc.default.svc.cluster.local"]
    S1 -->|"성공"| OK["해석 완료 ✅"]
    S1 -->|실패| S2["② web-svc.svc.cluster.local"]
    S2 -->|실패| S3["③ web-svc.cluster.local"]
    S3 -->|실패| S4["④ web-svc 그대로 조회"]
    S4 -->|실패| NX["NXDOMAIN ❌"]
    N -->|"그렇다"| DIRECT["search 를 건너뛰고 바로 조회"]

    classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef bad fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    classDef step fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class OK,DIRECT ok
    class NX bad
    class S1,S2,S3,S4 step
    class Q,N mute
spec:
dnsPolicy: ClusterFirst # 기본
dnsConfig:
nameservers: ["8.8.8.8"]
searches: ["custom.local"]
options:
- name: ndots
value: "2"

ClusterFirst

클러스터 DNS를 먼저. 기본값이다.

ClusterFirstWithHostNet

hostNetwork: true인 Pod도 클러스터 DNS를 쓰게 한다.

Default

노드의 /etc/resolv.conf를 그대로 쓴다. 이름과 달리 기본값이 아니다.

None

전부 dnsConfig로 직접 지정한다.

flowchart LR
    H["hostNetwork: true Pod"] --> D{"dnsPolicy"}
    D -->|"ClusterFirst · 기본"| B["노드 DNS 를 쓰게 된다<br/>클러스터 서비스 이름 해석 실패 ❌"]
    D -->|ClusterFirstWithHostNet| G["클러스터 DNS 사용<br/>정상 ✅"]

    classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef bad fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class G ok
    class B bad
    class H,D mute
Terminal window
kubectl get cm coredns -n kube-system -o yaml
kubectl edit cm coredns -n kube-system
.:53 {
errors
health { lameduck 5s }
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf { max_concurrent 1000 } # 외부 질의는 노드 DNS로
cache 30
loop
reload
loadbalance
}

질의 하나가 이 플러그인 체인을 순서대로 통과한다.

flowchart LR
    Q["질의"] --> CA["cache<br/>있으면 바로 응답"]
    CA -->|"miss"| K{"kubernetes 플러그인<br/>cluster.local 인가"}
    K -->|"그렇다"| KR["Service · Pod 이름 해석 → 응답"]
    K -->|"아니다 · fallthrough"| FW["forward<br/>노드 /etc/resolv.conf 로"]
    FW --> EXT["외부 DNS 응답"]

    classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class K,FW key
    class KR,EXT ok
    class Q,CA mute
  • kubernetes 플러그인이 Service/Pod 이름을 담당한다
  • forward 가 그 밖의 도메인을 노드의 리졸버로 넘긴다
  • reload 덕분에 ConfigMap을 고치면 재시작 없이 반영된다 (몇십 초)

특정 도메인을 다른 곳으로 보내기

섹션 제목: “특정 도메인을 다른 곳으로 보내기”
# Corefile에 스탠자를 추가한다
example.internal:53 {
errors
cache 30
forward . 192.168.10.53
}
  • 사내 DNS로 특정 존만 보낼 때 쓰는 표준 패턴이다
  • hosts 플러그인으로 정적 매핑도 가능하다
hosts {
192.168.10.50 legacy.internal
fallthrough
}

수정 후에는 CoreDNS 로그로 문법 오류가 없는지 확인한다. kubectl logs -n kube-system -l k8s-app=kube-dns

  1. 디버그 Pod에서 조회 — 기준점 테스트부터

    Terminal window
    kubectl run tmp --image=busybox:1.36 --rm -it --restart=Never -- sh
    nslookup kubernetes.default # ★ 이게 되면 DNS 는 정상
    nslookup web-svc
    nslookup web-svc.default.svc.cluster.local
    cat /etc/resolv.conf
  2. CoreDNS 자체 상태

    Terminal window
    kubectl get pods -n kube-system -l k8s-app=kube-dns
    kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
    kubectl get svc kube-dns -n kube-system
    kubectl get endpoints kube-dns -n kube-system # ★ 비어 있으면 CoreDNS Pod이 없다
  3. 설정 확인

    Terminal window
    kubectl get cm coredns -n kube-system -o yaml
flowchart TD
    S{"무엇이 안 되나"}
    S -->|"모든 이름"| A["CoreDNS Pod 다운<br/>kube-dns 엔드포인트가 비어 있다"]
    S -->|"클러스터 이름만"| B["Corefile 의 kubernetes 플러그인 이상<br/>또는 dnsPolicy 잘못"]
    S -->|"외부 도메인만"| C["forward 대상 문제<br/>노드 /etc/resolv.conf 확인"]
    S -->|"특정 네임스페이스만"| D["짧은 이름을 썼다<br/>→ FQDN 이 필요"]
    S -->|"이름은 되는데 연결이 안 됨"| E["Service · 엔드포인트 문제 · 9장<br/>또는 NetworkPolicy · 12장"]
    S -->|"간헐적으로 느리다"| F["ndots:5 로 인한 불필요한 조회<br/>CoreDNS 레플리카 부족"]

    classDef bad fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
    class A bad
    class B,C,D,E,F warn
    class S mute
증상 원인 후보
모든 이름이 안 된다 CoreDNS Pod 다운, kube-dns 엔드포인트 비어 있음
클러스터 이름만 안 된다 Corefile의 kubernetes 플러그인 이상, dnsPolicy 잘못
외부 도메인만 안 된다 forward 대상(노드 resolv.conf) 문제
특정 네임스페이스만 안 된다 짧은 이름을 썼다 → FQDN 필요
DNS는 되는데 연결이 안 된다 Service/엔드포인트 문제 (9장) 또는 NetworkPolicy (12장)
간헐적으로 느리다 ndots:5로 인한 불필요한 조회, CoreDNS 레플리카 부족
  • CoreDNS는 평범한 Deployment, 앞의 Service 이름은 여전히 kube-dns
  • 이름 규칙: 서비스.네임스페이스.svc.cluster.local
  • Pod의 /etc/resolv.conf네임서버 + search 도메인 + ndots:5 가 들어간다
  • ndots:5가 외부 도메인 조회를 느리게 만든다 — 끝에 점을 찍으면 우회
  • hostNetwork Pod은 ClusterFirstWithHostNet 이 필요하다
  • 설정은 kube-systemcoredns ConfigMap(Corefile). reload로 자동 반영
  • 기준점 테스트: nslookup kubernetes.default
  • egress NetworkPolicy는 DNS(UDP 53)를 반드시 허용해야 한다