Chuyển đến nội dung chính

BÀI 34: OPERATORS VÀ CUSTOM RESOURCES

Operator pattern: CRDs, Custom Controllers, Operator SDK, Kubebuilder. Common operators: Prometheus Operator, CloudNativePG (PostgreSQL), Strimzi (Kafka). Viết Operator đơn giản với Kubebuilder.

🔒 DevSecOps — Bài 34 BÀI 34: OPERATORS VÀ CUSTOM RESOURCES

KUBERNETES: TỪ CƠ BẢN ĐẾN NÂNG CAO

Module 8: Helm, Operators & GitOps

xdev.asia

🎯 Mục tiêu bài học

Hiểu Operator pattern, cách dùng CRDs để mở rộng Kubernetes API, và cách các operators phổ biến (Prometheus, CloudNativePG, Strimzi) giúp quản lý stateful applications.

1. Operator Pattern

Operators encode operational knowledge của một application vào Kubernetes controller. Thay vì admin thực hiện manual steps (backup, failover, scaling), Operator tự động hóa chúng.

Ví dụ: Không cần biết cách manually failover PostgreSQL primary — CloudNativePG Operator tự detect primary down và promote replica trong vài giây.

Operator = CRD (custom resource type) + Custom Controller (watches và acts)

2. Custom Resource Definitions (CRDs)

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.mycompany.io
spec:
  group: mycompany.io
  names:
    kind: Database
    plural: databases
    singular: database
    shortNames: ["db"]
  scope: Namespaced
  versions:
  - name: v1
    served: true    # API server phục vụ version này
    storage: true   # etcd lưu ở version này
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            required: ["engine", "size"]
            properties:
              engine:
                type: string
                enum: ["postgres", "mysql"]
              size:
                type: string
              replicas:
                type: integer
                minimum: 1
                maximum: 5
          status:
            type: object
            properties:
              phase:
                type: string
              connectionString:
                type: string
    subresources:
      status: {}   # enable status subresource
    additionalPrinterColumns:
    - name: Engine
      type: string
      jsonPath: .spec.engine
    - name: Size
      type: string
      jsonPath: .spec.size
    - name: Phase
      type: string
      jsonPath: .status.phase
# Sau khi apply CRD, có thể tạo custom resources
cat <<EOF | kubectl apply -f -
apiVersion: mycompany.io/v1
kind: Database
metadata:
  name: my-postgres
  namespace: production
spec:
  engine: postgres
  size: medium
  replicas: 3
EOF

kubectl get databases -n production kubectl get db -n production # dùng shortName

3. Controller Loop

Custom Controller liên tục watch resources và reconcile về desired state:

for {
  // Lấy desired state từ K8s API
  desired = getDatabase("my-postgres")

// Lấy actual state từ cluster actual = getActualDatabaseState()

// Tính sự khác biệt diff = compare(desired, actual)

// Act để reconcile if diff { applyChanges(diff) }

// Cập nhật status updateStatus(desired, actual.phase)

sleep(reconcileInterval) }

4. Kubebuilder — Build Operators

# Cài Kubebuilder
curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)
chmod +x kubebuilder && mv kubebuilder /usr/local/bin/

Tạo project mới

mkdir database-operator && cd database-operator kubebuilder init --domain mycompany.io --repo github.com/mycompany/database-operator

Tạo API (CRD + Controller)

kubebuilder create api --group mycompany --version v1 --kind Database

Project structure:

api/v1/database_types.go ← CRD schema

controllers/database_controller.go ← Reconcile loop

config/ ← K8s manifests

// controllers/database_controller.go
func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    log := log.FromContext(ctx)

    // Lấy Database resource
    var database mycompanyv1.Database
    if err := r.Get(ctx, req.NamespacedName, &database); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // Tạo StatefulSet nếu chưa tồn tại
    statefulSet := &appsv1.StatefulSet{}
    err := r.Get(ctx, types.NamespacedName{
        Name:      database.Name,
        Namespace: database.Namespace,
    }, statefulSet)

    if errors.IsNotFound(err) {
        // Tạo StatefulSet
        newSS := r.constructStatefulSet(&database)
        r.Create(ctx, newSS)
        log.Info("Created StatefulSet", "name", newSS.Name)
    }

    // Cập nhật status
    database.Status.Phase = "Running"
    r.Status().Update(ctx, &database)

    return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}

5. Common Operators — 2026

5.1 Prometheus Operator

# Quản lý Prometheus cluster bằng CRDs
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: main
  namespace: monitoring
spec:
  replicas: 2
  retention: 7d
  serviceMonitorSelector: {}   # watch tất cả ServiceMonitors
  resources:
    requests:
      memory: 512Mi

5.2 CloudNativePG — PostgreSQL (CNCF Graduated)

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: my-postgres
  namespace: production
spec:
  instances: 3    # 1 primary + 2 replicas
  primaryUpdateStrategy: unsupervised  # auto failover
  storage:
    size: 10Gi
    storageClass: fast-ssd
  postgresql:
    parameters:
      max_connections: "200"
      shared_buffers: "256MB"
  backup:
    retentionPolicy: "30d"
    barmanObjectStore:
      destinationPath: s3://my-bucket/postgres/
      s3Credentials:
        accessKeyId:
          name: aws-creds
          key: ACCESS_KEY_ID
# CloudNativePG: automatic primary/replica management
kubectl get clusters -n production
kubectl get pods -n production -l cnpg.io/cluster=my-postgres
# my-postgres-1 → primary
# my-postgres-2 → replica
# my-postgres-3 → replica

Failover: xóa primary → operator tự promote replica

kubectl delete pod my-postgres-1 -n production

→ my-postgres-2 được promote thành primary trong ~5s

5.3 Strimzi — Apache Kafka

apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
  name: my-kafka
  namespace: messaging
spec:
  kafka:
    replicas: 3
    version: 3.9.0
    config:
      auto.create.topics.enable: "false"
    storage:
      type: persistent-claim
      size: 50Gi
  zookeeper:
    replicas: 3
    storage:
      type: persistent-claim
      size: 10Gi
  entityOperator:
    topicOperator: {}    # quản lý KafkaTopic CRDs
    userOperator: {}     # quản lý KafkaUser CRDs

5.4 cert-manager

# Tự động cấp và renew TLS certificates
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-tls
  namespace: production
spec:
  secretName: api-tls-secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - api.example.com
  - *.api.example.com

6. Operator Hub và OLM

# Operator Lifecycle Manager (OLM) quản lý lifecycle của operators
# Tìm operators tại: https://operatorhub.io/

Cài OLM

curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/latest/download/install.sh | bash -s latest

Cài operator từ OperatorHub

kubectl create -f https://operatorhub.io/install/postgresql.yaml

Tóm tắt

  • Operator = CRD + Custom Controller để automate Day-2 operations
  • CRD mở rộng Kubernetes API với custom resource types
  • Kubebuilder: scaffold và build operators với Go
  • CloudNativePG: best PostgreSQL operator (CNCF graduated, auto failover)
  • Strimzi: Kafka lifecycle management trên Kubernetes
  • cert-manager: TLS certificate automation