Ngừng “dập lửa”: Xây dựng hệ thống Kubernetes hướng sự kiện với Argo Events

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

Cuộc gọi đánh thức lúc 2:14 sáng

PagerDuty của tôi không chỉ kêu bíp; nó gào thét. Một lập trình viên đã đẩy bộ dữ liệu 50GB vào một S3 bucket, nhưng script xử lý cũ kỹ của chúng tôi đã không bắt được nó. Các dịch vụ hạ nguồn (downstream) rơi vào trạng thái chờ, và pipeline sản xuất của chúng tôi bị đình trệ. Tôi đã dành 90 phút tiếp theo để gõ lệnh thủ công vào terminal—công việc mà lẽ ra máy móc phải xử lý trong vài giây. Đêm đó, tôi nhận ra chúng tôi không thể dựa vào các cron job hay sự may mắn. Chúng tôi cần một hệ thống có thể phản ứng với môi trường theo thời gian thực.

Argo Events thu hẹp khoảng cách giữa các tín hiệu bên ngoài và các hành động trong Kubernetes. Đây là một framework hướng sự kiện (event-driven) mạnh mẽ, giúp kích hoạt các đối tượng K8s, Argo Workflows hoặc serverless functions dựa trên hơn 20 nguồn sự kiện khác nhau. Kể từ khi triển khai hệ thống này 18 tháng trước, đội ngũ của chúng tôi đã giảm được 90% sự can thiệp thủ công đối với việc khởi động lại các data pipeline.

Bắt đầu nhanh: Khởi chạy trong 5 phút

Hãy để controller hoạt động trước khi chúng ta đi sâu vào các logic phức tạp. Bạn sẽ cần một cụm Kubernetes (v1.24+) và quyền truy cập qua kubectl.

1. Cài đặt Argo Events

Trước tiên, hãy tạo một namespace riêng biệt để giữ cho hạ tầng sự kiện của bạn được cô lập. Điều này giúp quản lý vòng đời của các event source và sensor.

kubectl create namespace argo-events
kubectl apply -n argo-events -f https://raw.githubusercontent.com/argoproj/argo-events/stable/manifests/install.yaml
# Validating admission controller giúp phát hiện các lỗi YAML sớm
kubectl apply -n argo-events -f https://raw.githubusercontent.com/argoproj/argo-events/stable/manifests/install-validating-webhook.yaml

2. Triển khai Event Bus

Hãy coi Event Bus như hệ thần kinh của toàn bộ thiết lập. Nó truyền tải thông điệp giữa nguồn cấp (source) và hành động (action). Chúng ta sẽ sử dụng NATS Jetstream để đảm bảo tính sẵn sàng cao.

apiVersion: argoproj.io/v1alpha1
kind: EventBus
metadata:
  name: default
  namespace: argo-events
spec:
  nats:
    native:
      replicas: 3

Áp dụng cấu hình này bằng lệnh kubectl apply -f eventbus.yaml. Cụm của bạn hiện đã sẵn sàng để lắng nghe các tín hiệu bên ngoài.

Ba trụ cột của tự động hóa sự kiện

Để thoát khỏi việc vận hành thủ công, bạn phải hiểu cách Argo Events cấu trúc logic của nó. Nó dựa trên ba thành phần chính: EventSource, Sensor và Trigger.

EventSource: Bộ phận lắng nghe

Một EventSource là một pod chạy lâu dài có nhiệm vụ theo dõi thế giới bên ngoài. Cho dù đó là một GitHub PR, một file mới xuất hiện trong S3, hay một tin nhắn trong Kafka topic, EventSource sẽ bắt lấy tín hiệu đó. Sau đó, it định dạng tín hiệu dưới dạng CloudEvent và đẩy vào Event Bus.

Sensor: Bộ não xử lý logic

Sensor đóng vai trò là bộ não. Nó lắng nghe Event Bus và quyết định xem có cần thực hiện hành động nào hay không. Bạn có thể định nghĩa các phụ thuộc (dependencies) phức tạp tại đây. Ví dụ: bạn có thể chỉ kích hoạt một quy trình nếu có file upload lên S3 VÀ một webhook xác nhận rằng metadata đó hợp lệ.

Trigger: Hành động cuối cùng

Trigger định nghĩa tài nguyên thực tế mà bạn muốn tạo ra. Mặc dù hầu hết các đội ngũ sử dụng nó để khởi chạy một Argo Workflow, nó cũng có thể tạo các Kubernetes Jobs tiêu chuẩn hoặc thậm chí gửi thông báo Slack thông qua một HTTP request thông thường.

Kịch bản thực tế: Tự động hóa S3 Data Pipelines

Hãy tưởng tượng bạn cần xác thực dữ liệu mỗi khi một file CSV được đẩy vào một bucket cụ thể. Việc kiểm tra thủ công là không thể khi quy mô lớn dần. Thay vào đó, chúng ta có thể tự động hóa toàn bộ quy trình chỉ với vài dòng cấu hình.

