Skip to content
JCJohnny Chung
← All posts

Xây dựng hệ thống quan sát bền vững đối với các cuộc khủng hoảng chồng chéo trong môi trường K8s và Edge

Phân tích cách kết hợp Cloudflare, Kubernetes và các công cụ quan sát để duy trì ổn định khi hệ thống phải đối mặt với nhiều sự cố cùng lúc.

· 7 min read

Thật không thường gặp khi một đêm tôi đang ngủ, điện thoại bật lên với hàng chút cảnh báo từ Prometheus. CPU của một node trong cluster K8s spike lên 95%, đồng thời lượng request vào Cloudflare Workers tăng đột ngột gấp ba so với mức bình thường. Trong cùng lúc, một số pod trong namespace monitoring bắt đầu crash vì hết bộ nhớ. Tôi phải xử lý ba vấn đề khác nhau mà chúng lại liên kết chặt chẽ. Đây chính là tình huống “cuộc khủng hoảng chồng chéo” mà nhiều team DevOps gặp phải khi chạy ứng dụng trên edge và trong trung tâm dữ liệu.

Trong bài viết này tôi sẽ chia sẻ cách tôi và team mình đã thiết kế lại hệ thống quan sát để không chỉ phát hiện sớm mà còn tự động giảm thiểu tác động khi nhiều lỗi xuất hiện cùng lúc. Chúng ta sẽ xem xét vai trò của Cloudflare ở lớp edge, cách sử dụng K8s để cô lập lỗi và một số mẫu quan sát thực tế mà chúng tôi đã áp dụng.

Vai trò của Cloudflare trong chiến lược phòng ngừa

Cloudflare không chỉ là một CDN đơn giản. Khi chúng tôi chuyển lưu lượng truy cập qua Workers và Argo Tunnel, chúng ta có thể áp dụng chính sách rate limiting, bot management và WAF ngay tại edge trước khi lưu lượng ever tới origin. Điều này giúp giảm tải cho cluster K8s khi có cuộc tấn công DDoS hoặc lưu lượng bất thường từ các công cụ quét lỗ hổng.

Một điều chúng tôi học được là việc chỉ依赖 origin-side metrics là không đủ. Chúng tôi bắt đầu thu thập métriques từ Cloudflare Logshare và gửi chúng vào Loki qua một job Fluentbit chạy trên một VM riêng. Khi lượng request bị chặn bởi WAF vượt qua ngưỡng chúng tôi định trước, một alert được kích hoạt trong Alertmanager và đồng thời một rule trong Cloudflare Workers tự động tăng cường chế độ challenge cho các IP nghi ngờ.

Cô lập lỗi ở lớp K8s bằng namespace và pod disruption budget

Trong sự cố đêm đó, chúng tôi nhận thấy một số pod monitoring bị OOM kill vì chúng cùng sử dụng một node với các workload ứng dụng chính. Điều này làm mất khả năng quan sát đúng lúc khi chúng ta nhất cần nó. Giải pháp là chúng tôi tạo ra một namespace riêng cho tất cả các thành phần quan sát (Prometheus, Grafana, Loki, Alertmanager) và đặt PodDisruptionBudget với minAvailable: 1 cho mỗi StatefulSet. Ngoài ra, chúng tôi áp dụng node affinity để đặt các pod quan sát lên một node pool riêng có tài nguyên được bảo留.

Khi một node trong pool ứng dụng gặp vấn đề, scheduler sẽ không evict pod quan sát vì chúng không được phép chạy trên cùng node pool đó. Đồng thời, chúng tôi thiết lập resource limits và requests cho mỗi container dựa trên dữ liệu sử dụng thực tế từ các vòng lặp đo trước. Điều này ngăn chặn tình trạng một pod quan sát tiêu thụ quá nhiều bộ nhớ và gây ra OOM kill trên node chung.

Quan sát đa lớp: metrics, logs, traces và sự liên kết chúng

Chúng tôi không chỉ dựa vào metrics từ Prometheus. Trong môi trường edge, việc truy cậpLogs từ Cloudflare Workers và các hàm serverless là rất quan trọng vì chúng cung cấp bối cảnh về request ngay tại điểm vào. Loki được cấu hình để nhận logs từ Fluentd agents chạy trên mỗi node K8s và cũng từ Cloudflare qua một webhook push.

Đối với tracing, chúng tôi sử dụng Tempo với OpenTelemetry SDK được inject vào mọi service trong cluster và cũng vào Cloudflare Workers qua một wrapper nhỏ. Khi một request lỗi xảy ra, chúng ta có thể trace từ edge qua ingress controller, qua service mesh (Istio) và cuối cùng tới backend service. Điều này giúp chúng tôi nhanh chóng xác định xem lỗi xảy ra ở đâu: là ở edge do WAF chặn, là ở network do timeout, hay là ở do ứng dụng trả về lỗi 5xx.

