初识Kubernetes Operator
Operator模式是Kubernetes声明式API和控制器模式的强大延伸。对于运维复杂的有状态应用来说,它是一个极具价值的工具。从使用开始:先熟练使用OperatorHub上的成熟Operator,理解其行为。选择合适框架:当需要自研时,(或功能相似的)是你的首选。核心是调和循环:编写Operator的关键在于理解并实现好Reconcile函数,不断对比"期望状态"和"实际状态",并驱动系统向
Kubernetes Operator是一个进阶的云原生工具,它能将复杂应用的运维知识编码成可重复使用的自动化程序。虽然概念听起来有些复杂,但别担心,下面我会为你拆解它的核心思想,并提供一个从使用到编写的详细指南。
一、🔍 理解Kubernetes Operator
简单来说,你可以把Operator看作是你集群中一位不知疲倦的、专门负责管理某个特定应用(例如MySQL、Redis等)的AI运维专家。
这位"专家"通过以下两个核心部件工作:
- 自定义资源(CRD):这是你为这个"专家"专门设计的工作指令单。它扩展了Kubernetes的API,让你能够定义和管理原生Kubernetes不支持的资源类型。比如,你可以创建一个
MysqlCluster类型的资源。 - 自定义控制器:这是那位"AI运维专家"本身。它会持续不断地监控你发出的这些"工作指令单"(CR),并根据指令单里的描述(即你期望的应用状态),去驱动整个系统达到并维持这个状态。
Operator vs. 原生控制器:你可能会问,Kubernetes本身不就有Deployment、StatefulSet等控制器吗?没错。但Operator更专业,它内嵌了特定应用领域的运维知识(比如如何安全地升级数据库,如何执行备份恢复),而原生控制器主要负责通用的、无状态的编排工作。
二、🛠️ 如何使用现成的Operator?
在考虑自己编写Operator之前,强烈建议你先熟悉如何使用社区里已有的成熟Operator。这是最快速的入门方式。
-
寻找Operator:你可以在 OperatorHub.io 上找到大量的、由社区维护的Operator文档。