Ví dụ: S3 EventSource

Cấu hình này giám sát một bucket cụ thể cho các sự kiện s3:ObjectCreated:Put. Nó phản ứng chỉ trong vài mili giây sau khi file được upload.

apiVersion: argoproj.io/v1alpha1
kind: EventSource
metadata:
  name: aws-s3-event-source
spec:
  s3:
    example-bucket:
      bucket: my-data-science-input
      endpoint: s3.amazonaws.com
      events:
        - s3:ObjectCreated:Put
      region: us-east-1
      accessKey:
        name: aws-secret
        key: accessKey
      secretKey:
        name: aws-secret
        key: secretKey

Logic của Sensor

Tiếp theo, chúng ta kết nối sự kiện S3 đó với một Workflow. Chúng ta sử dụng dataFilters để đảm bảo hệ thống chỉ xử lý các file có đuôi .csv, bỏ qua các file log hoặc file tạm.

apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
  name: s3-sensor
spec:
  template:
    serviceAccountName: argo-events-sa
  dependencies:
    - name: s3-dep
      eventSourceName: aws-s3-event-source
      eventName: example-bucket
      filters:
        data:
          - path: "notification.s3.object.key"
            type: string
            comparator: ".*\\.csv$"
  triggers:
    - template:
        name: s3-workflow-trigger
        k8s:
          operation: create
          source:
            resource:
              apiVersion: argoproj.io/v1alpha1
              kind: Workflow
              metadata:
                generateName: s3-processing-job-
              spec:
                entrypoint: process
                templates:
                  - name: process
                    container:
                      image: my-docker-repo/processor:latest
          parameters:
            - src:
                dependencyName: s3-dep
                dataKey: notification.s3.object.key
              dest: spec.arguments.parameters.0.value

Kinh nghiệm thực chiến cho môi trường Production

Chuyển từ môi trường thử nghiệm sang môi trường production đòi hỏi một sự thay đổi trong tư duy. Khi các sự kiện bắt đầu dồn dập với tốc độ 100 cái mỗi giây, những lỗi cấu hình nhỏ có thể trở thành sự cố lớn.

1. RBAC là “kẻ sát nhân thầm lặng”

Nếu Sensor của bạn không khởi chạy được Workflow, nguyên nhân hầu như luôn nằm ở phân quyền. Pod của Sensor cần một ServiceAccount có quyền createpatch tài nguyên. Tôi đã mất vô số giờ để khắc phục các lỗi “im lặng” mà thực chất chỉ là thiếu các quy tắc RBAC cho workflows.argoproj.io.

2. Gỡ lỗi Pipeline

Luôn kiểm tra log của EventSource trước. Nếu bạn không thấy payload JSON gửi đến đó, cụm của bạn thậm chí còn chưa nhận được tín hiệu từ AWS hoặc GitHub. Sử dụng lệnh kubectl logs -f [tên-pod-eventsource] để xác nhận kết nối trước khi bắt đầu tinh chỉnh logic của Sensor.

3. Đảm bảo tính Idempotency

Trong các hệ thống phân tán, việc phân phối “đúng một lần” (exactly-once) là một điều không tưởng. Các sự kiện cuối cùng rồi cũng sẽ bị gửi lặp lại ít nhất một lần. Workflow của bạn phải an toàn khi chạy nhiều lần. Tôi thường thêm một bước kiểm tra trước (pre-flight check) trong container để xem event-id hoặc tên file cụ thể đó đã được ghi lại trong cơ sở dữ liệu theo dõi của chúng tôi chưa.

4. Ngăn chặn “bão sự kiện”

Một đợt bùng nổ đột ngột của 1.000 file upload có thể dễ dàng làm sập cụm bằng cách tạo ra 1.000 workflow đồng thời. Hãy sử dụng phần filters trong Sensor để thu hẹp phạm vi. Ngoài ra, hãy thiết lập resource quotas cho namespace để sự gia tăng đột biến của sự kiện không làm cạn kiệt tài nguyên CPU và bộ nhớ của các dịch vụ ứng dụng cốt lõi.

Lời kết

Việc áp dụng Argo Events đã thay đổi hoàn toàn cách đội ngũ của tôi quản lý hạ tầng. Chúng tôi không còn là những người “dập lửa” thụ động mà bắt đầu xây dựng các hệ thống tự phục hồi. Bằng cách kết nối trực tiếp S3, GitHub và Webhooks vào Kubernetes, bạn sẽ loại bỏ được nút thắt cổ chai từ con người. Cấu hình YAML ban đầu có thể tốn công sức, nhưng phần thưởng là một hệ thống hoạt động trơn tru ngay cả khi bạn đang ngủ.

Share: