Vượt xa iptables: Cách chúng tôi mở rộng mạng Kubernetes với Cilium và eBPF

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

Vượt xa iptables: Tại sao chúng tôi chuyển sang Cilium

Hầu hết các cụm Kubernetes bắt đầu bằng iptables hoặc IPVS để định tuyến lưu lượng. Các công cụ này hoạt động tốt ở quy mô nhỏ, nhưng chúng không được thiết kế cho sự biến động của hơn 10.000 service endpoint. Khi cụm production của chúng tôi đạt đến 200 node, chúng tôi nhận thấy mức tiêu thụ CPU tăng đáng kể. Mỗi khi một pod mới được scale, kernel phải thực hiện tìm kiếm tuyến tính qua hàng nghìn quy tắc tuần tự. Điều này gây kém hiệu quả và khiến việc khắc phục sự cố trở nên khó khăn.

Sáu tháng trước, độ trễ mạng của chúng tôi bắt đầu tăng thêm 15-20ms trong thời gian cao điểm. Đồng thời, đội ngũ bảo mật yêu cầu khả năng giám sát chi tiết đối với giao tiếp giữa các pod mà log tiêu chuẩn không cung cấp được. Chúng tôi đã chọn chuyển sang Cilium. Khác với các CNI truyền thống, Cilium tận dụng eBPF (Extended Berkeley Packet Filter). Điều này cho phép chúng tôi chạy các chương trình sandboxed trực tiếp trong Linux kernel, bỏ qua hoàn toàn stack iptables chậm chạp.

Kết quả trong môi trường production của chúng tôi rất ổn định. Việc chuyển sang CNI dựa trên eBPF đã thay đổi cơ bản cách chúng tôi xử lý bảo mật và giám sát. Hướng dẫn này phác thảo các bước thực tế để triển khai Cilium và giải thích tại sao đây là lựa chọn chiến lược cho hạ tầng hiện đại.

Bước 1: Chuẩn bị môi trường và cài đặt

Để có hiệu suất tốt nhất, bạn nên triển khai Cilium trên một cụm chưa có CNI. Nếu bạn đang sử dụng các dịch vụ quản lý như EKS hoặc GKE, bạn thường có thể vô hiệu hóa nhà cung cấp mặc định trong khi khởi tạo. Tôi khuyên bạn nên sử dụng Cilium CLI để kiểm tra ban đầu.

Đầu tiên, tải và cài đặt tệp thực thi. Công cụ này thực hiện các bước kiểm tra tiền khả thi để đảm bảo các node của bạn tương thích với eBPF.

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all "https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}"
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

Tôi thích sử dụng Helm để triển khai thực tế hơn. Nó tích hợp tốt hơn với các pipeline GitOps và giúp quản lý phiên bản dễ dàng hơn. Ở đây chúng tôi sử dụng phiên bản 1.16.0 để tận dụng các bản vá hiệu suất mới nhất.

helm repo add cilium https://helm.cilium.io/

helm install cilium cilium/cilium --version 1.16.0 \
  --namespace kube-system \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set prometheus.enabled=true \
  --set operator.prometheus.enabled=true \
  --set kubeProxyReplacement=true

Thiết lập kubeProxyReplacement=true là bước quan trọng. Nó chỉ định Cilium xử lý trực tiếp các dịch vụ LoadBalancer và NodePort, loại bỏ sự cần thiết của kube-proxy. Khi các pod đã chạy, hãy kiểm tra trạng thái của mesh:

cilium status --wait

Bước 2: Triển khai chính sách L7 để bảo mật chi tiết

Các NetworkPolicy tiêu chuẩn của Kubernetes là những công cụ khá thô sơ. Chúng hoạt động ở Layer 3 và 4, nghĩa là bạn chỉ có thể chặn IP hoặc Port. Nếu bạn muốn cho phép một pod truy cập api.github.com trong khi chặn các lưu lượng bên ngoài khác, các chính sách tiêu chuẩn sẽ thất bại vì địa chỉ IP của GitHub thay đổi thường xuyên.

