Chaos Engineering trên Kubernetes với Chaos Mesh: Hướng dẫn thực hành Fault Injection

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Quick start (5 phút): Cài đặt và vận hành Chaos Mesh

Các hệ thống phân tán trên môi trường production thường gặp sự cố theo những cách rất phức tạp và khó lường. Một cloud node có thể sập mà không hề báo trước. Cổng thanh toán của bên thứ ba đột ngột tăng vọt độ trễ thêm 450ms. Một service xác thực bị cạn kiệt bộ nhớ khi chịu tải cao. Khi các thành phần downstream thiếu cơ chế timeout chặt chẽ và tính năng cô lập, những trục trặc cục bộ này sẽ tạo hiệu ứng domino dẫn đến sập toàn bộ nền tảng.

Chaos Engineering sẽ thay đổi hoàn toàn cục diện này. Thay vì ngồi chờ sự cố xảy ra lúc 3 giờ sáng để phát hiện điểm yếu, bạn chủ động inject các gián đoạn có kiểm soát ngay trong giờ làm việc. Chaos Mesh giúp việc này trở nên đơn giản trên Kubernetes bằng cách vận hành các thử nghiệm thông qua Custom Resource Definitions (CRDs) native cùng khả năng inject chi tiết ở cấp độ kernel.

Bước 1: Cài đặt Chaos Mesh bằng Helm

Cài đặt Chaos Mesh vào một cụm Kubernetes hiện có (v1.19+) bằng Helm 3. Bắt đầu bằng việc thêm kho lưu trữ chart chính thức và cập nhật index cục bộ:

helm repo add chaos-mesh https://charts.chaos-mesh.org
helm repo update

Tiếp theo, hãy cài đặt Chaos Mesh vào một namespace riêng biệt là chaos-mesh và bật web dashboard. Đối với các cụm chạy containerd (chẳng hạn như EKS tiêu chuẩn, GKE hoặc k3s), hãy chỉ định đường dẫn runtime socket:

kubectl create namespace chaos-mesh

helm install chaos-mesh chaos-mesh/chaos-mesh \
  --namespace=chaos-mesh \
  --set dashboard.create=true \
  --set chaosDaemon.runtime=containerd \
  --set chaosDaemon.socketPath=/run/containerd/containerd.sock

Xác minh rằng tất cả các thành phần cốt lõi—controller manager, daemonset chaos daemon và dashboard—đều đã chuyển sang trạng thái Running:

kubectl get pods -n chaos-mesh -o wide

Bước 2: Triển khai ứng dụng đích Demo

Để đánh giá an toàn các kịch bản lỗi, hãy triển khai một workload Nginx nhẹ gồm 3 replica trong một namespace sandbox riêng biệt:

kubectl create namespace app-test

kubectl create deployment web-target \
  --image=nginx:alpine \
  --replicas=3 \
  --namespace=app-test

Bước 3: Chạy thử nghiệm Pod Termination đầu tiên

Kiểm tra khả năng sẵn sàng failover của dịch vụ. Manifest này sẽ kill ngẫu nhiên một pod khớp với nhãn app: web-target:

apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
  name: pod-kill-demo
  namespace: app-test
spec:
  action: pod-kill
  mode: one
  selector:
    namespaces:
      - app-test
    labelSelectors:
      app: web-target

Áp dụng manifest và quan sát Kubernetes ngay lập tức khởi tạo một replica thay thế:

kubectl apply -f pod-kill-demo.yaml

# Theo dõi các sự kiện vòng đời và quá trình phục hồi của pod
kubectl get pods -n app-test -w

Đi sâu phân tích: Mô phỏng các kịch bản sự cố thực tế

1. Vấn đề Cascading Timeout (Độ trễ mạng)

Vấn đề: Trong chuỗi microservices, Checkout API thực hiện các lệnh gọi đồng bộ đến Inventory Service. Khi xảy ra tranh chấp khóa cơ sở dữ liệu nghiêm trọng, thời gian phản hồi của Inventory tăng vọt từ 15ms lên 2.400ms. Nếu Checkout API thiếu cơ chế client timeout chặt chẽ và circuit breaker, thread pool của nó sẽ bị quá tải chỉ sau vài giây. Toàn bộ frontend sẽ bị treo.

Nguyên nhân gốc rễ: Các upstream service mặc định rằng mạng luôn đạt độ trễ thấp như trong mạng LAN. Chúng bỏ qua circuit breaker, không thiết lập phản hồi fallback và cấu hình HTTP connection pool không giới hạn.

Giải pháp thực tế: Inject độ trễ nhân tạo vào service đích bằng NetworkChaos. Điều này giúp kiểm tra xem các caller upstream có kích hoạt circuit breaker hay hạ cấp dịch vụ một cách mềm dẻo mà không làm mất request của người dùng hay không.

apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
  name: network-delay-experiment
  namespace: app-test
spec:
  action: delay
  mode: all
  selector:
    namespaces:
      - app-test
    labelSelectors:
      app: web-target
  delay:
    latency: '800ms'
    jitter: '150ms'
    correlation: '25'
  duration: '5m'

Hãy theo dõi dashboard Grafana trong khi thử nghiệm đang chạy. Nếu độ trễ p99 của upstream tăng vọt ở cả những endpoint không liên quan, bạn cần tinh chỉnh lại cấu hình client timeout của mình.

2. Vấn đề mất gói tin gián đoạn (Packet Loss)

Vấn đề: Hiện tượng nghẽn mạng giữa các Availability Zone (Cross-AZ) hoặc quá tải lớp mạng CNI overlay (như Cilium hoặc Calico) khiến 10% đến 15% gói tin bị drop ngắt quãng. Người dùng thi thoảng gặp lỗi 502 Bad Gateway hoặc 504 Gateway Timeout. Trong khi đó, các liveness probe tiêu chuẩn của Kubernetes vẫn báo xanh.

Nguyên nhân gốc rễ: Các liveness probe định kỳ chỉ thực hiện một TCP handshake duy nhất mỗi 10 giây. Chúng hầu như không thể phát hiện tình trạng mất gói ngẫu nhiên trên các luồng ghép kênh gRPC và HTTP/2 đang hoạt động với thông lượng cao.

Giải pháp thực tế: Áp dụng NetworkChaos với cấu hình mất gói tin nhắm vào 2 replica cụ thể để xác minh cơ chế retry ở cấp độ ứng dụng:

apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
  name: packet-loss-experiment
  namespace: app-test
spec:
  action: loss
  mode: fixed
  value: '2'
  selector:
    namespaces:
      - app-test
    labelSelectors:
      app: web-target
  loss:
    loss: '15'
    correlation: '50'
  duration: '3m'

3. Áp lực bộ nhớ và OOM Eviction (Căng thẳng tài nguyên)

Vấn đề: Lượng truy vấn tăng đột biến khiến mức tiêu thụ bộ nhớ vượt quá giới hạn (limit) của container. Cơ chế OOM-killer của Linux kernel sẽ lập tức kill container đó. Nếu nhiều replica cùng chạm ngưỡng này, service sẽ sập hoàn toàn trước khi Horizontal Pod Autoscaler (HPA) kịp schedule các pod mới.

Nguyên nhân gốc rễ: Giới hạn cgroup memory của container quá chặt chẽ kết hợp với các chỉ số scaling chậm của HPA (ví dụ: chu kỳ đánh giá 60 giây) và các runtime ngốn bộ nhớ như JVM/Node.js.

Giải pháp thực tế: Áp dụng StressChaos để đẩy mức tiêu thụ bộ nhớ lên 512MB trên hai worker thread. Thao tác này giúp kiểm tra xem HPA có kịp scale out trước khi các pod bị kill hay không:

apiVersion: chaos-mesh.org/v1alpha1
kind: StressChaos
metadata:
  name: memory-stress-test
  namespace: app-test
spec:
  mode: one
  selector:
    namespaces:
      - app-test
    labelSelectors:
      app: web-target
  stressors:
    memory:
      workers: 2
      size: '512Mi'
  duration: '2m'

Sử dụng nâng cao: Điều phối Chaos Workflow và Tự động hóa CI/CD

