前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Kubernetes Operator 开发教程

Kubernetes Operator 开发教程

原创
作者头像
rxg456
修改2025-03-05 18:37:22
修改2025-03-05 18:37:22
1430
举报

一. Operator 概述

Kubernetes Operator 是一种封装、部署和管理复杂有状态应用的高级方法。它通过扩展 Kubernetes API 和控制器模式,将运维领域的知识(如备份、扩缩容、故障恢复)编码到自定义逻辑中,使应用可以像管理原生 Kubernetes 资源(如 Deployment、Service)一样自动化运行。

Operator 的核心思想:通过声明式 API + 控制循环(Control Loop)实现应用的全生命周期管理

二. 什么是 Operator?

Operator = 自定义资源(Custom Resource, CR) + 自定义控制器(Custom Controller)

自定义资源(CR)

  • 定义一种新的 Kubernetes 资源类型(例如 MySQLCluster),描述应用的期望状态。
  • 示例:通过 YAML 声明一个 MySQL 集群的配置:
代码语言:yaml
复制
  apiVersion: mysql.example.com/v1
  kind: MySQLCluster
  metadata:
    name: my-mysql
  spec:
    replicas: 3
    storageSize: 100Gi

自定义控制器(Controller)

  • 持续监控 CR 的实际状态,并驱动系统向期望状态调整(如创建 Pod、配置副本)。
  • 实现原理:监听 Kubernetes API 的事件(Create/Update/Delete),触发 Reconcile 调谐逻辑。

三. Operator 开发模式的好处

  1. 自动化复杂操作
    • 自动处理备份、恢复、升级等运维任务(例如:Etcd Operator 自动处理节点故障恢复)。
  2. 封装领域知识
    • 将运维经验编码到代码中,降低对人工操作的依赖。
  3. 统一管理界面
    • 通过 kubectl 和 Kubernetes API 管理应用,与原生资源无缝集成。
  4. 减少人为错误
    • 通过声明式配置和自动化控制,避免手动操作的失误。

四. 构建 Operator 的两种方式

1. 使用 Kubebuilder

Kubebuilder 是由 Kubernetes SIG 维护的 Operator 框架,适合熟悉 Kubernetes API 结构的开发者。

开发流程

步骤 1:安装 Kubebuilder
代码语言:bash
复制
# 下载二进制文件(以 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/
步骤 2:初始化项目
代码语言:bash
复制
mkdir my-operator && cd my-operator && go mod init github.com/rxg456/my-operator
kubebuilder init --domain example.com
步骤 3:创建 API(定义 CRD)
代码语言:bash
复制
kubebuilder create api --group webapp --version v1 --kind Guestbook

生成的 CRD 结构定义文件位于 api/v1/guestbook_types.go,需在此文件中定义资源的 SpecStatus 字段。例如:

代码语言:go
复制
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 示例:

代码语言:yaml
复制
apiVersion: webapp.example.com/v1
kind: Guestbook
metadata:
  name: my-guestbook
spec:
  replicas: 3
  image: nginx:latest
  port: 8080
步骤 4:实现业务逻辑

controllers/guestbook_controller.goReconcile 方法中编写调谐逻辑,使用 controllerutil 工具简化资源管理:

代码语言:go
复制
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
}
步骤 5:部署到本地集群测试
代码语言:bash
复制
make manifests  # 生成 CRD YAML
make install    # 部署 CRD 本地集群
make run        # 本地运行 Operator
步骤6:本地启动测试
代码语言:yaml
复制
apiVersion: webapp.example.com/v1
kind: Guestbook
metadata:
  name: my-guestbook
spec:
  replicas: 3
  image: nginx:latest
  port: 8080
步骤 7:生产环境部署

本地开发测试完成后,需将 Operator 打包为容器镜像并部署到集群:

  1. 构建镜像 修改 Makefile 中的 IMG 变量,指定镜像仓库地址:
代码语言:makefile
复制
IMG = your-registry.example.com/my-operator:v1

执行构建并推送镜像:

代码语言:bash
复制
make docker-build docker-push
  1. 生成Operator Deploy文件
代码语言:bash
复制
make build-installer
  1. 部署到集群

dist/install.yaml即可在任何k8s集群安装

代码语言:bash
复制
kubectl apply -f dist/install.yaml
kubebuilder目录结构

/cmd

  • Operator 主程序入口,执行 kubebuilder init 时生成。

/api

  • API 资源定义,用户需要修改 *_types.go 文件实现自定义 CRD,其他文件自动生成。
  • 执行 kubebuilder create api 时生成。

/internal/controller

  • 控制器,用户需要修改 *_controller.go 文件实现自定义 Reconcile 逻辑。
  • 执行 kubebuilder create api 时生成。

