Kubernetes Operator 是一种封装、部署和管理复杂有状态应用的高级方法。它通过扩展 Kubernetes API 和控制器模式,将运维领域的知识(如备份、扩缩容、故障恢复)编码到自定义逻辑中,使应用可以像管理原生 Kubernetes 资源(如 Deployment、Service)一样自动化运行。
Operator 的核心思想:通过声明式 API + 控制循环(Control Loop)实现应用的全生命周期管理。
Operator = 自定义资源(Custom Resource, CR) + 自定义控制器(Custom Controller)
MySQLCluster
),描述应用的期望状态。 apiVersion: mysql.example.com/v1
kind: MySQLCluster
metadata:
name: my-mysql
spec:
replicas: 3
storageSize: 100Gi
Reconcile
调谐逻辑。kubectl
和 Kubernetes API 管理应用,与原生资源无缝集成。Kubebuilder 是由 Kubernetes SIG 维护的 Operator 框架,适合熟悉 Kubernetes API 结构的开发者。
开发流程
# 下载二进制文件(以 Linux 为例)
curl -L -o kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)"
chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
mkdir my-operator && cd my-operator && go mod init github.com/rxg456/my-operator
kubebuilder init --domain example.com
kubebuilder create api --group webapp --version v1 --kind Guestbook
生成的 CRD 结构定义文件位于 api/v1/guestbook_types.go
,需在此文件中定义资源的 Spec
和 Status
字段。例如:
type GuestbookSpec struct {
// 定义用户期望状态(Operator YAML 中填写的字段)
Replicas int32 `json:"replicas"` // 对应 YAML 的 `spec.replicas`
Image string `json:"image"` // 对应 YAML 的 `spec.image`
Port int32 `json:"port"` // 应用监听的端口
}
type GuestbookStatus struct {
// 定义实际状态(由 Operator 控制器更新)
AvailableReplicas int32 `json:"availableReplicas"` // 实际运行的副本数
Conditions []metav1.Condition `json:"conditions,omitempty"`
}
对应的 YAML 示例:
apiVersion: webapp.example.com/v1
kind: Guestbook
metadata:
name: my-guestbook
spec:
replicas: 3
image: nginx:latest
port: 8080
在 controllers/guestbook_controller.go
的 Reconcile
方法中编写调谐逻辑,使用 controllerutil
工具简化资源管理:
func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
// 获取 CR 实例
guestbook := webappv1.Guestbook{}
if err := r.Get(ctx, req.NamespacedName, &guestbook); err != nil {
if apierrors.IsNotFound(err) {
// 资源已被物理删除,无需处理
return ctrl.Result{}, nil
}
return ctrl.Result{}, err
}
labels := map[string]string{
"app": guestbook.Name,
}
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: guestbook.Name,
Namespace: guestbook.Namespace,
},
}
if err := controllerutil.SetControllerReference(&guestbook, deployment, r.Scheme); err != nil {
return ctrl.Result{}, err
}
// 关键操作 :CreateOrUpdate
// 如果 Deployment 不存在则创建,存在则更新到最新状态
result, err := controllerutil.CreateOrUpdate(ctx, r.Client, deployment, func() error {
// 示例:创建或更新一个 Deployment
// 在此函数中更新 Deployment 的期望状态
deployment.Spec = appsv1.DeploymentSpec{
Replicas: &guestbook.Spec.Replicas,
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: guestbook.Name,
Image: guestbook.Spec.Image,
Ports: []corev1.ContainerPort{
{
ContainerPort: guestbook.Spec.Port,
},
},
},
},
},
},
}
// 关键操作:设置 OwnerReference
// 确保删除 Guestbook CR 时,自动清理关联的 Deployment
if err := controllerutil.SetControllerReference(&guestbook, deployment, r.Scheme); err != nil {
return err
}
return nil
})
if err != nil {
logger.Error(err, "Failed to create or update Deployment")
guestbook.Status.AvailableReplicas = 0
return ctrl.Result{}, err
}
logger.Info("Deployment操作结果", "result", result)
return ctrl.Result{}, nil
}
make manifests # 生成 CRD YAML
make install # 部署 CRD 本地集群
make run # 本地运行 Operator
apiVersion: webapp.example.com/v1
kind: Guestbook
metadata:
name: my-guestbook
spec:
replicas: 3
image: nginx:latest
port: 8080
本地开发测试完成后,需将 Operator 打包为容器镜像并部署到集群:
Makefile
中的 IMG
变量,指定镜像仓库地址:IMG = your-registry.example.com/my-operator:v1
执行构建并推送镜像:
make docker-build docker-push
make build-installer
dist/install.yaml即可在任何k8s集群安装
kubectl apply -f dist/install.yaml
/cmd
kubebuilder init
时生成。/api
*_types.go
文件实现自定义 CRD,其他文件自动生成。kubebuilder create api
时生成。/internal/controller
*_controller.go
文件实现自定义 Reconcile 逻辑。kubebuilder create api
时生成。/config
/config/crd
/config/rbac
/config/sample
Makefile
Operator SDK 是 Red Hat 维护的工具,支持 Go/Ansible/Helm 多种开发方式(推荐使用 Go)。
export ARCH=$(uname -m)
export OS=$(uname | awk '{print tolower($0)}')
curl -LO "https://github.com/operator-framework/operator-sdk/releases/latest/download/operator-sdk_${OS}_${ARCH}"
mv operator-sdk_${OS}_${ARCH} operator-sdk
chmod +x operator-sdk && mv operator-sdk /usr/local/bin/
mkdir my-operator && cd my-operator && go mod init github.com/rxg456/my-operator
operator-sdk init --domain example.com
operator-sdk create api --group webapp --version v1 --kind Guestbook --resource --controller
这将生成:
api/v1/guestbook_types.go
→ 自定义 CRD 结构controllers/guestbook_controller.go
→ 控制器逻辑修改 api/v1/guestbook_types.go
:
type GuestbookSpec struct {
Replicas int32 `json:"replicas"`
Image string `json:"image"`
Port int32 `json:"port"`
}
type GuestbookStatus struct {
AvailableReplicas int32 `json:"availableReplicas"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}
生成 CRD:
make manifests
修改 controllers/guestbook_controller.go
:
func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
guestbook := webappv1.Guestbook{}
if err := r.Get(ctx, req.NamespacedName, &guestbook); err != nil {
if apierrors.IsNotFound(err) {
return ctrl.Result{}, nil
}
return ctrl.Result{}, err
}
labels := map[string]string{
"app": guestbook.Name,
}
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: guestbook.Name,
Namespace: guestbook.Namespace,
},
}
if err := controllerutil.SetControllerReference(&guestbook, deployment, r.Scheme); err != nil {
return ctrl.Result{}, err
}
result, err := controllerutil.CreateOrUpdate(ctx, r.Client, deployment, func() error {
deployment.Spec = appsv1.DeploymentSpec{
Replicas: &guestbook.Spec.Replicas,
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: guestbook.Name,
Image: guestbook.Spec.Image,
Ports: []corev1.ContainerPort{
{
ContainerPort: guestbook.Spec.Port,
},
},
},
},
},
},
}
if err := controllerutil.SetControllerReference(&guestbook, deployment, r.Scheme); err != nil {
return err
}
return nil
})
if err != nil {
logger.Error(err, "Failed to create or update Deployment")
guestbook.Status.AvailableReplicas = 0
return ctrl.Result{}, err
}
logger.Info("Deployment操作结果", "result", result)
return ctrl.Result{}, nil
}
本地运行
make install
make run
测试 CRD
创建 config/samples/webapp_v1_guestbook.yaml
:
apiVersion: webapp.example.com/v1
kind: Guestbook
metadata:
name: my-guestbook
spec:
replicas: 3
image: nginx:latest
port: 8080
kubectl apply -f config/samples/webapp_v1_guestbook.yaml
修改 Makefile
:
IMG=your-registry.example.com/my-operator:v1
构建并推送镜像:
make docker-build docker-push
make build-installer
kubectl apply -f dist/install.yaml
CRD(Custom Resource Definitions) 的 apiVersion
可能受 Kubernetes 版本影响:
apiextensions.k8s.io/v1beta1
(Kubernetes 1.15 及更早)apiextensions.k8s.io/v1
apiextensions.k8s.io/v1beta1
检查 install.yaml
CRD 版本
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
如果 install.yaml
里有 apiextensions.k8s.io/v1beta1
,则 不兼容 Kubernetes 1.22+,需要手动升级。
Kubernetes 每个版本 都会废弃或移除旧 API,如果 install.yaml
里使用了废弃 API,可能无法在较新版本上运行。
常见 API 变更:
API 资源 | 旧版本(已废弃) | 新版本(推荐使用) | 移除版本 |
---|---|---|---|
|
|
| 1.22+ |
|
|
| 1.16+ |
|
|
| 1.17+ |
检查 install.yaml
API 版本
kubectl apply --dry-run=client -f dist/install.yaml
如果输出 警告 或 报错,需要升级 install.yaml
中的 API 版本。
特性 | Kubebuilder | Operator SDK |
---|---|---|
维护方 | Kubernetes SIG | Red Hat |
语言支持 | Go | Go/Ansible/Helm |
项目结构 | 更贴近 Kubernetes API 风格 | 提供更多脚手架工具 |
适用场景 | 需要深度定制 Kubernetes 功能 | 快速构建标准化 Operator |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。