•9 min read

Định nghĩa tài nguyên tùy chỉnh của Kubernetes

Định nghĩa tài nguyên tùy chỉnh của Kubernetes

Kubernetes đã khẳng định vững chắc vị thế là hệ điều hành thực tế cho đám mây. Tuy nhiên, sức mạnh thực sự của nó không chỉ nằm ở việc điều phối các workload tiêu chuẩn như Pods, Deployments và Services. Tiềm năng chuyển đổi thực sự của Kubernetes được mở khóa thông qua khả năng mở rộng của nó, chủ yếu thông qua Custom Resource Definitions (CRD). CRD cho phép các nhà phát triển mở rộng API Kubernetes, định nghĩa các loại đối tượng tùy chỉnh hoạt động giống như các tài nguyên gốc.

Trong bài viết chuyên sâu toàn diện này, chúng ta sẽ khám phá các nền tảng kiến trúc của CRD, cơ chế của các bộ điều khiển tùy chỉnh, các chiến lược quản lý phiên bản API và các kỹ thuật xác thực nâng cao bằng cách sử dụng Webhooks.

Audio Briefing
0:00 / 0:00

Mô hình khả năng mở rộng

Để hiểu rõ về CRD, trước tiên chúng ta cần hiểu cách kiến trúc của mặt phẳng điều khiển Kubernetes. Về cốt lõi, Kubernetes API Server (kube-apiserver) là một giao diện RESTful hoạt động như giao diện người dùng cho kho trạng thái của cluster (thường là etcd). Nó xử lý việc xác thực, ủy quyền và cấp phép cho tất cả các yêu cầu.

Trong lịch sử, việc mở rộng API này đòi hỏi phải sửa đổi mã nguồn của chính API Server. Cách tiếp cận nguyên khối này không bền vững. Việc giới thiệu Custom Resource Definitions (ban đầu là ThirdPartyResources) đã tách rời cơ chế mở rộng. Một CRD cho phép bạn khai báo một lược đồ mới một cách linh hoạt. Sau khi được định nghĩa, API Server ngay lập tức hiển thị các endpoint RESTful cho tài nguyên mới, cung cấp các hoạt động Tạo, Đọc, Cập nhật và Xóa (CRUD), hoàn chỉnh với hỗ trợ Kiểm soát truy cập dựa trên vai trò (RBAC).

Advertisement

Giải phẫu một CRD

Hãy cùng phân tích một đặc tả CRD điển hình. Khi bạn tạo một CRD, bạn định nghĩa nhóm, phiên bản và loại (GVK) của tài nguyên mới. Hơn nữa, bạn định nghĩa lược đồ bằng cách sử dụng đặc tả OpenAPI v3.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.company.com
spec:
  group: company.com
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                engine:
                  type: string
                  enum: ["postgres", "mysql"]
                replicas:
                  type: integer
                  minimum: 1
  scope: Namespaced
  names:
    plural: databases
    singular: database
    kind: Database
    shortNames:
    - db

Trong ví dụ này, chúng ta định nghĩa một tài nguyên Database. openAPIV3Schema định kiểu cấu trúc cho tài nguyên tùy chỉnh, đảm bảo rằng bất kỳ payload nào được gửi đến máy chủ API đều tuân thủ nghiêm ngặt hình dạng mong đợi. Trong trường hợp của chúng ta, engine phải là postgres hoặc mysql, và replicas phải ít nhất là 1. Việc xác thực lược đồ này được API Server thực thi một cách đồng bộ.

Mô hình Operator: Đưa CRD vào cuộc sống

Một mình CRD chỉ là dữ liệu tĩnh trong etcd. Nó định nghĩa cái gì nên tồn tại, nhưng không định nghĩa cách để làm cho nó xảy ra. Đây là lúc Mô hình Operator phát huy tác dụng. Một Operator là một bộ điều khiển tùy chỉnh theo dõi các thay đổi đối với tài nguyên tùy chỉnh của bạn và điều hòa trạng thái hiện tại của cluster với trạng thái mong muốn được chỉ định trong CRD.

Các bộ điều khiển hoạt động trên một vòng lặp điều hòa được kích hoạt theo cấp độ. Khi một đối tượng Database được tạo, API Server phát ra một sự kiện. Bộ điều khiển tùy chỉnh, thường được viết bằng Go sử dụng thư viện controller-runtime, nhận sự kiện này, đọc đặc tả CRD và cung cấp các tài nguyên cơ bản tương ứng—có thể là một StatefulSet cho các pod cơ sở dữ liệu, một Service cho mạng và một Secret cho thông tin đăng nhập.

Điều hòa trạng thái và tính bất biến

Nguyên tắc cốt lõi của một bộ điều khiển là tính bất biến. Bộ điều khiển không chỉ phản ứng với các sự kiện; nó định kỳ so sánh trạng thái mong muốn với trạng thái thực tế. Nếu người dùng xóa thủ công StatefulSet hỗ trợ Database, bộ điều khiển sẽ phát hiện sự sai lệch và tạo lại nó.

func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var db companyv1alpha1.Database
    if err := r.Get(ctx, req.NamespacedName, &db); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // Logic to ensure a StatefulSet exists with the correct configuration
    // matching db.Spec.Replicas and db.Spec.Engine
    // ...

    return ctrl.Result{}, nil
}

Xác thực và biến đổi nâng cao: Webhooks

Mặc dù xác thực lược đồ OpenAPI rất mạnh mẽ, nhưng nó có những hạn chế. Điều gì sẽ xảy ra nếu bạn cần đảm bảo rằng tên cơ sở dữ liệu là duy nhất trên các namespace? Hoặc điều gì sẽ xảy ra nếu bạn muốn đặt các giá trị mặc định động? Đây là lúc Admission Webhooks phát huy tác dụng.

Kubernetes cho phép bạn chặn các yêu cầu API thông qua ValidatingAdmissionWebhooks và MutatingAdmissionWebhooks.

  1. Mutating Webhooks: Chúng chặn yêu cầu trước khi xác thực lược đồ. Chúng chủ yếu được sử dụng để đặt giá trị mặc định. Ví dụ, nếu người dùng không chỉ định lịch sao lưu trong CRD Database của họ, một mutating webhook có thể tự động chèn một biểu thức cron mặc định vào payload trước khi nó được lưu trữ.
  2. Validating Webhooks: Chúng chạy sau khi biến đổi và xác thực lược đồ nhưng trước khi đối tượng được commit vào etcd. Chúng thực thi logic xác thực phức tạp, bắt buộc. Một validating webhook có thể truy vấn một công cụ chính sách doanh nghiệp bên ngoài để đảm bảo người dùng có ngân sách trung tâm chi phí phù hợp để triển khai cơ sở dữ liệu đa bản sao.
Advertisement

Quản lý vòng đời: Quản lý phiên bản API

Khi tài nguyên tùy chỉnh của bạn phát triển, bạn chắc chắn sẽ cần thay đổi lược đồ của chúng. Kubernetes xử lý điều này một cách duyên dáng thông qua việc quản lý phiên bản CRD và các webhook chuyển đổi.

Khi bạn giới thiệu phiên bản v1 thay thế v1alpha1, bạn có thể cấu hình API Server để phục vụ cả hai phiên bản đồng thời. Tuy nhiên, chỉ có thể có một phiên bản lưu trữ trong etcd.

Để thu hẹp khoảng cách giữa các phiên bản, bạn triển khai một Conversion Webhook. Khi một client yêu cầu v1alpha1, nhưng dữ liệu được lưu trữ dưới dạng v1, API Server sẽ gọi Conversion Webhook của bạn, chuyển đổi payload JSON v1 thành v1alpha1 ngay lập tức. Điều này cung cấp một lộ trình di chuyển liền mạch, cho phép các client cũ tiếp tục hoạt động trong khi lược đồ backend phát triển.

Lược đồ cấu trúc và cắt tỉa

Với apiextensions.k8s.io/v1, Kubernetes thực thi nghiêm ngặt các lược đồ cấu trúc cho CRD. Việc thực thi này rất quan trọng đối với một tính năng được gọi là cắt tỉa. Nếu người dùng gửi một CRD với các trường thừa không được định nghĩa trong lược đồ OpenAPI, API Server sẽ tự động loại bỏ (cắt tỉa) chúng trước khi lưu trữ đối tượng. Điều này ngăn chặn sự phình to của etcd và đảm bảo tính nhất quán của dữ liệu.

Hơn nữa, việc tích hợp CRD hiệu quả vào hệ thống của bạn có nghĩa là hiểu rõ các sắc thái của Finalizers. Finalizers hoạt động như các hook trước khi xóa, ngăn một tài nguyên tùy chỉnh bị xóa hoàn toàn khỏi etcd cho đến khi bộ điều khiển liên quan đã dọn dẹp thành công tất cả các phụ thuộc bên ngoài hoặc các đối tượng con mà nó quản lý. Sau khi quá trình dọn dẹp hoàn tất, bộ điều khiển sẽ xóa finalizer, cho phép quá trình xóa tiếp tục.

Các cân nhắc về bảo mật cho các phần mở rộng

Bảo mật không thể là một suy nghĩ sau khi mở rộng API Kubernetes. Vì CRD giới thiệu các endpoint mới, chúng phải được quản lý chặt chẽ bởi RBAC. Bạn nên luôn thực thi nguyên tắc đặc quyền tối thiểu, đảm bảo rằng chỉ các ServiceAccount hoặc nhóm người dùng cụ thể mới có quyền create, update hoặc delete trên các tài nguyên tùy chỉnh của bạn.

Ngoài ra, hãy xem xét các vector cạn kiệt tài nguyên. Một bộ điều khiển được viết kém có thể liên tục lặp lại khi gặp lỗi, tạo ra các bản ghi khổng lồ và có khả năng làm gián đoạn các thành phần khác. Triển khai giới hạn tốc độ và backoff theo cấp số nhân trong các hàng đợi công việc của bộ điều khiển để giảm thiểu rủi ro này.

Kết luận

Kubernetes Custom Resource Definitions biến một công cụ điều phối mạnh mẽ thành một nền tảng có khả năng mở rộng vô hạn. Bằng cách nắm vững CRD, mô hình Operator, Admission Webhooks và quản lý phiên bản API, các nhóm kỹ thuật nền tảng có thể trừu tượng hóa cơ sở hạ tầng phức tạp, dành riêng cho miền thành các API khai báo.

Điều này trao quyền cho các nhà phát triển với khả năng tự phục vụ, cho phép họ cung cấp cơ sở dữ liệu, hàng đợi tin nhắn và các hệ thống phân tán phức tạp bằng cách sử dụng chính quy trình làm việc kubectl mà họ sử dụng cho các Pod cơ bản. Kết quả là một hệ sinh thái đám mây gốc thống nhất, mạnh mẽ và tự động hóa cao, mở rộng tuyến tính với sự phức tạp của tổ chức.

Bạn cũng có thể thích

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement