Skip to content

Private DNS Zones: Liên kết VPC và Khám phá Zone

Tại sao điều này quan trọng

Private DNS zones là nền tảng cho cơ chế phát hiện dịch vụ (service discovery) trong GCP. Việc hiểu rõ cơ chế liên kết (binding) là vô cùng quan trọng (critical) để tránh:

  • Dịch vụ (Services) không thể phân giải (resolve) từ các VPC khác
  • Vi phạm bảo mật (các VPC không được phép vẫn có thể truy cập bản ghi)
  • Nhầm lẫn trong vận hành (không rõ zone nào liên kết với VPC nào)

Cơ chế hoạt động của Private Zone

Mô hình liên kết VPC (VPC Binding Model)

Các Private zone chỉ thực hiện phân giải trong các VPC đã được cấp quyền (authorized VPCs):

Zone "db.internal.example.com"
  Bound to: VPC A, VPC B
  
Tài nguyên VPC A: ✓ Có thể phân giải db.internal.example.com
Tài nguyên VPC B: ✓ Có thể phân giải db.internal.example.com
Tài nguyên VPC C: ✗ Không thể phân giải (do chưa liên kết)

Cơ chế của trình phân giải (Resolver Behavior)

VM thuộc VPC A (10.0.1.5) gửi truy vấn: service.db.internal.example.com

Bước 1: Trình phân giải VPC (169.254.169.254) tiếp nhận truy vấn
Bước 2: Kiểm tra tất cả các private zone được liên kết với VPC A
Bước 3: Phát hiện kết quả khớp: zone db.internal.example.com
Bước 4: Trả về các bản ghi từ zone (10.0.3.50 cho service)
Bước 5: Kết quả nhận được: 10.0.3.50

VM thuộc VPC C (172.16.1.5) gửi truy vấn: service.db.internal.example.com

Bước 1: Trình phân giải VPC tiếp nhận truy vấn
Bước 2: Kiểm tra tất cả các private zone được liên kết với VPC C
Bước 3: Không tìm thấy kết quả khớp (zone chưa được liên kết với VPC C)
Bước 4: Chuyển tiếp tới public DNS (ví dụ 8.8.8.8)
Bước 5: Kết quả nhận được: NXDOMAIN

Triển khai

Thiết lập với một VPC duy nhất (Single VPC Setup)

bash
# Tạo private zone liên kết với VPC
gcloud dns managed-zones create db-internal \
  --dns-name=db.internal.example.com \
  --visibility=private \
  --networks=projects/PROJECT/global/networks/default

# Thêm các bản ghi (records)
gcloud dns record-sets transaction start --zone=db-internal
gcloud dns record-sets transaction add 10.0.3.50 \
  --name=primary.db.internal.example.com \
  --type=A \
  --ttl=300 \
  --zone=db-internal
gcloud dns record-sets transaction add 10.0.3.51 \
  --name=secondary.db.internal.example.com \
  --type=A \
  --ttl=300 \
  --zone=db-internal
gcloud dns record-sets transaction execute --zone=db-internal

Thiết lập với nhiều VPC (Multi-VPC Setup)

bash
# Tạo zone liên kết với nhiều VPC cùng lúc
gcloud dns managed-zones create shared-internal \
  --dns-name=shared.internal.example.com \
  --visibility=private \
  --networks=projects/PROJECT/global/networks/vpc-a,projects/PROJECT/global/networks/vpc-b,projects/PROJECT/global/networks/vpc-c

# Cập nhật để bổ sung thêm các VPC sau đó
gcloud dns managed-zones update shared-internal \
  --networks=projects/PROJECT/global/networks/vpc-a,projects/PROJECT/global/networks/vpc-b,projects/PROJECT/global/networks/vpc-c,projects/PROJECT/global/networks/vpc-d

Triển khai bằng Terraform (Terraform)

hcl
resource "google_compute_network" "vpc_a" {
  name = "vpc-a"
  auto_create_subnetworks = false
}

resource "google_compute_network" "vpc_b" {
  name = "vpc-b"
  auto_create_subnetworks = false
}

resource "google_dns_managed_zone" "shared" {
  name        = "shared-zone"
  dns_name    = "shared.internal.example.com."
  visibility  = "private"
  
  private_visibility_config {
    networks_list {
      network_url = google_compute_network.vpc_a.id
    }
    networks_list {
      network_url = google_compute_network.vpc_b.id
    }
  }
}

resource "google_dns_record_set" "service" {
  name            = "api.shared.internal.example.com."
  type            = "A"
  ttl             = 300
  managed_zone    = google_dns_managed_zone.shared.name
  rrdatas         = ["10.0.1.100", "10.0.2.100"]  # Dual-region
}

Khám phá Zone (Zone Discovery)

Cơ chế hoạt động của Zone Discovery

Khi VM trong VPC thực hiện truy vấn tên miền, trình phân giải sẽ kiểm tra tất cả các zone được liên kết theo thứ tự:

VM trong VPC A truy vấn: api.example.com

Trình phân giải kiểm tra các zone được liên kết:
  1. Zone api.example.com? → Chưa liên kết với VPC A
  2. Zone example.com? → Đã liên kết với VPC A, nhưng không chứa bản ghi api
  3. Zone com? → Không có sẵn trên Cloud DNS
  → Mặc định chuyển hướng sang public DNS
  → Kết quả: Chuyển tiếp tới trình phân giải internet

Hệ thống phân cấp đặt tên Zone (Zone Naming Hierarchy)

Đặt tên chính xác giúp quá trình khám phá zone diễn ra hiệu quả:

Zone gốc (Root zone): example.com
  └── Liên kết với VPC A
      Records: example.com A 10.0.1.5

Zone con (Sub-zone): api.example.com
  └── Liên kết với VPC A
      Records: api.example.com A 10.0.2.5

Truy vấn: api.example.com
  Trình phân giải sẽ kiểm tra zone api.example.com trước tiên
  → Tìm thấy bản ghi, trả về địa chỉ 10.0.2.5
  
Truy vấn: service.api.example.com
  Trình phân giải kiểm tra các zone theo thứ tự phân cấp
  → Không có zone nào khớp cho service.api.example.com
  → Kiểm tra tiếp zone api.example.com
  → Tìm thấy? Trả về các bản ghi tương ứng
  → Không tìm thấy? Kiểm tra tiếp zone example.com

Hệ quả (Implication): Tên của các zone nên được thiết kế theo cấu trúc cây ủy quyền (delegation tree):

example.com (root)
├── api.example.com (các dịch vụ API)
├── db.example.com (các dịch vụ cơ sở dữ liệu)
└── internal.example.com (các công cụ nội bộ)

Khi có truy vấn gửi đến, trình phân giải sẽ duyệt qua cấu trúc cây một cách hiệu quả.

Các mô hình áp dụng trong Production (Production Patterns)

Mô hình 1: Phân tách zone theo môi trường (Pattern 1)

prod.internal.example.com (liên kết với prod-vpc)
  └── các dịch vụ trong prod-vpc sẽ phân giải tại đây

staging.internal.example.com (liên kết với staging-vpc)
  └── các dịch vụ trong staging-vpc sẽ phân giải tại đây

dev.internal.example.com (liên kết với dev-vpc)
  └── các dịch vụ trong dev-vpc sẽ phân giải tại đây

Lợi ích: Cách ly hoàn toàn, tránh việc nhầm lẫn phân giải chéo giữa các môi trường.

Mô hình 2: Sử dụng Shared VPC kết hợp Zone tập trung (Pattern 2)

Dự án Host (quản lý DNS tập trung - Central Host Project):
  └── Shared VPC
      └── Tạo Private Zone "internal.example.com"
          Liên kết trực tiếp với Shared VPC

Các dự án dịch vụ (sử dụng Shared VPC):
  └── Các tài nguyên nằm trong Shared VPC
      └── Có thể tự do phân giải domain internal.example.com

Lợi ích: Chỉ cần một zone duy nhất, quản lý tập trung và cho phép tất cả các team truy cập.

Mô hình 3: Phân tách zone theo dịch vụ cụ thể (Pattern 3)

auth.internal.example.com (zone của đội phụ trách xác thực)
  └── Liên kết với auth-vpc

backend.internal.example.com (zone của đội phụ trách backend)
  └── Liên kết với backend-vpc

data.internal.example.com (zone của đội phụ trách dữ liệu)
  └── Liên kết với data-vpc

Lợi ích: Giúp phân định quyền sở hữu rõ ràng cho từng team, hoạt động trên các zone độc lập.

Những thách thức khi làm việc với Multi-VPC

Thách thức 1: Độ trễ khi liên kết Zone (Zone Binding Delays)

Khi thực hiện liên kết một zone tới một VPC mới, quá trình đồng bộ sẽ mất khoảng 60 giây:

Thời điểm T+0: Cập nhật zone, thêm liên kết VPC
Khoảng T+0 tới 60s: Tài nguyên trong VPC mới vẫn chưa thể phân giải (do độ trễ cache/propagation)
Thời điểm T+60s: Liên kết zone chính thức hoạt động

Hệ quả (Implication): Đừng kỳ vọng hệ thống có thể phân giải được ngay lập tức sau khi cập nhật liên kết.

Thách thức 2: Liên kết VPC xuyên dự án (Cross-Project VPC)

Các Private zone thông thường chỉ có thể liên kết với các VPC trong cùng một dự án:

Project A: VPC A
  └── Private Zone "a.internal" (liên kết với VPC A)

Project B: VPC B
  └── Không thể liên kết trực tiếp với zone của Dự án A (do khác dự án)
      Solution: Sử dụng cơ chế DNS Peering

Khi cần phân giải xuyên dự án: Hãy sử dụng cơ chế DNS Peering (một mô hình riêng biệt).

Thách thức 3: Hạn ngạch VPC (VPC Quota)

Một Private zone chỉ có thể liên kết tối đa khoảng 100 VPC
(Tùy thuộc vào hạn ngạch cụ thể)

Nếu số lượng vượt quá 100 VPC:
  → Không thể sử dụng một zone duy nhất
  → Giải pháp: Thực hiện sao chép zone hoặc cấu hình peering

Tích hợp GKE

Tự động tạo DNS cho GKE Service

GKE sẽ tự động tạo ra các bản ghi DNS tương ứng cho dịch vụ (service DNS entries):

Dịch vụ "api" nằm trong namespace "default":
  Tên miền DNS của Kubernetes: api.default.svc.cluster.local
  
GKE sẽ tự động cấu hình private zone tương ứng:
  Zone cluster.local (private, được liên kết với VPC của GKE)
  Records:
    - api.default.svc.cluster.local A 10.4.0.50 (IP của service)

Kết quả: Các Pod có thể tự động phân giải tên dịch vụ mà không cần cấu hình gì thêm.

Công khai GKE Services ra ngoài (Exposing GKE Services)

Để công khai dịch vụ GKE ra bên ngoài phạm vi cluster:

bash
# Tạo private zone cho việc truy cập từ bên ngoài
gcloud dns managed-zones create gke-services \
  --dns-name=k8s.internal.example.com \
  --visibility=private \
  --networks=projects/PROJECT/global/networks/default

# Thêm bản ghi dịch vụ (service record)
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 execute --zone=gke-services

# Hiện tại các dịch vụ bên ngoài (cùng VPC) đã có thể phân giải
# api.k8s.internal.example.com → 10.4.0.50

Khắc phục sự cố (Troubleshooting)

Sự cố 1: Không thể phân giải bản ghi trong Private Zone

bash
# From VM in VPC:
nslookup api.internal.example.com
# Result: NXDOMAIN

Các bước gỡ lỗi (Debug):
1. Kiểm tra xem zone đã tồn tại được cấu hình private chưa
   gcloud dns managed-zones describe api-zone

2. Kiểm tra xem VPC đã được liên kết hay chưa
   gcloud dns managed-zones describe api-zone \
     --format="value(privateVisibilityConfig.networks[].networkUrl)"
   Kết quả phải hiển thị VPC của bạn

3. Kiểm tra xem bản ghi DNS tồn tại hay không
   gcloud dns record-sets list --zone=api-zone \
     --filter="name:api.internal.example.com"

4. Kiểm tra cấu hình VPC của VM
   gcloud compute instances describe VM_NAME --zone=ZONE \
     --format="value(networkInterfaces[0].network)"
   Kết quả phải trùng khớp với VPC đã liên kết

5. Kiểm tra trực tiếp từ máy chủ VM
   Nếu sử dụng cấu hình tùy chỉnh /etc/resolv.conf, thể VM không gọi tới VPC resolver
   cat /etc/resolv.conf | grep nameserver
   Cấu hình phải bao gồm 169.254.169.254 hoặc để trống (dùng mặc định)

Sự cố 2: Zone tồn tại nhưng không thể phân giải từ một số VPC

Zone đang liên kết với: VPC A, VPC B
VM nằm trong VPC C không thể thực hiện phân giải

Các bước gỡ lỗi (Debug):
  Xác nhận xem VM có chính xác nằm trong VPC C hay không
  Nếu đúng là VPC C: Zone bắt buộc phải được liên kết lại để bao gồm cả VPC C
  
Giải pháp:
  gcloud dns managed-zones update zone-name \
    --networks=VPC_A,VPC_B,VPC_C

Sự cố 3: Negative Caching (Bản ghi đã xóa nhưng vẫn phân giải được)

Zone record: api.internal.example.com A 10.0.1.5
TTL: 300

Thực hiện xóa bản ghi tại thời điểm T+0

Truy vấn tại thời điểm T+100 (vẫn trong khoảng thời gian TTL):
  Bộ nhớ đệm của VM vẫn lưu bản ghi cũ
  → Kết quả trả về địa chỉ 10.0.1.5 (dữ liệu đã cũ)

Truy vấn tại thời điểm T+300+1 (sau khi hết TTL):
  Bộ nhớ đệm hết hạn
  → Gửi truy vấn mới tới Cloud DNS
  → Nhận về bản ghi đã được cập nhật

Biện pháp giảm thiểu: Hãy chủ động giảm thời gian sống TTL xuống trước khi thực hiện các thay đổi bản ghi.

Giám sát (Monitoring)

bash
# Giám sát các liên kết zone (zone bindings)
for zone in $(gcloud dns managed-zones list --filter="visibility:PRIVATE" --format="value(name)"); do
  echo "Zone: $zone"
  gcloud dns managed-zones describe $zone --format="value(privateVisibilityConfig.networks[].networkUrl)" | wc -l
done

# Giám sát lỗi phân giải (resolution errors)
gcloud logging read "resource.type=dns_query AND severity=ERROR" --limit=50

# Thiết lập cảnh báo nếu số lượng liên kết zone bị giảm (dấu hiệu của lỗi)

Các thực hành tốt nhất (Best Practices)

  1. Sử dụng hệ thống phân cấp zone (ví dụ: từ example.com → api.example.com)
  2. Đặt quy tắc đặt tên rõ ràng (ví dụ: prod.internal.example.com)
  3. Viết tài liệu lưu vết các VPC nào đang liên kết với mỗi zone
  4. Kiểm thử khả năng phân giải chéo VPC trước khi đưa vào vận hành
  5. Lên kế hoạch phát triển (phương án là gì nếu thêm 50 VPC nữa?)
  6. Giám sát sức khỏe của zone (có truy vấn nào đang bị lỗi hay không?)
  7. Sao lưu cấu hình các zone (sử dụng Terraform IaC)
  8. Điều chỉnh TTL phù hợp dựa trên tần suất thay đổi bản ghi

Tài liệu tham khảo (References)