/config

  • CRD 相关对象,自动生成,包含:
    • /config/crd
    • /config/rbac
    • /config/sample

Makefile

  • 自动生成,包含构建、测试、运行和部署控制器的规则

2. 使用 Operator SDK

Operator SDK 是 Red Hat 维护的工具,支持 Go/Ansible/Helm 多种开发方式(推荐使用 Go)。

步骤 1:安装 Operator SDK
代码语言:bash
复制
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/
步骤 2:初始化项目
代码语言:bash
复制
mkdir my-operator && cd my-operator && go mod init github.com/rxg456/my-operator
operator-sdk init --domain example.com
步骤 3:创建 API(定义 CRD)
代码语言:bash
复制
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

代码语言: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:

代码语言:bash
复制
make manifests
步骤4:实现业务逻辑

修改 controllers/guestbook_controller.go

代码语言: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
}
步骤5:测试 Operator

本地运行

代码语言:bash
复制
make install
make run

测试 CRD

创建 config/samples/webapp_v1_guestbook.yaml

代码语言:yaml
复制
apiVersion: webapp.example.com/v1
kind: Guestbook
metadata:
  name: my-guestbook
spec:
  replicas: 3
  image: nginx:latest
  port: 8080
代码语言:bash
复制
kubectl apply -f config/samples/webapp_v1_guestbook.yaml
步骤6:部署 Operator

修改 Makefile

代码语言:makefile
复制
IMG=your-registry.example.com/my-operator:v1

构建并推送镜像:

代码语言:bash
复制
make docker-build docker-push
步骤7:生成 Install YAML
代码语言:bash
复制
make build-installer
步骤8:应用
代码语言:bash
复制
kubectl apply -f dist/install.yaml

3. CRD 版本兼容性

CRD(Custom Resource Definitions)apiVersion 可能受 Kubernetes 版本影响:

  • 旧版本使用 apiextensions.k8s.io/v1beta1(Kubernetes 1.15 及更早)
  • Kubernetes 1.16+ 之后推荐使用 apiextensions.k8s.io/v1
  • 1.22+ 移除apiextensions.k8s.io/v1beta1

检查 install.yaml CRD 版本

代码语言:yaml
复制
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition

如果 install.yaml 里有 apiextensions.k8s.io/v1beta1,则 不兼容 Kubernetes 1.22+,需要手动升级。

4. API 资源的版本

Kubernetes 每个版本 都会废弃或移除旧 API,如果 install.yaml 里使用了废弃 API,可能无法在较新版本上运行。

常见 API 变更

API 资源

旧版本(已废弃)

新版本(推荐使用)

移除版本

Ingress

extensions/v1beta1

networking.k8s.io/v1

1.22+

Deployment

apps/v1beta1 / extensions/v1beta1

apps/v1

1.16+

RBAC

rbac.authorization.k8s.io/v1beta1

rbac.authorization.k8s.io/v1

1.17+

检查 install.yaml API 版本

代码语言:bash
复制
kubectl apply --dry-run=client -f dist/install.yaml

如果输出 警告报错,需要升级 install.yaml 中的 API 版本。

五. Kubebuilder vs Operator SDK

特性

Kubebuilder

Operator SDK

维护方

Kubernetes SIG

Red Hat

语言支持

Go

Go/Ansible/Helm

项目结构

更贴近 Kubernetes API 风格

提供更多脚手架工具

适用场景

需要深度定制 Kubernetes 功能

快速构建标准化 Operator

六. 总结

  1. 选择工具:Kubebuilder 适合熟悉 K8s API 的开发者,Operator SDK 提供更多开箱即用功能。
  2. 核心思想:Operator = 声明式 API + 控制循环,通过自动化提升运维效率。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. Operator 概述
  • 二. 什么是 Operator?
    • 自定义资源(CR)
    • 自定义控制器(Controller)
  • 三. Operator 开发模式的好处
  • 四. 构建 Operator 的两种方式
    • 1. 使用 Kubebuilder
      • 步骤 1:安装 Kubebuilder
      • 步骤 2:初始化项目
      • 步骤 3:创建 API(定义 CRD)
      • 步骤 4:实现业务逻辑
      • 步骤 5:部署到本地集群测试
      • 步骤6:本地启动测试
      • 步骤 7:生产环境部署
      • kubebuilder目录结构
    • 2. 使用 Operator SDK
      • 步骤 1:安装 Operator SDK
      • 步骤 2:初始化项目
      • 步骤 3:创建 API(定义 CRD)
      • 步骤4:实现业务逻辑
      • 步骤5:测试 Operator
      • 步骤6:部署 Operator
      • 步骤7:生成 Install YAML
      • 步骤8:应用
    • 3. CRD 版本兼容性
    • 4. API 资源的版本
  • 五. Kubebuilder vs Operator SDK
  • 六. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档