-
安装Operator:很多Operator可以通过Operator Lifecycle Manager (OLM) 来安装,这是一个在集群内安装、管理和升级Operator的框架。操作通常很简单,在OperatorHub的网页上会有详细的安装指引。
-
使用Operator:安装好后,你就可以通过创建自定义资源(CR) 来使用它。例如,如果安装了一个Etcd Operator,你可能会创建一个如下所示的YAML文件,然后使用
kubectl apply -f命令,Operator就会自动为你部署和管理一个Etcd集群。apiVersion: "etcd.database.coreos.com/v1beta2" kind: "EtcdCluster" metadata: name: "example-etcd-cluster" spec: size: 3 # 期望的集群节点数量 version: "3.4.13"
三、👨💻 如何编写自己的Operator?
当你需要管理一个Kubernetes本身无法处理的、有状态的复杂应用时,就是考虑编写自己Operator的时候了。这里我们以Go语言和 Kubebuilder 框架为例,因为它目前是社区最主流和推荐的方式。
3.1 准备工作
我本地的k8s集群的版本是v1.23.0
-
一个Kubernetes集群(可以是Minikube、Kind等本地开发集群)。
-
安装好Go(1.13+版本)。
#1官方网站下载 https://go.dev/dl/ #本次下载的是 go1.24.9.linux-amd64.tar.gz #2 解压缩 tar -zxvf go1.24.9.linux-amd64.tar.gz -C /usr/local/ #3 配置环境变量 vim /etc/profile export GOROOT=/usr/local/go export PATH=$PATH:$GOROOT/bin #4 生效 source /etc/profile #5 验证 go version go version go1.24.9 linux/amd64 -
安装Docker。
-
安装kubectl。
-
安装Kubebuilder命令行工具。
#1 创建相关文件夹 mkdir /root/crd cd /root/crd #2 下载并添加到环境变量 curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH) chmod +x kubebuilder && sudo mv kubebuilder /usr/local/bin/ #3 部署验证 kubebuilder version Version: cmd.version{KubeBuilderVersion:"4.9.0", KubernetesVendor:"1.34.0", GitCommit:"5e331e74c7a25c8e8fc0d9d5c33c319b7268f395", BuildDate:"2025-09-22T10:53:21Z", GoOs:"linux", GoArch:"amd64"} #4 #更改GOPROXY依赖下载代理为国内的地址 go env -w GOPROXY=https://mirrors.aliyun.com/goproxy,direct
3.2 详细步骤
第一步:初始化项目
使用Kubebuilder创建一个新的Operator项目骨架。这会生成一个完整的Go模块,包含所有必要的依赖和基础配置文件。
#1 创建项目目录并进入
[root@k8s-master][~/crd]
$mkdir myopertor
[root@k8s-master][~/crd]
$cd myopertor/
#2 初始化项目
kubebuilder init --domain=mydomain.com --repo=mydomain.com/myoperator
#初始化项目的时间会稍微久一些,下面是一些日志信息
INFO Writing kustomize manifests for you to edit...
INFO Writing scaffold for you to edit...
INFO Get controller runtime
go: downloading sigs.k8s.io/controller-runtime v0.22.1
go: downloading k8s.io/apimachinery v0.34.0
go: downloading github.com/gogo/protobuf v1.3.2
go: downloading github.com/go-logr/logr v1.4.2
go: downloading k8s.io/client-go v0.34.0
go: downloading k8s.io/klog/v2 v2.130.1
go: downloading k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
go: downloading k8s.io/api v0.34.0
go: downloading sigs.k8s.io/randfill v1.0.0
go: downloading sigs.k8s.io/structured-merge-diff/v6 v6.3.0
go: downloading github.com/evanphx/json-patch/v5 v5.9.11
go: downloading gomodules.xyz/jsonpatch/v2 v2.4.0
go: downloading k8s.io/apiextensions-apiserver v0.34.0
go: downloading github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
go: downloading golang.org/x/net v0.38.0
go: downloading github.com/spf13/pflag v1.0.6
go: downloading golang.org/x/term v0.30.0
go: downloading github.com/prometheus/client_golang v1.22.0
go: downloading gopkg.in/inf.v0 v0.9.1
go: downloading sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8
go: downloading github.com/json-iterator/go v1.1.12
go: downloading go.yaml.in/yaml/v2 v2.4.2
go: downloading k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
go: downloading github.com/google/gnostic-models v0.7.0
go: downloading google.golang.org/protobuf v1.36.5
go: downloading golang.org/x/time v0.9.0
go: downloading github.com/google/btree v1.1.3
go: downloading golang.org/x/sync v0.12.0
go: downloading github.com/fxamacker/cbor/v2 v2.9.0
go: downloading golang.org/x/oauth2 v0.27.0
go: downloading golang.org/x/sys v0.31.0
go: downloading github.com/google/uuid v1.6.0
go: downloading github.com/fsnotify/fsnotify v1.9.0
go: downloading github.com/prometheus/client_model v0.6.1
go: downloading github.com/prometheus/common v0.62.0
go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
go: downloading github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee
go: downloading sigs.k8s.io/yaml v1.6.0
go: downloading go.yaml.in/yaml/v3 v3.0.4
go: downloading github.com/go-openapi/jsonreference v0.20.2
go: downloading github.com/go-openapi/swag v0.23.0
go: downloading github.com/google/go-cmp v0.7.0
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading github.com/beorn7/perks v1.0.1
go: downloading github.com/cespare/xxhash/v2 v2.3.0
go: downloading github.com/prometheus/procfs v0.15.1
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/x448/float16 v0.8.4
go: downloading golang.org/x/text v0.23.0
go: downloading github.com/go-openapi/jsonpointer v0.21.0
go: downloading github.com/mailru/easyjson v0.7.7
go: downloading gopkg.in/yaml.v3 v3.0.1
go: downloading gopkg.in/evanphx/json-patch.v4 v4.12.0
go: downloading github.com/emicklei/go-restful/v3 v3.12.2
go: downloading github.com/josharian/intern v1.0.0
go: downloading github.com/pkg/errors v0.9.1
INFO Update dependencies
go: downloading github.com/onsi/ginkgo/v2 v2.22.0
go: downloading github.com/onsi/gomega v1.36.1
go: downloading github.com/stretchr/testify v1.10.0
go: downloading github.com/go-logr/zapr v1.3.0
go: downloading go.uber.org/zap v1.27.0
go: downloading k8s.io/apiserver v0.34.0
go: downloading go.uber.org/goleak v1.3.0
go: downloading go.uber.org/multierr v1.11.0
go: downloading k8s.io/component-base v0.34.0
go: downloading github.com/klauspost/compress v1.18.0
go: downloading github.com/evanphx/json-patch v0.5.2
go: downloading gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
go: downloading github.com/google/gofuzz v1.2.0
go: downloading github.com/google/cel-go v0.26.0
go: downloading github.com/blang/semver/v4 v4.0.0
go: downloading go.opentelemetry.io/otel/trace v1.35.0
go: downloading go.opentelemetry.io/otel v1.35.0
go: downloading github.com/stretchr/objx v0.5.2
go: downloading github.com/kylelemons/godebug v1.1.0
go: downloading github.com/kr/pretty v0.3.1
go: downloading github.com/go-task/slim-sprig/v3 v3.0.0
go: downloading golang.org/x/tools v0.26.0
go: downloading cel.dev/expr v0.24.0
go: downloading google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb
go: downloading github.com/kr/text v0.2.0
go: downloading github.com/rogpeppe/go-internal v1.13.1
go: downloading github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db
go: downloading github.com/stoewer/go-strcase v1.3.0
go: downloading github.com/antlr4-go/antlr/v4 v4.13.0
go: downloading google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb
go: downloading google.golang.org/grpc v1.72.1
go: downloading sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2
go: downloading go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0
go: downloading go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0
go: downloading go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0
go: downloading go.opentelemetry.io/otel/sdk v1.34.0
go: downloading golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
go: downloading github.com/spf13/cobra v1.9.1
go: downloading github.com/felixge/httpsnoop v1.0.4
go: downloading go.opentelemetry.io/otel/metric v1.35.0
go: downloading go.opentelemetry.io/proto/otlp v1.5.0
go: downloading github.com/inconshreveable/mousetrap v1.1.0
go: downloading github.com/go-logr/stdr v1.2.2
go: downloading github.com/cenkalti/backoff/v4 v4.3.0
go: downloading github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
go: downloading go.opentelemetry.io/auto/sdk v1.1.0
go: downloading github.com/golang/protobuf v1.5.4
go: downloading go.opentelemetry.io/otel/sdk/metric v1.34.0
Next: define a resource with:
$ kubebuilder create api
第二步:创建新的API(CRD)
这一步会为你创建一个新的自定义资源(CRD)以及对应的控制器框架。
kubebuilder create api --group webapp --version v1 --kind Welcome
当提示创建资源和控制器时,都选择 y (yes)。这个命令会在 api/v1/ 目录下生成 welcome_types.go 文件,这就是你定义CRD规格的地方。
#下面是使用上述命令的一些输出信息
INFO Create Resource [y/n]
y
INFO Create Controller [y/n]
y
INFO Writing kustomize manifests for you to edit...
INFO Writing scaffold for you to edit...
INFO api/v1/welcome_types.go
INFO api/v1/groupversion_info.go
INFO internal/controller/suite_test.go
INFO internal/controller/welcome_controller.go
INFO internal/controller/welcome_controller_test.go
INFO Update dependencies
INFO Running make
mkdir -p /root/crd/myopertor/bin
Downloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.19.0
go: downloading sigs.k8s.io/controller-tools v0.19.0
go: downloading golang.org/x/tools v0.36.0
go: downloading github.com/spf13/pflag v1.0.7
go: downloading k8s.io/code-generator v0.34.0
go: downloading k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f
go: downloading github.com/gobuffalo/flect v1.0.3
go: downloading gopkg.in/yaml.v2 v2.4.0
go: downloading github.com/fatih/color v1.18.0
go: downloading golang.org/x/sync v0.16.0
go: downloading github.com/mattn/go-colorable v0.1.13
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading google.golang.org/protobuf v1.36.7
go: downloading github.com/go-logr/logr v1.4.3
go: downloading golang.org/x/mod v0.27.0
go: downloading golang.org/x/sys v0.35.0
go: downloading golang.org/x/net v0.43.0
go: downloading golang.org/x/text v0.28.0
/root/crd/myopertor/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:
$ make manifests
第三步:定义自定义资源的规范
当前的目录结构如下:
#1 当前目录结构
$ tree /root/crd/myopertor
/root/crd/myopertor
├── api
│ └── v1
│ ├── groupversion_info.go
│ ├── welcome_types.go
│ └── zz_generated.deepcopy.go
├── bin
│ ├── controller-gen -> /root/crd/myopertor/bin/controller-gen-v0.19.0
│ └── controller-gen-v0.19.0
├── cmd
│ └── main.go
├── config
│ ├── crd
│ │ ├── kustomization.yaml
│ │ └── kustomizeconfig.yaml
│ ├── default
│ │ ├── cert_metrics_manager_patch.yaml
│ │ ├── kustomization.yaml
│ │ ├── manager_metrics_patch.yaml
│ │ └── metrics_service.yaml
│ ├── manager
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── network-policy
│ │ ├── allow-metrics-traffic.yaml
│ │ └── kustomization.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ ├── monitor_tls_patch.yaml
│ │ └── monitor.yaml
│ ├── rbac
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── metrics_auth_role_binding.yaml
│ │ ├── metrics_auth_role.yaml
│ │ ├── metrics_reader_role.yaml
│ │ ├── role_binding.yaml
│ │ ├── role.yaml
│ │ ├── service_account.yaml
│ │ ├── welcome_admin_role.yaml
│ │ ├── welcome_editor_role.yaml
│ │ └── welcome_viewer_role.yaml
│ └── samples
│ ├── kustomization.yaml
│ └── webapp_v1_welcome.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── internal
│ └── controller
│ ├── suite_test.go
│ ├── welcome_controller.go
│ └── welcome_controller_test.go
├── Makefile
├── PROJECT
├── README.md
└── test
├── e2e
│ ├── e2e_suite_test.go
│ └── e2e_test.go
└── utils
└── utils.go
18 directories, 46 files
编辑 api/v1/welcome_types.go 文件,在 WelcomeSpec 结构体中添加你需要的字段。这些字段就是用户在YAML文件中配置的参数。
#2 编辑welcome_types.go文件
vim api/v1/welcome_types.go
// WelcomeSpec defines the desired state of Welcome
type WelcomeSpec struct {
// 在这里添加字段。例如,让用户可以设置显示的名字和服务端口。
Name string `json:"name"`
Port int32 `json:"port,omitempty"`
}
同样,你也可以在 WelcomeStatus 结构体中定义状态字段,控制器可以用它来反映资源的当前状态。
定义完成后,需要运行 make install 命令,将你的CRD真正安装到Kubernetes集群中。
第四步:实现控制器的协调逻辑
这是Operator的核心大脑。你需要编辑 internal/controller/welcome_controller.go 文件中的 Reconcile 方法。Reconcile 方法的目标是:检查系统的当前状态,并将其调整到与CR(“工作指令单”)中描述的期望状态一致。这个过程是声明式API的核心。
以下是一个非常简化的例子,当用户创建一个 Welcome 资源时,控制器会自动为我们部署一个Deployment和一个Service:
func (r *WelcomeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := ctrl.Log.FromContext(ctx)
// 1. 获取当前的Welcome资源实例
var welcome webappv1.Welcome
if err := r.Get(ctx, req.NamespacedName, &welcome); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// 2. 检查并创建Deployment(如果不存在)
dep := &appsv1.Deployment{}
err := r.Get(ctx, types.NamespacedName{Name: welcome.Name, Namespace: req.Namespace}, dep)
if err != nil && errors.IsNotFound(err) {
// 定义并创建新的Deployment
newDep := r.newDeploymentForWelcome(&welcome)
if err := r.Create(ctx, newDep); err != nil {
return ctrl.Result{}, err
}
log.Info("创建了一个新的Deployment", "Deployment.Namespace", newDep.Namespace, "Deployment.Name", newDep.Name)
}
// 3. 检查并创建Service(如果不存在)
svc := &corev1.Service{}
err = r.Get(ctx, types.NamespacedName{Name: welcome.Name, Namespace: req.Namespace}, svc)
if err != nil && errors.IsNotFound(err) {
// 定义并创建新的Service
newSvc := r.newServiceForWelcome(&welcome)
if err := r.Create(ctx, newSvc); err != nil {
return ctrl.Result{}, err
}
log.Info("创建了一个新的Service", "Service.Namespace", newSvc.Namespace, "Service.Name", newSvc.Name)
}
return ctrl.Result{}, nil
}
// 辅助函数,根据Welcome规格创建Deployment对象
func (r *WelcomeReconciler) newDeploymentForWelcome(w *webappv1.Welcome) *appsv1.Deployment {
// ... 这里需要你根据Welcome对象的Spec来构建并返回一个完整的Deployment对象。
// 例如,可以将 w.Spec.Name 作为环境变量传递给Pod。
}
// 辅助函数,根据Welcome规格创建Service对象
func (r *WelcomeReconciler) newServiceForWelcome(w *webappv1.Welcome) *corev1.Service {
// ... 这里需要你根据Welcome对象的Spec来构建并返回一个完整的Service对象。
}
第五步:运行与测试
-
在集群中运行:
make docker-build docker-push IMG=<你的镜像仓库地址>/myoperator:v1 make deploy -
本地直接运行(用于开发调试):
make run
第六步:使用你的Operator
#部署控制器,这一步需要你本地有k8s环境,它会将你的CRD部署到集群
make install
在集群中部署或本地运行你的Operator控制器后,你就可以创建一个自定义资源实例来使用它了。
# config/samples/webapp_v1_welcome.yaml
apiVersion: webapp.mydomain.com/v1
kind: Welcome
metadata:
name: welcome-sample
spec:
name: "Kubernetes Operator test"
port: 8088
使用 kubectl apply -f config/samples/webapp_v1_welcome.yaml 命令创建资源,然后使用 kubectl get pods 和 kubectl get services 观察你的Operator是否成功创建了对应的Deployment和Service。
$ kubectl apply -f config/samples/webapp_v1_welcome.yaml
welcome.webapp.mydomain.com/welcome-sample created
四、💎 总结与进阶
Operator模式是Kubernetes声明式API和控制器模式的强大延伸。对于运维复杂的有状态应用来说,它是一个极具价值的工具。
- 从使用开始:先熟练使用OperatorHub上的成熟Operator,理解其行为。
- 选择合适框架:当需要自研时,Kubebuilder(或功能相似的 operator-sdk)是你的首选。
- 核心是调和循环:编写Operator的关键在于理解并实现好
Reconcile函数,不断对比"期望状态"和"实际状态",并驱动系统向期望状态收敛。
本文来源于我的微信公众号Linux运维小白,我会持续更新文章,欢迎大家关注,互相交流学习。
更多推荐

所有评论(0)