Một điểm mấu chốt là chúng tôi thiết lập một rule trong Alertmanager mà không chỉ kích hoạt khi một metric vượt ngưỡng mà còn khi có sự tương quan giữa logs và traces. Ví dụ: nếu lượng request bị chặn bởi Cloudflare WAF tăng hơn 50% trong 5 phút đồng thời có sự gia tăng lỗi 502 từ ingress controller, Alertmanager sẽ gửi một thông báo严重程度 critical và đồng thời tự động kích hoạt một runbook trong Argo Workflows để scale thêm worker nodes và bật chế độ caching agresif ở Cloudflare.

Tự động hóa phản ứng qua GitOps và ChatOps

Sau khi có được dữ liệu quan sát đủ tốt, bước tiếp là tự động hóa phản ứng. Chúng tôi sử dụng Argo CD để quản lý mọi manifest K8s và Argo Rollouts để thực hiện các chiến lược canary và blue-green. Khi một alert về mức độ lỗi vượt ngưỡng được kích hoạt, một webhook từ Alertmanager gọi tới một repository chứa các Argo Workflows được định nghĩa sẵn. Workflow này thực hiện các bước: (1) tăng replica của deployment affected, (2) thay đổi cấu hình rate limit ở Cloudflare qua API, (3) bật chế độ logging debug cho các component liên quan, và (4) gửi tin nhắn vào channel #devops-incident trên Slack với summary và liên kết tới Grafana dashboard.

Trong thực tế, chúng tôi đã thấy thời gian MTTR (Mean Time To Recovery) giảm từ khoảng 45 phút xuống dưới 10 phút đối với các sự cố có liên quan đến edge và K8s đồng thời. Điều này không chỉ nhờ vào công cụ mà còn nhờ vào việc chúng tôi đã đặt ra một quy trình rõ ràng: detect → correlate → automate → notify.

Kinh nghiệm học được từ các sự cố gần đây

Một số bài học cụ thể từ những sự cố chúng tôi đã trải qua:

  • Đừng để các thành phần quan sát và ứng dụng chạy chung node pool. Tách biệt rõ ràng giúp tránh tình trạng “mất mắt” khi node gặp sự cố.
  • Luôn có một nguồn metrics từ lớp edge (Cloudflare, Fastly, hoặc bất kỳ provider nào bạn dùng). Điều này cho phép bạn phát hiện vấn đề trước khi nó tới origin.
  • Sử dụng PodDisruptionBudget và node affinity không chỉ để tránh việc pod bị xóa mà còn để bảo đảm rằng các thành phần quan sát luôn có đủ tài nguyên để hoạt động.
  • Khi thiết lập alert, hãy kết hợp ít nhất hai loại tín hiệu (metrics + logs hoặc metrics + traces) để giảm false positive.
  • Tự động hóa phản ứng không phải là chỉ scale pod. Hãy cân nhắc việc thay đổi cấu hình ở edge, bật tắt các tính năng bảo mật hoặc thay đổi routing policy.
  • Lưu trữ và truy vấn logs từ nhiều nguồn cần một schema thống一. Chúng tôi sử dụng một trường “source” trong Loki để unterscheiden logs từ K8s, Cloudflare và các hàm serverless.

Kết luận và bước tiếp theo

Xây dựng hệ thống quan sát bền vững trong môi trường K8s và edge không chỉ là việc chọn công cụ đúng mà còn là việc thiết kế kiến trúc sao cho mỗi lớp có thể hoạt động độc lập khi lớp khác gặp sự cố. Cloudflare cung cấp lớp bảo vệ đầu tiên, K8s cung cấp lớp compute và orchestration linh hoạt, trong khi các công cụ quan sát như Prometheus, Loki, Tempo và Alertmanager cung cấp lớp eyes và ears để chúng ta biết chính xác đang xảy ra gì.

Tôi khuyến khích mọi team bắt đầu bằng việc: (1) xác định các điểm vào edge mà lưu lượng đi qua, (2) triển khai một agent thu thập metrics và logs từ edge vào hệ thống trung tâm, (3) tách namespace và node pool cho quan sát, (4) viết một số rule alert đơn giản kết hợp metrics và logs, (5) tự động hóa một hành động phản hồi cơ bản như scale pod hoặc thay đổi rate limit ở Cloudflare. Từ đó, bạn có thể mở rộng dần sang tracing, chatops và các runworkflow phức tạp hơn.

Cuối cùng, nhớ rằng mục tiêu không phải là never có sự cố mà là giảm thiểu thời gian hệ thống không khả dụng và cung cấp cho team thông tin cần thiết để khắc phục nhanh chóng. Khi bạn có thể nhìn thấy sự cố từ edge tới bên trong cluster trong một dashboard duy nhất, bạn đã đi được một bước dài trên hành trình xây dựng hệ thống chịu lỗi thực sự.

Monitoring dashboard overview

Ảnh: winkelnkemper, CC BY-SA 2.0 qua wikimedia (nguồn) Cloudflare edge network diagram

Ảnh: Quirk seacom, BY-SA qua openverse (nguồn) K8s node pool separation illustration

Ảnh: Jemimus, BY qua openverse (nguồn)