

Mục tiêu của bài hướng dẫn là xây dựng Operator chịu trách nhiệm duy trì trạng thái mong muốn cho các tài nguyên tên là “memcached” thông qua các nhiệm vụ cụ thể:
Link source code tham khảo: source code https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/getting-started/testdata/project
Trước khi bắt đầu xây dựng Kubernetes Operator, bạn cần chuẩn bị đầy đủ các công cụ hỗ trợ. Dưới đây là danh sách các yêu cầu phần mềm và các bước cài đặt cụ thể
Trước khi bắt đầu, bạn cần chuẩn bị môi trường:
Kubebuilder là một framework giúp chúng ta xây dựng Kubernetes APIs một cách nhanh chóng. Để cài đặt bản binary trên Linux hoặc macOS, bạn thực hiện các lệnh sau:
Lưu ý: Lệnh dưới đây sẽ tự động nhận diện hệ điều hành và kiến trúc chip của bạn
curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)
chmod +x kubebuilder && mv kubebuilder /usr/local/bin/Cuối cùng, hãy xác nhận xem mọi thứ đã sẵn sàng chưa bằng cách kiểm tra phiên bản:
kubebuilder version
Nếu thông tin phiên bản hiện ra, bạn đã cài đặt thành công và sẵn sàng để bắt đầu khởi tạo dự án.
Sau khi đã chuẩn bị đầy đủ công cụ, chúng ta sẽ tiến hành khởi tạo cấu trúc thư mục cho dự án Operator bằng Kubebuilder.
Đầu tiên, hãy tạo một thư mục mới cho dự án và thực hiện lệnh init:
mkdir memcached-operator
cd memcached-operator
kubebuilder init --domain example.com --repo github.com/example/memcached-operator
Ý nghĩa:
Sau khi lệnh hoàn tất, Kubebuilder sẽ tự động tạo bộ khung cho dự án. Các thành phần then chốt cần lưu ý bao gồm:

