Sau bài này bạn làm được: chạy rolling deploy Kubernetes không gây 502; biết khi nào cần hạ TTL trước khi đổi DNS; điều hành incident call với checklist; viết post-mortem tập trung vào nguyên nhân mạng.
Rolling deploy — không downtime nhưng có rủi ro
Kubernetes rolling update thay Pod theo từng batch:
[v1: 3/3 running] ──deploy v2──▶
[v1: 2/3] [v2: 1/3] ← LB gửi traffic tới cả v1 và v2
[v1: 1/3] [v2: 2/3]
[v1: 0/3] [v2: 3/3] ← hoàn thành
Nguyên nhân 502 hay gặp khi rolling deploy:
Lỗi 1: readiness probe chưa sẵn sàng nhưng traffic đã tới
spec:
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10 # chờ 10s trước probe đầu tiên
periodSeconds: 5
failureThreshold: 3
Nếu initialDelaySeconds quá ngắn, LB gửi traffic vào Pod chưa sẵn sàng → 502.
Lỗi 2: Pod cũ bị terminate giữa chừng (thiếu graceful shutdown)
Xem lại bài 12: Pod phải handle SIGTERM và hoàn thành request đang xử lý trước khi exit.
spec:
terminationGracePeriodSeconds: 60 # cho Pod 60s để graceful shutdown
containers:
- lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"] # chờ LB cập nhật endpoints
preStop sleep nhỏ (5–10s) đảm bảo LB đã remove Pod khỏi backend trước khi Pod bắt đầu shutdown.
Canary và blue-green
Canary — tăng dần traffic cho phiên bản mới
# Hai Deployment: v1 (9 replica) và v2 (1 replica)
# Cùng label selector trên Service → 10% traffic tới v2
# Tăng dần replica v2, giảm v1
# Hoặc dùng Ingress weight (NGINX Ingress Controller)
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% traffic
Blue-Green — switch toàn bộ
[LB] ──▶ [Service: selector = app: blue] (100% traffic)
[Blue deployment: v1]
[Green deployment: v2] ← warm up song song
# Khi ready:
kubectl patch service my-app -p '{"spec":{"selector":{"app":"green"}}}'
# Switch ngay lập tức; rollback = switch lại về blue
DNS TTL strategy khi đổi endpoint
Tình huống: di chuyển service từ LB cũ sang LB mới, cần đổi DNS.
Sai (TTL cao):
api.example.com → LB cũ (TTL 3600s = 1h)
Đổi record → LB mới
→ 1h sau một số user mới dùng LB mới; user cũ còn LB cũ 1h nữa
→ Nếu LB cũ đã tắt → 502 cho user còn cache
Đúng (hạ TTL trước):
Trước 1 ngày: đặt TTL = 60s
Chờ 24h (TTL cũ expire hết)
Đổi record → LB mới
→ Sau tối đa 60s, mọi user đã dùng LB mới
Sau khi ổn: nâng TTL lại về 300–3600s
CDN và cache invalidation
Khi dùng CDN (Cloudflare, CloudFront, Fastly) trước origin:
User → CDN edge → origin (app)
cache-control: public, max-age=300
Khi deploy mới:
Origin trả nội dung mới
CDN edge vẫn cache nội dung cũ trong 300s
→ User vẫn thấy phiên bản cũ
Chiến lược:
- API dynamic:
Cache-Control: no-storehoặcprivate(không cache CDN). - Static asset: đổi URL theo version hash (
/app.v2.js), max-age dài. - Cần invalidate nhanh: dùng CDN purge API, hoặc tăng version path.
Checklist incident mạng
Khi nhận alert hoặc escalation “service không vào được”:
T+0: Xác nhận scope
□ Tất cả user hay một nhóm cụ thể?
□ Tất cả region hay một AZ?
□ Mọi endpoint hay một path cụ thể?
□ Bắt đầu từ khi nào? Có deploy gần đây không?
T+5: Kiểm tra nhanh (theo thứ tự tầng)
□ DNS: dig +short A api.example.com
□ TCP: nc -vz api.example.com 443
□ HTTP: curl -sv https://api.example.com/health
□ LB: kiểm tra healthy target count
T+10: Scope hẹp hơn
□ LB log: có pattern 5xx nào không?
□ App log: có exception cụ thể không?
□ Infra: CPU, memory, connection count bình thường không?
T+15: Quyết định
□ Rollback deploy? (nếu gần đây có deploy)
□ Scale up? (nếu traffic tăng đột biến)
□ Failover AZ? (nếu một AZ có vấn đề)
□ Escalate? (nếu không xác định được nguyên nhân)
Post-mortem: tập trung nguyên nhân gốc rễ
Sau incident, viết post-mortem có cấu trúc:
## Incident: 502 sau deploy v2.3.1 (14:30–15:45 UTC)
### Timeline
- 14:30: Deploy v2.3.1 bắt đầu
- 14:35: Alert rate(5xx) > 5% trigger
- 14:42: Xác nhận readiness probe sai path (/health vs /ready)
- 14:45: Rollback về v2.3.0
- 15:00: Metric về normal
- 15:45: Deploy lại v2.3.1 với probe đúng
### Nguyên nhân gốc rễ
readinessProbe path trong v2.3.1 đổi từ /health sang /ready
nhưng endpoint /ready chỉ được thêm ở v2.3.2 (chưa merge lúc deploy).
Pod báo Not Ready → LB loại nhưng không đủ nhanh → 502 trong ~5 phút.
### Hành động khắc phục
1. [DONE] Rollback về v2.3.0
2. [TODO] Thêm CI test kiểm tra readiness probe endpoint tồn tại trước deploy
3. [TODO] Tăng initialDelaySeconds để buffer tốt hơn
4. [TODO] Alert sớm hơn: readiness probe fail > 30s trong rolling deploy
Nguyên tắc post-mortem tốt: không blame người, tập trung vào hệ thống và quy trình.
Tóm tắt
- Graceful shutdown + readiness probe là bộ đôi bắt buộc để rolling deploy không 502.
- Hạ TTL trước 24–48h khi plan đổi DNS endpoint.
- CDN cache và DNS TTL là hai lý do user thấy phiên bản cũ dù deploy đã xong.
- Incident checklist: DNS → TCP → HTTP → LB → App — cùng thứ tự như debug bình thường.
Câu hỏi hay gặp
Grace 30s, request dài 20s — có cần preStop không?
Trả lời: Về lý thuyết đủ nếu app shutdown nhanh. preStop hữu ích khi cần chờ LB gỡ backend (sleep vài giây) hoặc drain trước SIGTERM — tránh race với kube-proxy.
Đổi DNS lúc 14:00, TTL 3600s, 15:00 vẫn user trỏ LB cũ — vì sao? LB cũ xóa thì sao?
Trả lời: Resolver/client vẫn cache tới 1h. LB cũ xóa → user đó lỗi/timeout cho đến khi cache hết. Giảm TTL trước migration.
Post-mortem: lỗi do quên cập nhật probe — “ai chịu trách nhiệm”?
Trả lời: Nguyên tắc blameless: tìm thiếu sót hệ thống (CI không validate probe, checklist deploy). Trách nhiệm cá nhân không để “kỷ luật” trong doc — mà để cải quy trình.
Bạn đã hoàn thành nhánh vận hành chính của loạt bài (Giai đoạn I → IV).
Ôn lại lộ trình:
- Giai đoạn I (01–04): Bản đồ giao thức — tầng, IP, TCP, DNS.
- Giai đoạn II (05–07): HTTP stack — HTTPS, TLS, debug checklist.
- Giai đoạn III (08–10): Nơi workload chạy — Linux, Docker, Kubernetes.
- Giai đoạn IV (11–16): Hạ tầng và vòng đời — cloud, LB, cert, observability, IaC, release.
Bài tuỳ chọn nâng cao: Service mesh và mTLS — nếu hệ thống đã đủ lớn để quan tâm east-west traffic, retry mesh-level và zero-trust giữa service.
Xem lại mục lục loạt bài hoặc tiếp tục với các bài spin-off: tcpdump thực chiến, eBPF observability, hoặc đa cloud VPC.