Cilium cung cấp các chính sách nhận diện FQDNlọc Layer 7 (HTTP). Trong thiết lập của mình, chúng tôi đã giới hạn frontend để nó chỉ có thể thực hiện các yêu cầu GET trên một đường dẫn API cụ thể. Điều này ngăn chặn sự di chuyển ngang (lateral movement) nếu một pod bị xâm nhập.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "restrict-api-access"
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: backend-service
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend-web
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/api/v1/public/.*"

Mức độ kiểm soát này rất quan trọng. Nếu kẻ tấn công cố gắng POST dữ liệu độc hại hoặc truy cập vào endpoint /admin, kernel sẽ hủy gói tin ngay lập tức. Vì eBPF xử lý việc lọc này trong data plane, chúng tôi không thấy độ trễ yêu cầu tăng lên đáng kể.

Bước 3: Khả năng quan sát thời gian thực với Hubble

Lợi ích rõ rệt nhất của Cilium là Hubble. Việc gỡ lỗi các lỗi “Connection Refused” trong một hệ thống phân tán thường đòi hỏi tcpdump và rất nhiều sự kiên nhẫn. Hubble thay đổi điều đó bằng cách cung cấp luồng dữ liệu cấp cao của mọi luồng (flow) trong cụm.

Bạn có thể theo dõi lưu lượng trực tiếp từ terminal để xem chính xác chính sách nào đang chặn gói tin:

cilium hubble port-forward &
hubble observe --namespace production --follow --outcome dropped

Nếu bạn thích giao diện đồ họa (GUI), Hubble UI sẽ tạo ra một bản đồ dịch vụ động. Nó tự động vẽ các mối quan hệ phụ thuộc giữa các microservice dựa trên lưu lượng thực tế. Đây là một điểm cộng lớn cho đội ngũ của chúng tôi. Chúng tôi đã sử dụng nó để xác định một số dịch vụ cũ vẫn đang thực hiện các cuộc gọi trái phép đến cơ sở dữ liệu. Để khởi chạy dashboard, chỉ cần chạy:

cilium hubble ui

Truy cập vào localhost:12000 sẽ cho bạn hình ảnh trực quan về sức khỏe của cụm. Việc nhìn thấy các “đường màu đỏ” đại diện cho lưu lượng bị chặn giúp xác nhận ngay lập tức rằng các chính sách bảo mật của bạn đang hoạt động như mong đợi.

Bài học sau 6 tháng chạy Production

Việc duy trì Cilium khá đơn giản, nhưng nó đòi hỏi sự thay đổi trong tư duy về tài nguyên của node. Dưới đây là ba bài học chính từ hành trình của chúng tôi:

  • Nâng cấp Kernel: Mặc dù Cilium hỗ trợ các phiên bản cũ, bạn thực sự cần Linux 5.10 trở lên. Chúng tôi đã chuyển sang 5.15 để sử dụng các eBPF helper hiệu quả nhất, giúp giảm thêm 5% mức sử dụng CPU của node.
  • Theo dõi bộ nhớ: Cilium agent tiêu tốn nhiều tài nguyên hơn Flannel. Hãy dự tính cấp khoảng 200MB đến 500MB RAM cho mỗi node, đặc biệt nếu bạn có số lượng kết nối đồng thời cao và bật Hubble.
  • Loại bỏ kube-proxy: Đừng chạy cả hai. Sử dụng Cilium ở chế độ thay thế hoàn toàn giúp đơn giản hóa stack mạng và loại bỏ sự phức tạp khi quản lý các bộ quy tắc iptables khổng lồ.

Cilium không chỉ là một CNI; nó là một nền tảng bảo mật và quan sát được tích hợp vào kernel. Nếu bạn đang mở rộng môi trường Kubernetes của mình, eBPF là con đường hiệu quả nhất để tiến xa hơn.

Share: