Sau bài này bạn làm được: hiểu DNS naming convention trong K8s; debug “service không resolve” đúng chỗ; biết ndots ảnh hưởng performance thế nào.


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

Tóm tắt

  • 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.