Những thành phần chính:
Sau khi đã có bộ khung dự án, bước tiếp theo là xác định thực thể mà Operator sẽ quản lý. Chúng ta sẽ tạo một API mới với định danh Group/Version là cache/v1alpha1 và loại tài nguyên (Kind) là Memcached.
Chạy lệnh sau trong thư mục gốc của dự án để tạo một API mới (Group/Version) là cache/v1alpha1 và một loại tài nguyên mới (Kind/CRD) tên là Memcached:
kubebuilder create api --group cache --version v1alpha1 --kind MemcachedTrong quá trình thực hiện, Kubebuilder sẽ đưa ra hai câu hỏi xác nhận tạo tài template:
Sau khi lệnh hoàn tất, bạn sẽ thấy các thành phần quan trọng sau được tự động sinh ra trong dự án:
Nhóm file định nghĩa API
Logic điều khiển (Controller)
Cấu hình tài nguyên (CRD YAML)
Sau khi tạo file, chúng ta cần tùy chỉnh cấu trúc dữ liệu trong file api/v1alpha1/memcached_types.go. Đây là nơi bạn xác định "ngôn ngữ" mà người dùng sẽ sử dụng để giao tiếp với Operator của bạn.
Trường Spec đại diện cho trạng thái mong muốn (Desired State) mà người dùng khai báo. Chúng ta sẽ thêm trường Size để xác định số lượng bản sao (replicas) của Memcache
type MemcachedSpec struct {
// +kubebuilder:validation:Minimum=1
Size int32 `json:"size,omitempty"`
}Trường Status dùng để phản ánh trạng thái quan sát được (Observed State). Trong môi trường Cloud hoặc môi trường thực tế của đối tượng, việc theo dõi các điều kiện (Conditions) là tiêu chuẩn để biết tài nguyên đang chạy tốt, đang khởi tạo hay gặp lỗi.
// MemcachedStatus định nghĩa trạng thái hiện tại của tài nguyên Memcached
type MemcachedStatus struct {
// Conditions đại diện cho các quan sát về trạng thái hiện tại của Memcached
// +listType=map
// +listMapKey=type
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
}
Tại sao nên sử dụng Conditions?
Lưu ý :
Sau khi chỉnh sửa file _types.go, đừng quên chạy lệnh sau để cập nhật lại mã nguồn tự động và các file manifest, chi tiết sẽ được trình bình trong bước sau:
make generate
make manifestsMột trong những ưu điểm lớn nhất của Kubebuilder là khả năng tự động sinh mã (Code Generation). Sau khi bạn thay đổi cấu trúc Spec hoặc Status trong file _types.go, chúng ta cần thực thi các lệnh sau để cập nhật toàn bộ dự án.
Để thực hiện, chạy câu lệnh sau trên terminal:
make generate
make manifests
Việc hiểu rõ cơ chế phía sau sẽ giúp bạn xử lý lỗi (debug) tốt hơn khi dự án trở nên phức tạp:
Sau khi thực hiện thành công, tài nguyên Custom Resource Definition (CRD) của bạn sẽ sở hữu các tính năng cao cấp:
Sau khi đã có bộ khung và API, chúng ta sẽ bước vào phần "linh hồn" của Operator: Reconcile Loop. Đây là vòng lặp vô tận nơi Operator liên tục so sánh trạng thái người dùng mong muốn (Desired State) và trạng thái thực tế trên Cluster (Actual State) để thực hiện các hành động điều chỉnh.
Trước khi đi vào chi tiết mã nguồn, chúng ta cần hiểu về Manager – thành phần cốt lõi điều khiển toàn bộ Operator. Kubebuilder sử dụng thư viện controller-runtime để khởi tạo một Manager với 3 nhiệm vụ chính:
Khi người dùng tạo một Custom Resource (CR) Memcached, một chuỗi sự kiện sẽ diễn ra trong hệ thống:
Triển khai code cho Reconcile tại file:
internal/controller/memcached_controller.goĐầu tiên, Operator cần kiểm tra xem Deployment tương ứng đã tồn tại trên Cluster hay chưa.
// Check if the deployment already exists, if not create a new one
found := &appsv1.Deployment{}
err = r.Get(ctx, types.NamespacedName{Name: memcached.Name, Namespace: memcached.Namespace}, found)
if err != nil && apierrors.IsNotFound(err) {
// Define a new deployment
dep := r.deploymentForMemcached()
// Create the Deployment on the cluster
if err = r.Create(ctx, dep); err != nil {
log.Error(err, "Failed to create new Deployment",
"Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
return ctrl.Result{}, err
}
...
}
Nếu Deployment đã tồn tại, nhiệm vụ của Operator là đảm bảo các thông số kỹ thuật (như size) phải luôn khớp với những gì người dùng khai báo trong Spec.
...
size := memcached.Spec.Size
if *found.Spec.Replicas != size {
found.Spec.Replicas = &size
if err = r.Update(ctx, found); err != nil {
log.Error(err, "Failed to update Deployment",
"Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name)
return ctrl.Result{}, err
}
...Lưu ý:
Khi xây dựng hàm reconcile cần đảm bảo và lưu ý:
Để hàm Reconcile trên hoạt động, chúng ta cần một hàm bổ trợ để định nghĩa cấu hình Deployment cho Memcached. Đây là nơi bạn thiết lập Image, Port và các cấu hình hệ thống:
func (r *MemcachedReconciler) deploymentForMemcached(m *cachev1alpha1.Memcached) *appsv1.Deployment {
labels := labelsForMemcached(m.Name)
replicas := m.Spec.Size
dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name,
Namespace: m.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: "memcached:1.4.36-alpine",
Name: "memcached",
Ports: []corev1.ContainerPort{{
ContainerPort: 11211,
Name: "memcached",
}},
}},
},
},
},
}
// Thiết lập quyền sở hữu (OwnerReference) để khi xóa Memcached CR, Deployment cũng bị xóa theo
ctrl.SetControllerReference(m, dep, r.Scheme)
return dep
}
Để Operator có thể thay mặt người dùng thao tác với các tài nguyên trên Cluster (như tạo Deployment hay theo dõi Pod), chúng ta cần cấp quyền thông qua cơ chế RBAC (Role-Based Access Control).
Thay vì viết các file YAML phức tạp một cách thủ công, Kubebuilder cho phép chúng ta định nghĩa quyền hạn ngay trong mã nguồn Go bằng các Markers (chú thích đặc biệt). Các markers này nằm ngay phía trên hàm Reconcile trong file internal/controller/memcached_controller.go.
//+kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
Vì Operator của chúng ta cần quản lý cả Custom Resource lẫn các tài nguyên chuẩn của Kubernetes, bạn cần bổ sung các dòng sau:
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/finalizers,verbs=update
// +kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watchSau khi thêm các markers, hãy chạy lại lệnh sau để Kubebuilder tự động cập nhật cấu hình:
make manifestsKết quả: Toàn bộ các quyền hạn trên sẽ được tổng hợp vào file config/rbac/role.yaml. File này đóng vai trò là "chứng minh thư" về quyền hạn của Operator khi được triển khai lên cụm Kubernetes.
Tại sao bước này lại quan trọng?
Sau khi đã hoàn tất logic và cấu hình RBAC, đây là lúc chúng ta đưa Operator vào vận hành thực tế trên Kubernetes Cluster.
Trước khi Operator có thể hiểu được tài nguyên Memcached, bạn cần đăng ký định nghĩa của nó với Cluster.
Lưu ý: Đảm bảo kubectl của bạn đang trỏ đúng vào context của Cluster (Kind, Minikube hoặc Cloud Cluster).
make install
Lệnh này sẽ lấy file manifest từ config/crd/bases và áp dụng lên Cluster. Bây giờ, Cluster đã sẵn sàng để tiếp nhận các đối tượng loại Memcached.
Bạn có hai lựa chọn để chạy Operator tùy theo mục đích kiểm thử:
Nếu bạn đang trong quá trình phát triển và muốn xem log nhanh, hãy dùng lệnh:
make run
Lệnh này sẽ chạy Operator như một tiến trình Go bình thường trên máy bạn nhưng sử dụng quyền hạn từ kubeconfig để tương tác với Cluster từ xa.
Để chạy Operator như một Deployment thực thụ bên trong Kubernetes, bạn cần build image và push lên registry (Docker Hub, GCR, v.v.):
# Build và Push Image
make docker-build docker-push IMG=<your-registry>/memcached-operator:v1
# Triển khai Operator lên Cluster
make deploy IMG=<your-registry>/memcached-operator:v1Lệnh deploy sẽ tự động khởi tạo:
Chúng ta sẽ tạo một file manifest mẫu tại config/samples/cache_v1alpha1_memcached.yaml:
config/samples/cache_v1alpha1_memcached.yaml
Thực thi lệnh apply:
kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
Kiểm tra trạng thái:
Hãy quan sát cách Operator tự động tạo ra Deployment và các Pod tương ứng:
kubectl get memcached,deploymentDeployment sẽ được tạo tương ứng.

Sau khi hoàn thành các bước hướng dẫn, bạn đã nắm vững quy trình cơ bản để xây dựng một Kubernetes Operator bằng Kubebuilder, bao gồm:
Các chủ đề nâng cao cần tìm hiểu
Để đưa Operator vào môi trường Production với độ tin cậy cao, bạn có thể tiếp tục nghiên cứu các tính năng nâng cao trong tài liệu The Kubebuilder Book (https://book.kubebuilder.io/)
