Cloud DNS cho GKE: Các giải pháp thay thế và Hiệu năng quy mô lớn
Tại sao điều này quan trọng
Đối với GKE Autopilot, Cloud DNS không phải là tùy chọn—đây là thành phần bắt buộc (mandatory) cho toàn bộ việc phát hiện dịch vụ bên ngoài (external service discovery). Việc hiểu cơ chế tích hợp (integration) là vô cùng quan trọng cho độ tin cậy trong môi trường production.
Các kịch bản thực tế (Real scenarios):
Kịch bản 1: Kết nối Microservices (Scenario 1)
Frontend pod gửi truy vấn DNS: "api-service.default.svc.cluster.local"
→ Được phân giải nội bộ trong cluster (bởi kube-dns)
Frontend pod gửi truy vấn DNS: "database.prod.internal"
→ Được phân giải bởi Cloud DNS (ở ngoài phạm vi cluster)
Kịch bản 2: Sử dụng GKE Autopilot (Scenario 2)
Không thể sử dụng cấu hình tùy chỉnh kube-dns
→ Bắt buộc phải sử dụng Google-managed DNS
→ Tự động tích hợp hoàn toàn với Cloud DNS
Kịch bản 3: Mô hình đa Cluster (Scenario 3: Multi-Cluster)
Frontend cluster: Thực hiện phân giải api.example.com
→ Định tuyến lưu lượng tới IP của backend cluster
→ Đòi hỏi sự phối hợp điều phối của Cloud DNS
Kịch bản 4: Tải lượng truy vấn cực lớn (Scenario 4: High Query Volume)
10,000 pod × 1000 truy vấn/pod = hàng triệu truy vấn DNS mỗi giây
→ Một dịch vụ kube-dns duy nhất sẽ trở thành điểm nghẽn cổ chai (bottleneck)
→ Giải pháp: Kết hợp NodeLocal DNSCache và Cloud DNSKiến trúc GKE DNS trước thời đại Autopilot (Pre-Autopilot)
Kube-DNS (Giải pháp cũ, Đã lỗi thời)
Quy trình phân giải của Pod (Pod Resolution Flow):
Pod (10.4.1.5)
↓
/etc/resolv.conf (ndots=5)
↓
Trình phân giải Kubelet (127.0.0.1:53 qua kube-dns)
↓
Kube-DNS Pod (nằm trong kube-system namespace tại 10.4.0.10)
↓
Phản hồi kết quả:
- Nội bộ (Internal): api.default.svc.cluster.local → 10.4.0.50
- Bên ngoài (External): example.com → Cloud DNS → 35.201.100.50Đặc điểm của Kube-DNS:
- Dễ bị lỗi tại một điểm duy nhất (do dùng Central DNS pod)
- Chạy trong namespace kube-system (hiển thị đối với mọi pod)
- Mặc định cấu hình dnsPolicy=ClusterFirst (ưu tiên phân giải nội bộ trước, sau đó mới tới upstream)
Lý do bị loại bỏ: Gặp vấn đề về hiệu năng ở quy mô lớn, hiện được thay thế bởi CoreDNS.
CoreDNS (Mặc định hiện tại)
Quy trình phân giải của Pod (Pod Resolution Flow):
Pod (10.4.2.5)
↓
/etc/resolv.conf (ndots=5)
↓
Trình phân giải Kubelet (127.0.0.1:53 qua CoreDNS)
↓
CoreDNS Pod (nằm trong kube-system namespace tại 10.4.0.11)
↓
Cấu hình Corefile (dựa trên các plugin):
├── kubernetes plugin (phục vụ phân giải nội bộ)
├── forward plugin (chuyển tiếp tới upstream Cloud DNS)
└── cache plugin (lớp lưu bộ đệm caching)
↓
Phản hồi kết quả:
- Nội bộ (Internal): api.default.svc.cluster.local → 10.4.0.50
- Bên ngoài (External): example.com → Cloud DNS → 35.201.100.50Ưu điểm của CoreDNS:
- Thiết kế dạng mô-đun (cấu trúc plugin)
- Hiệu năng tốt hơn (hỗ trợ xử lý đa luồng)
- Cho phép dễ dàng cấu hình Corefile
- Quá trình tìm kiếm cache nhanh hơn
DNS trong GKE Autopilot
GKE Autopilot sử dụng cơ chế tích hợp Cloud DNS được quản lý (managed Cloud DNS integration):
Phân giải của Pod trong GKE Autopilot:
Pod (10.4.3.5)
↓
/etc/resolv.conf
↓
GKE-managed CoreDNS (được Google quản lý, không hiển thị pod cụ thể)
↓
Cloud DNS (phân giải cả nội bộ và bên ngoài)
↓
Đối với nội bộ: Trả về địa chỉ IP của Pod
Đối với bên ngoài: Gửi truy vấn tới Cloud DNSĐặc tính của Autopilot:
- Không thể tùy chỉnh Corefile của CoreDNS (do Google quản lý)
- Không thể tắt tính năng tích hợp Cloud DNS
- Quá trình định tuyến truy vấn được tự động hóa hoàn toàn
- Khả năng giám sát được thực hiện qua Cloud Monitoring
Các phương thức tích hợp Cloud DNS
Phương thức 1: Sử dụng Private Zones cho các dịch vụ GKE
# Tạo private zone cho các dịch vụ GKE
gcloud dns managed-zones create gke-services \
--dns-name=k8s.internal.example.com \
--visibility=private \
--networks=projects/PROJECT/global/networks/gke-vpc
# Thêm các bản ghi dịch vụ (thông thường được tự động hóa qua operator)
gcloud dns record-sets transaction start --zone=gke-services
gcloud dns record-sets transaction add 10.4.0.50 \
--name=api.k8s.internal.example.com \
--type=A \
--ttl=60 \
--zone=gke-services
gcloud dns record-sets transaction add 10.4.0.51 \
--name=database.k8s.internal.example.com \
--type=A \
--ttl=60 \
--zone=gke-services
gcloud dns record-sets transaction execute --zone=gke-services
# Chạy thử từ GKE pod:
# nslookup api.k8s.internal.example.com
# → Phân giải ra địa chỉ 10.4.0.50 thông qua Cloud DNSPhương thức 2: Sử dụng Cloud Service Directory cho mô hình đa Cluster
# Kích hoạt Service Directory trong dự án
gcloud services enable servicedirectory.googleapis.com
# Tạo namespace
gcloud service-directory namespaces create my-services \
--location=us-central1
# Tạo dịch vụ (service)
gcloud service-directory services create my-api \
--namespace=my-services \
--location=us-central1
# Thêm điểm cuối (endpoint)
gcloud service-directory endpoints create ep1 \
--service=my-api \
--namespace=my-services \
--location=us-central1 \
--address=10.4.0.50 \
--port=8080
# Tự động đăng ký DNS: my-api.my-services.servicedirectory.cloud.googChi tiết về Mạng (Networking Details)
Đường truyền truy vấn DNS trong GKE
Truy vấn của Pod: curl api.default.svc.cluster.local
Bước 1: Phân tích file cấu hình /etc/resolv.conf
nameserver 127.0.0.1
search api.default.svc.cluster.local svc.cluster.local cluster.local
Bước 2: Sử dụng thông số ndots=5 (mặc định)
Thực hiện truy vấn trực tiếp (FQDN): api.default.svc.cluster.local
→ Chứa 4 dấu chấm → Thử truy vấn trực tiếp trước
Bước 3: CoreDNS tiếp nhận và xử lý truy vấn
Các quy tắc trong Corefile:
├── .:53 (default zone)
│ ├── kubernetes cluster.local (nội bộ)
│ ├── cache 30 (lưu cache)
│ └── forward . /etc/resolv.conf (chuyển tiếp upstream)
Bước 4: kubernetes plugin xử lý truy vấn
Query: api.default.svc.cluster.local
→ Kiểm tra với Kubernetes API
→ Dịch vụ "api" trong namespace "default" có tồn tại
→ Trả về ClusterIP tương ứng: 10.4.0.50
Kết quả: Pod nhận về địa chỉ 10.4.0.50 và kết nối trực tiếpPhân giải bên ngoài (External Resolution)
Truy vấn của Pod: curl example.com
Bước 1: Phân tích file cấu hình /etc/resolv.conf
search api.default.svc.cluster.local ...
Bước 2: Gửi thử kèm theo các search domains trước
api.default.svc.cluster.local.example.com → NXDOMAIN
api.default.svc.cluster.local → NXDOMAIN
example.com (không có hậu tố search) → Thử truy vấn trực tiếp
Bước 3: CoreDNS tiếp nhận và xử lý
Query: example.com
→ kubernetes plugin: Không phải địa chỉ nội bộ
→ forward plugin: Chuyển tiếp tới upstream
→ Upstream: Trỏ tới Cloud DNS (được khai báo trong corefile)
Bước 4: Cloud DNS thực hiện phân giải
example.com → 35.201.100.50
Kết quả: Pod nhận về địa chỉ 35.201.100.50Cấu hình Corefile
Cấu hình Corefile mặc định trong GKE (Default Corefile)
.:53 {
cache 30
errors
health
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
}
loop
reload
loadbalance
}Ý nghĩa của các Plugin (Plugins explained):
cache 30: Lưu trữ cache phản hồi DNS trong vòng 30 giâykubernetes: Cơ chế phát hiện dịch vụ nội bộ (Internal service discovery)forward .: Trình phân giải upstream (mặc định là Cloud DNS)max_concurrent 1000: Hạn chế tần suất truy vấn (Rate limiting)
Tùy chỉnh Corefile (Dành cho Standard GKE, không áp dụng cho Autopilot)
# Tạo ConfigMap chứa cấu hình Corefile tùy chỉnh
cat <<EOF > corefile.txt
.:53 {
cache 30
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
# Thêm cấu hình chuyển tiếp tùy chỉnh
rewrite name regex (.*)\.internal\.company\.com {1}.internal.gcp.company.com
# Bổ sung lưu cache cho internal domain
cache 60 internal.company.com
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
loop
reload
loadbalance
}
EOF
# Áp dụng cấu hình ConfigMap
kubectl create configmap coredns-custom \
--from-file=internal.override=corefile.txt \
-n kube-systemCác chính sách GKE DNS Policies
Các loại chính sách DNS (DNS Policy Types)
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
dnsPolicy: ClusterFirst # Default (cluster DNS first, then upstream)
---
dnsPolicy: ClusterFirstWithHostNet # Use cluster DNS with hostNetwork
hostNetwork: true
---
dnsPolicy: Default # Node's DNS resolver (no cluster DNS)
---
dnsPolicy: None # Use custom dnsConfig below
dnsConfig:
nameservers:
- 8.8.8.8
- 1.1.1.1
searches:
- my-domain.comKhi nào nên sử dụng loại nào
| Chính sách (Policy) | Trường hợp sử dụng (Use Case) |
|---|---|
| ClusterFirst (Mặc định) | Truyền thông giữa các Pod, truy cập services |
| ClusterFirstWithHostNet | Dành cho các DaemonSets cần dùng DNS của cluster |
| Default | Bỏ qua DNS của cluster (hiếm gặp, trường hợp đặc biệt) |
| None | Kiểm soát hoàn toàn, tự cấu hình DNS (các trường hợp đặc biệt) |
Hiệu năng ở quy mô lớn (Performance at Scale)
Thách thức: Điểm nghẽn cổ chai DNS
Hệ thống GKE Cluster:
- 10,000 pod
- Mỗi pod trung bình gửi khoảng 100 truy vấn DNS/phút
- Tổng cộng: Đạt mức 1,666 truy vấn/giây
Một CoreDNS pod duy nhất:
- Có thể xử lý khoảng ~5,000-10,000 QPS (tùy thuộc vào phần cứng)
- Sẽ trở thành điểm nghẽn cổ chai (bottleneck)
Các triệu chứng xảy ra (Symptoms):
- Bị hết thời gian chờ DNS (DNS timeouts)
- Kết nối bị từ chối (không thể phân giải tên dịch vụ)
- Tăng tỷ lệ khởi động lại của pod (do liveness probes bị timeout)Giải pháp 1: Tăng số lượng CoreDNS Replicas
# Nhân bản CoreDNS lên 3 bản sao để đảm bảo tính sẵn sàng cao (HA)
kubectl scale deployment -n kube-system coredns --replicas=3
# Hoặc thực hiện cấu hình nhanh qua lệnh patch của kubectl
kubectl patch deployment coredns -n kube-system -p '{"spec":{"replicas":3}}'
# Xác minh lại cấu hình
kubectl get pods -n kube-system -l k8s-app=kube-dnsGiải pháp 2: Sử dụng NodeLocal DNSCache (Khuyến nghị)
Triển khai trình phân giải cache cục bộ trên mỗi node (đây là một chủ đề riêng biệt, được trình bày chi tiết trong file 08.nodelocal-dnscache.md).
# Kích hoạt tính năng NodeLocal DNSCache
gcloud container clusters create my-cluster \
--enable-ip-alias \
--addons=HttpLoadBalancing,HorizontalPodAutoscaling,NodeLocalDNS
# Hoặc tiến hành cập nhật cluster hiện có
gcloud container clusters update my-cluster \
--enable-ip-alias \
--addons=NodeLocalDNS \
--zone=us-central1-aHiệu quả mang lại (Effect):
Trước đây (Before): 10,000 pod × 100 truy vấn/phút = 1,666 QPS gửi tới CoreDNS
Sau khi áp dụng (After): Tỷ lệ cache hit cục bộ đạt ~95% → Chỉ còn khoảng ~83 QPS gửi tới CoreDNS (giảm tải 95 lần)Phát hiện dịch vụ bên ngoài (External Service Discovery)
Mô hình 1: Kết hợp Kubernetes Ingress và Cloud DNS (Pattern 1)
# Dịch vụ được công khai ra ngoài qua Google Cloud LB
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: backend-config
spec:
sessionAffinity:
affinityType: "CLIENT_IP"
---
# Cập nhật địa chỉ IP của service vào Cloud DNS
apiVersion: v1
kind: Service
metadata:
name: api-service
annotations:
cloud.google.com/backend-config: '{"external": "backend-config"}'
spec:
type: LoadBalancer
selector:
app: api
ports:
- port: 80
targetPort: 8080Sau khi tạo thành công, tiến hành cập nhật địa chỉ IP của Load Balancer vào Cloud DNS.
Mô hình 2: Sử dụng ExternalDNS Operator (Pattern 2)
Tự động đồng bộ các tài nguyên Kubernetes Ingress/Service trực tiếp với Cloud DNS:
# Install ExternalDNS
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm install external-dns external-dns/external-dns \
--set google.project=PROJECT_ID \
--set policy=sync \
--set registry=txt \
--set txtOwnerId=my-cluster
# Hiện tại mọi Ingress được tạo sẽ tự động cập nhật bản ghi lên Cloud DNS
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
external-dns.alpha.kubernetes.io/hostname: api.example.com
spec:
ingressClassName: gce
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
EOF
# ExternalDNS tự động khởi tạo bản ghi trên Cloud DNS
# api.example.com → Load Balancer IPKhắc phục sự cố (Troubleshooting)
Sự cố 1: Bị hết thời gian chờ DNS (DNS Timeouts) bên trong các Pod
# Thực hiện kiểm tra từ bên trong pod
nslookup kubernetes.default
# Nếu quá trình bị treo hoặc hết thời gian chờ
Các bước gỡ lỗi (Debug):
1. Kiểm tra xem các pod CoreDNS có đang hoạt động hay không
kubectl get pods -n kube-system -l k8s-app=kube-dns
2. Kiểm tra nhật ký hoạt động (logs) của CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100
3. Kiểm tra cấu hình Corefile hiện tại
kubectl get cm -n kube-system coredns -o yaml
4. Thực hiện kiểm tra trực tiếp CoreDNS
kubectl exec -it -n kube-system POD_NAME -- nslookup kubernetes.default
5. Kiểm tra giới hạn tài nguyên (resource limits) đã cấp
kubectl top pods -n kube-system -l k8s-app=kube-dnsSự cố 2: Pod không thể phân giải các dịch vụ bên ngoài
# Kiểm tra từ bên trong pod
nslookup example.com
# Nếu nhận về mã lỗi NXDOMAIN
Các bước gỡ lỗi (Debug):
1. Kiểm tra file cấu hình /etc/resolv.conf của node
kubectl debug node/NODE_NAME -it --image=ubuntu
cat /etc/resolv.conf
2. Kiểm tra cấu hình của forward plugin
kubectl get cm -n kube-system coredns -o yaml | grep forward
3. Thực hiện kiểm tra trực tiếp từ pod CoreDNS
kubectl exec -it -n kube-system POD_NAME -- \
nslookup example.com 8.8.8.8
4. Kiểm tra tường lửa có cho phép gửi lưu lượng ra ngoài (egress) qua cổng 53
gcloud compute firewall-rules list --filter="direction:EGRESS"Sự cố 3: Độ trễ truy vấn DNS tăng cao (High DNS Query Latency)
# Giám sát độ trễ của hệ thống DNS
kubectl top pods -n kube-system -l k8s-app=kube-dns
# Trường hợp chỉ số CPU tăng cao:
1. Tăng quy mô CoreDNS: scale deployment coredns -n kube-system --replicas=5
2. Kích hoạt tính năng NodeLocal DNSCache
3. Điều chỉnh lại thông số TTL cho cache trong Corefile
# Trường hợp chỉ số bộ nhớ (memory) tăng cao:
1. Giảm dung lượng cache trong cấu hình Corefile
2. Kiểm tra các truy vấn DNS trỏ tới domain không tồn tại (các lỗi liên quan đến search domains)Các thực hành tốt nhất (Best Practices)
- Sử dụng NodeLocal DNSCache cho môi trường production (giúp tăng tốc hiệu năng vượt trội)
- Tăng quy mô CoreDNS lên ít nhất từ 2-3 replicas để đảm bảo tính sẵn sàng cao (HA)
- Giám sát liên tục độ trễ của hệ thống DNS
- Sử dụng các private zone cho việc phân giải dịch vụ nội bộ
- Viết tài liệu lưu vết các thay đổi trong Corefile (duy trì chú thích trong ConfigMap)
- Kiểm thử DNS kỹ lưỡng trước khi triển khai (sử dụng kịch bản test dành riêng cho pod)
- Thiết lập cảnh báo lỗi DNS (tích hợp trực tiếp với hệ thống giám sát)
- Định kỳ sao lưu dữ liệu ConfigMap của Corefile