Service discovery bằng DNS

Kubernetes chạy CoreDNS trong cluster (namespace kube-system). Mỗi Service tự động có DNS record:

<service-name>.<namespace>.svc.cluster.local

Ví dụ:
my-api.default.svc.cluster.local     → ClusterIP 10.96.0.15
postgres.production.svc.cluster.local → ClusterIP 10.96.3.42

Pod gọi service cùng namespace → chỉ cần tên ngắn:

# Cùng namespace
curl http://my-api:80

# Khác namespace
curl http://my-api.staging:80

# FQDN đầy đủ (chậm nhất do skip search)
curl http://my-api.staging.svc.cluster.local:80

DNS records cho Service

ClusterIP Service

my-api.default.svc.cluster.local.  →  A record  →  10.96.0.15

Headless Service (clusterIP: None)

my-db.default.svc.cluster.local.  →  A records  →  10.244.0.5
                                                     10.244.1.3
                                                     10.244.2.7

Mỗi pod backend có record riêng. Client nhận danh sách IP, chọn pod.

StatefulSet + Headless Service

Mỗi pod có DNS name riêng:

my-db-0.my-db.default.svc.cluster.local  →  10.244.0.5
my-db-1.my-db.default.svc.cluster.local  →  10.244.1.3
my-db-2.my-db.default.svc.cluster.local  →  10.244.2.7

SRV records

Service có port name → có SRV record:

_http._tcp.my-api.default.svc.cluster.local → SRV → port 80

resolv.conf trong Pod

Kubelet cấu hình DNS cho mỗi pod:

kubectl exec my-app -- cat /etc/resolv.conf
# nameserver 10.96.0.10               ← CoreDNS ClusterIP
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

Search domains

Khi bạn gọi my-api, resolver thử:

  1. my-api.default.svc.cluster.local (search domain 1)
  2. my-api.svc.cluster.local (search domain 2)
  3. my-api.cluster.local (search domain 3)
  4. my-api. (absolute name)

Tên ngắn my-api resolve qua search domain đầu tiên → nhanh (1 query).

ndots:5 và hiệu ứng

ndots:5 nghĩa là: nếu tên có ít hơn 5 dấu chấm, thử search domains trước, rồi mới thử absolute.

Hậu quả: gọi api.example.com (2 dots < 5) → resolver thử:

  1. api.example.com.default.svc.cluster.local (fail)
  2. api.example.com.svc.cluster.local (fail)
  3. api.example.com.cluster.local (fail)
  4. api.example.com. (thành công)

4 DNS queries thay vì 1. Với external domain gọi nhiều → gấp 4 lần DNS traffic.

Giải pháp:

# Option 1: FQDN có dấu chấm cuối
# Trong code: gọi "api.example.com." (trailing dot) → skip search
# Hoặc thiết lập ở pod spec:

spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2" # Giảm ndots cho pod gọi nhiều external

CoreDNS

Kiến trúc

CoreDNS chạy như Deployment trong kube-system, thường 2 replicas. Config qua ConfigMap coredns:

kubectl -n kube-system get cm coredns -o yaml

Corefile mặc định

.: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
    }
    cache 30
    loop
    reload
    loadbalance
}
  • kubernetes plugin: resolve service/pod names.
  • forward: external domains forward tới upstream DNS (node’s resolv.conf).
  • cache 30: cache DNS 30 giây.

Stub domain (custom DNS zone)

Nếu internal domain corp.example.com dùng DNS server riêng:

corp.example.com:53 {
    errors
    cache 30
    forward . 10.0.0.53    # Corporate DNS server
}

Debug DNS trong Pod

Bước 1: Tạo debug pod

kubectl run dns-debug --image=busybox:1.36 --restart=Never -- sleep 3600
kubectl exec -it dns-debug -- sh

Bước 2: Kiểm tra resolve

# nslookup
nslookup my-api
nslookup my-api.default.svc.cluster.local
nslookup google.com