Tự động hóa pipeline thử nghiệm với Workflow CRD

Các thử nghiệm chaos đơn lẻ rất hữu ích cho việc debug, nhưng các buổi diễn tập độ bền bỉ định kỳ đòi hỏi quy trình thực thi có cấu trúc. Workflow CRD của Chaos Mesh cho phép bạn liên kết theo chuỗi và chạy song song các chuỗi kịch bản lỗi phức tạp cùng với các khoảng đệm phục hồi tích hợp sẵn.

apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
  name: microservice-disaster-drill
  namespace: app-test
spec:
  entry: main-pipeline
  templates:
    - name: main-pipeline
      templateType: Serial
      children:
        - network-delay-step
        - recovery-pause
        - pod-kill-step
    - name: network-delay-step
      templateType: NetworkChaos
      deadline: 2m
      networkChaos:
        action: delay
        mode: all
        selector:
          namespaces:
            - app-test
          labelSelectors:
            app: web-target
        delay:
          latency: '500ms'
    - name: recovery-pause
      templateType: Suspend
      deadline: 1m
    - name: pod-kill-step
      templateType: PodChaos
      deadline: 1m
      podChaos:
        action: pod-kill
        mode: one
        selector:
          namespaces:
            - app-test
          labelSelectors:
            app: web-target

Tích hợp thử nghiệm Chaos vào CI/CD Pipeline

Xác thực khả năng phục hồi trước khi merge PR. Bạn có thể kích hoạt các chaos workflow trên môi trường staging trực tiếp từ GitHub Actions, GitLab CI hoặc Argo Workflows song song với các bài kiểm thử tải mô phỏng:

# 1. Kích hoạt chaos workflow trong quá trình chạy integration tự động
kubectl apply -f workflows/microservice-disaster-drill.yaml

# 2. Chạy kiểm thử tải mô phỏng lên service đang bị suy giảm hiệu năng
k6 run --vus 50 --duration 90s loadtests/checkout-flow.js

# 3. Kiểm tra xem workflow đã hoàn thành thành công hay chưa
kubectl get workflow microservice-disaster-drill -n app-test \
  -o jsonpath='{.status.conditions[?(@.type=="Accomplished")].status}'

# 4. Dọn dẹp tài nguyên workflow
kubectl delete -f workflows/microservice-disaster-drill.yaml

Lời khuyên thực tế: Thực hiện Chaos Test một cách an toàn

  • Xác định trước các chỉ số trạng thái ổn định: Thiết lập các chỉ số service level rõ ràng trước khi tác động vào bất kỳ cluster nào. Ví dụ: “Khi inject 500ms độ trễ, tỷ lệ lỗi phải duy trì dưới 0,5% và độ trễ p95 phải dưới 750ms.” Nếu hệ thống giám sát (observability) không thể đo lường điều này theo thời gian thực, hãy dừng thử nghiệm và hoàn thiện telemetry trước.
  • Cô lập mục tiêu chaos bằng RBAC: Không bao giờ cấp quyền inject lỗi trên toàn bộ cluster. Hãy giới hạn controller của Chaos Mesh chỉ nhắm vào các namespace staging hoặc test cụ thể bằng Kubernetes Role-Based Access Control (RBAC) và namespaceSelectors rõ ràng.
  • Chuẩn bị sẵn lệnh dừng khẩn cấp: Luôn nắm rõ quy trình rollback trước khi kích hoạt bất kỳ thử nghiệm nào. Việc xóa một resource chaos sẽ lập tức xóa sạch các quy tắc iptables và Traffic Control (TC) qdiscs bên dưới kernel:
# Hủy ngay lập tức tất cả các thử nghiệm network chaos đang hoạt động
kubectl delete networkchaos --all -n app-test
  • Thực hiện thử nghiệm trong giờ hành chính với đầy đủ đội ngũ: Khi chuyển thử nghiệm sang môi trường staging hoặc canary production, hãy chạy chúng vào lúc các kỹ sư on-call và chuyên gia liên quan luôn sẵn sàng theo dõi dữ liệu telemetry của hệ thống.
Share: