确保 kubeconfig 文件 ~/.kube/config 存在,并且内容正确
如果是k3s参考我之前的文章 https://www.cnblogs.com/qcy-blog/p/18188865
1. Operator 是什么?
Operator 是使用自定义资源(CR,Custom Resource)管理应用及其组件的自定义控制器(Controller)
Control Plane 的控制器实施控制循环,反复比较集群的 Disired Status 和 Current Status,如果两者不符,那么控制器采取措施解决该问题
CR 是 Kubernetes 中的 API 扩展机制
自定义资源定义(CRD,Custom Resource Definition)明确 CR,列出 Operator 用户可用的所有配置
Operator 通过 CRD 引入新对象类型。Kubenetes API 像处理内置对象一样处理 CRD
2. 安装 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/
查看 kubebuilder 版本
kubebuilder version
# 输出:
Version: main.version{KubeBuilderVersion:"3.14.2", KubernetesVendor:"1.27.1", GitCommit:"d7b4febe6b673709100b780b5b99151c5e26a206", BuildDate:"2024-04-27T08:27:24Z", GoOs:"linux", GoArch:"amd64"}
3. 创建测试项目
mkdir kubebuilder-operator-demo
cd kubebuilder-operator-demo/
go mod init kubebuilder-operator-demo
4. 初始化项目 --domain 是公司域名
kubebuilder init --domain timd.cn
当看到如下输出时,表明初始化成功:
...
$ go mod tidy
Next: define a resource with:
$ kubebuilder create api
说明:
config/default/kustomization.yaml 中的 namespace 字段用于为所有资源添加命名空间。
在这里它是 kubebuilder-operator-demo-system,因为他是跟go mod 有关系
5. 创建 API
这是使用 Kubebuilder 工具创建一个新的自定义 Kubernetes API 资源。具体来说,它会创建一个名为 Redis 的新资源,位于 testapp 组中,
并且版本为 v1。这将在您的项目中生成相应的代码,包括 API 对象定义、控制器和 CRD(自定义资源定义)。
kubebuilder create api --group testapp --version v1 --kind Redis
创建成功后,项目结构如下:
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api
│ └── v1
│ ├── groupversion_info.go
│ ├── redis_types.go
│ └── zz_generated.deepcopy.go
├── bin
│ └── controller-gen
├── config
│ ├── crd
│ │ ├── kustomization.yaml
│ │ ├── kustomizeconfig.yaml
│ │ └── patches
│ │ ├── cainjection_in_redis.yaml
│ │ └── webhook_in_redis.yaml
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── redis_editor_role.yaml
│ │ ├── redis_viewer_role.yaml
│ │ ├── role_binding.yaml
│ │ └── service_account.yaml
│ └── samples
│ └── testapp_v1_redis.yaml
├── controllers
│ ├── redis_controller.go
│ └── suite_test.go
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
└── main.go
说明:##############
apiVersion 为 testapp.timd.cn/v1
kind 为 Redis
6. 创建测试 CRD
将 api/v1/redis_types.go 中 RedisSpec 结构体的定义改为:
// RedisSpec defines the desired state of Redis
type RedisSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Foo is an example field of Redis. Edit redis_types.go to remove/update
//Foo string `json:"foo,omitempty"`
Port int `json:"port,omitempty"`
}
创建 test/redis.yaml 文件,其内容为:
apiVersion: testapp.timd.cn/v1
kind: Redis
metadata:
name: testapp
spec:
port: 80
安装:
make install
如果通过在线脚本下载 kustomize 失败,可以使用代理;或自己下载 kustomize,然后放到 bin/ 目录下
查看刚刚创建的 CRD:
kubectl describe crd redis.testapp.timd.cn
7. 在本地运行
将 controllers/redis_controller.go 中 Reconcile() 方法的定义改为:
func (r *RedisReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
// TODO(user): your logic here
redis := &testappv1.Redis{}
if err := r.Get(ctx, req.NamespacedName, redis); err != nil {
fmt.Println(err)
} else {
fmt.Println("object:", redis)
}
return ctrl.Result{}, nil
}
注意:导入 fmt 包
在一个窗口运行:
make run
在另一个窗口运行:
kubectl apply -f test/redis.yaml
查看第一个窗口的日志;用 kubectl 查看刚刚创建的 CR:
kubectl get redis
8. 添加验证
将 api/v1/redis_types.go 中 RedisSpec 的定义修改为:
// RedisSpec defines the desired state of Redis
type RedisSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// +kubebuilder:validation:Maximum:=6380
// +kubebuilder:validation:Minimum:=6370
Port int `json:"port,omitempty"`
}
安装:
make install
查看 CRD:
kubectl get crd redis.testapp.timd.cn -o yaml
可以看到类似下面的输出:
spec:
description: RedisSpec defines the desired state of Redis
properties:
port:
description: Foo is an example field of Redis. Edit redis_types.go
to remove/update
maximum: 6380
minimum: 6370
type: integer
type: object
测试验证:
kubectl delete -f test/redis.yaml
kubectl apply -f test/redis.yaml
可以看到类似下面的错误:
The Redis "testapp" is invalid: spec.port: Invalid value: 80: spec.port in body should be greater than or equal to 6370
9. 将 Operator 部署到 Kubernetes 集群
将前面测试过程中创建的 CR、CRD 清理掉:
kubectl delete -f test/redis.yaml
make uninstall
然后重新安装:
make install
kubectl get crd redis.testapp.timd.cn
9.1. 构建镜像
make docker-build IMG=<镜像名称>:<标签>
9.2. 部署
make deploy IMG=<镜像名称>:<标签>
通过如下命令查看部署状态:
kubectl -n kubebuilder-operator-demo-system get all
通过如下命令查看 Pod 输出的日志(注意替换 Pod 的名称):
kubectl -n kubebuilder-operator-demo-system logs -f kubebuilder-operator-demo-controller-manager-74fb7bf75-522tg
创建 CR,同时观察 Pod 的输出:
kubectl apply -f test/redis.yaml