# Hoặc dùng image có dig
kubectl run dns-debug --image=tutum/dnsutils --restart=Never -- sleep 3600
kubectl exec -it dns-debug -- dig my-api.default.svc.cluster.local

Bước 3: Kiểm tra CoreDNS

# CoreDNS pods chạy?
kubectl -n kube-system get pods -l k8s-app=kube-dns

# CoreDNS logs
kubectl -n kube-system logs -l k8s-app=kube-dns

# CoreDNS Service (DNS ClusterIP)
kubectl -n kube-system get svc kube-dns

Lỗi thường gặp

Triệu chứngNguyên nhân
nslookup: can't resolveCoreDNS pod crash, Service selector sai, hoặc service không tồn tại
Resolve chậm (> 5s)ndots:5 + external domain → nhiều query. Giảm ndots hoặc dùng FQDN
Resolve OK nhưng connect failDNS đúng nhưng port/targetPort sai, hoặc NetworkPolicy chặn
NXDOMAIN cho service cùng namespaceNamespace sai, hoặc tên service viết sai

dnsPolicy

spec:
  dnsPolicy: ClusterFirst # Mặc định: dùng CoreDNS cluster
  # Các option khác:
  # Default: dùng DNS của node
  # ClusterFirstWithHostNet: ClusterFirst khi hostNetwork=true
  # None: tự configure hoàn toàn qua dnsConfig

Debug transcript: service resolve được nhưng không connect

DNS đúng không có nghĩa traffic đi được. Mình thường tách DNS và TCP như sau:

kubectl -n app run dns-debug --rm -it --image=busybox:1.36 -- sh
nslookup api.app.svc.cluster.local
nc -vz api.app.svc.cluster.local 8080
wget -S -O- http://api.app.svc.cluster.local:8080/health

Nếu nslookup OK nhưng nc fail, kiểm tra Service và EndpointSlice:

kubectl -n app get svc api -o wide
kubectl -n app get endpointslice -l kubernetes.io/service-name=api
kubectl -n app describe networkpolicy

DNS chỉ trả lời “tên này là ai”. Nó không đảm bảo port đúng, pod ready, hay NetworkPolicy cho phép kết nối.


Điều cần giữ khi vận hành Kubernetes

  • Kubernetes DNS: <svc>.<ns>.svc.cluster.local. Cùng namespace → tên ngắn.
  • CoreDNS chạy trong cluster, forward external domain ra upstream.
  • ndots:5 gây nhiều query cho external domain → giảm ndots hoặc dùng FQDN trailing dot.
  • Debug: nslookup/dig trong pod → check CoreDNS pod → check Service/Endpoints.
  • Headless Service → DNS trả pod IP trực tiếp. StatefulSet → mỗi pod có DNS name riêng.

Câu hỏi hay gặp

Tại sao dùng tên ngắn my-api mà resolve được?

Trả lời: /etc/resolv.conf trong pod có search default.svc.cluster.local svc.cluster.local cluster.local. Resolver tự append search domain vào tên ngắn. my-apimy-api.default.svc.cluster.local → resolve.

Pod ở namespace A gọi Service ở namespace B bằng cách nào?

Trả lời: Dùng <service-name>.<namespace>: my-api.production. DNS resolve qua search domain thành my-api.production.svc.cluster.local. Hoặc dùng FQDN đầy đủ.

DNS cache ảnh hưởng khi Service endpoint thay đổi?

Trả lời: CoreDNS cache mặc định 30s. Service thay đổi endpoint (pod mới) → client có thể giữ IP cũ tối đa 30s. Với headless Service, app nên re-resolve DNS thường xuyên (connection pool TTL < 30s). Xem thêm Mạng bài 04, DNS thực dụng.


Bài tiếp theo (Giai đoạn III): Ingress, Gateway API và TLS, route HTTP traffic từ ngoài vào cluster.