~/.kube/config
存在,并且内容正确Kubernetes Operator 是一种封装、部署和管理 Kubernetes 应用的方法。
如欲了解更多细节,请阅读:
简单来讲:
Operator 是使用自定义资源(CR,Custom Resource)管理应用及其组件的自定义控制器(Controller)
CR 是 Kubernetes 中的 API 扩展机制
自定义资源定义(CRD,Custom Resource Definition)明确 CR,列出 Operator 用户可用的所有配置
Operator 通过 CRD 引入新对象类型。Kubenetes API 像处理内置对象一样处理 CRD
常用的 Operator 开发框架:
下面介绍如何使用 kubebuilder 开发 Operator。
说明:
- kubebuilder book:https://book.kubebuilder.io/quick-start.html
- kubebuilder Github:https://github.com/kubernetes-sigs/kubebuilder
xxxxxxxxxx
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.7.0", KubernetesVendor:"1.24.1", GitCommit:"3bfc84ec8767fa760d1771ce7a0cb05a9a8f6286", BuildDate:"2022-09-20T17:21:57Z", GoOs:"darwin", GoArch:"amd64"}
xxxxxxxxxx
mkdir kubebuilder-operator-demo
cd kubebuilder-operator-demo/
go mod init kubebuilder-operator-demo
xxxxxxxxxx
kubebuilder init --plugins go/v3 --domain timd.cn --owner "Tim Chow"
当看到如下输出时,表明初始化成功:
...
$ go mod tidy
Next: define a resource with:
$ kubebuilder create api
说明:
config/default/kustomization.yaml
中的namespace
字段用于为所有资源添加命名空间。在这里它是 kubebuilder-operator-demo-system
xxxxxxxxxx
kubebuilder create api --group testapp --version v1 --kind Redis
创建成功后,项目结构如下:
xxxxxxxxxx
.
├── 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
将 api/v1/redis_types.go
中 RedisSpec
结构体的定义改为:
x
// 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
Port int `json:"port,omitempty"`
}
创建 test/redis.yaml 文件,其内容为:
xxxxxxxxxx
apiVersion testapp.timd.cn/v1
kind Redis
metadata
name testapp
spec
port80
安装:
make install
如果通过在线脚本下载
kustomize
失败,可以使用代理;或自己下载kustomize
,然后放到bin/
目录下
查看刚刚创建的 CRD:
xxxxxxxxxx
kubectl describe crd redis.testapp.timd.cn
将 controllers/redis_controller.go
中 Reconcile()
方法的定义改为:
xxxxxxxxxx
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
在另一个窗口运行:
xxxxxxxxxx
kubectl apply -f test/redis.yaml
查看第一个窗口的日志;用 kubectl
查看刚刚创建的 CR:
kubectl get redis
CRD 通过在 validation
区域使用 OpenAPI v3 模式的方式支持声明式验证(declarative validation)。
通常,验证标记(validation markers)被附加到字段或类型,如果定义复杂验证,必须重用验证,或必须验证切片元素,最好定义新类型来描述验证。
比如:
type ToySpec struct {
// +kubebuilder:validation:MaxLength=15
// +kubebuilder:validation:MinLength=1
Name string `json:"name,omitempty"`
// +kubebuilder:validation:MaxItems=500
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:UniqueItems=true
Knights []string `json:"knights,omitempty"`
Alias Alias `json:"alias,omitempty"`
Rank Rank `json:"rank"`
}
// +kubebuilder:validation:Enum=Lion;Wolf;Dragon
type Alias string
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=3
// +kubebuilder:validation:ExclusiveMaximum=false
type Rank int32
如欲了解更多关于验证的细节,请查看 https://book.kubebuilder.io/reference/markers/crd-validation.html。
将 api/v1/redis_types.go
中 RedisSpec
的定义修改为:
x
// 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
// +kubebuilder:validation:Maximum:=6380
// +kubebuilder:validation:Minimum:=6370
Port int `json:"port,omitempty"`
}
安装:
make install
查看 CRD:
xxxxxxxxxx
kubectl get crd redis.testapp.timd.cn -o yaml
可以看到类似下面的输出:
xxxxxxxxxx
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
maximum6380
minimum6370
type integer
type object
测试验证:
x
kubectl delete -f test/redis.yaml
kubectl apply -f test/redis.yaml
可以看到类似下面的错误:
xxxxxxxxxx
The Redis "testapp" is invalid: spec.port: Invalid value: 80: spec.port in body should be greater than or equal to 6370
xxxxxxxxxx
kubebuilder create webhook --group testapp --version v1 --kind Redis --defaulting --programmatic-validation
将 api/v1/redis_webhook.go
中 ValidateCreate()
方法的定义修改为:
x
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (r *Redis) ValidateCreate() error {
redislog.Info("validate create", "name", r.Name)
// TODO(user): fill in your validation logic upon object creation.
if r.Name == "abandon" {
return errors.New("abandon")
}
return nil
}
注意:
- 导入 errors 包
执行如下命令安装:
xxxxxxxxxx
# 如果下载失败,请使用代理
curl -L -o cert-manager.yaml https://github.com/cert-manager/cert-manager/releases/download/v1.8.2/cert-manager.yaml
kubectl apply -f cert-manager.yaml
查看 Pod,确认启动成功:
x
kubectl get pods -n cert-manager
注意:
- 需要为 dockerd 配置代理或 registry-mirrors,否则拉取镜像可能会失败
将 config/default/kustomization.yaml
中:
#- ../webhook
解除注释#- ../certmanager
解除注释#- manager_webhook_patch.yaml
解除注释#- webhookcainjection_patch.yaml
解除注释vars
下面被注释的内容解除注释在 config/manager/manager.yaml
中的如下两行:
image controller latest
name manager
之间插入:
x
imagePullPolicy IfNotPresent
获取 Temp 目录,比如在 macOS 上是环境变量 TMPDIR
的值
创建保存证书的目录
xxxxxxxxxx
mkdir -p ${TMPDIR}/k8s-webhook-server/serving-certs
获取 tls.crt
xxxxxxxxxx
kubectl -n cert-manager get secret cert-manager-webhook-ca -o jsonpath="{..tls\.crt}" | base64 -d > $TMPDIR/k8s-webhook-server/serving-certs/tls.crt
获取 tls.key
xxxxxxxxxx
kubectl -n cert-manager get secret cert-manager-webhook-ca -o jsonpath="{..tls\.key}" | base64 -d > $TMPDIR/k8s-webhook-server/serving-certs/tls.key
获取 ca.crt
xxxxxxxxxx
kubectl -n cert-manager get secret cert-manager-webhook-ca -o jsonpath="{..ca\.crt}" | base64 -d > $TMPDIR/k8s-webhook-server/serving-certs/ca.crt
运行
xxxxxxxxxx
make run
测试
kubectl apply -f test/redis.yaml
,然后观察日志kubectl get redis
查看创建的 CR将前面测试过程中创建的 CR、CRD 清理掉:
kubectl delete -f test/redis.yaml
make uninstall
然后重新安装:
make install
kubectl get crd redis.testapp.timd.cn
我使用的镜像仓库是免费的腾讯云镜像仓库个人版(https://console.cloud.tencent.com/tcr/repository)。
在开发机上,通过如下命令登陆腾讯云镜像仓库:
x
docker login ccr.ccs.tencentyun.com
在 Kubernetes 集群的每个 node 上:
用与开发机相同的命令进行登陆
执行下面的命令,使 Kubernetes 无需登陆腾讯云镜像仓库
cp ~/.docker/config.json /var/lib/kubelet/config.json
重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
注意:
- 因为部署时,从 gcr.io 拉取镜像,因此需要为 dockerd 设置代理或 registry-mirrors;也可以先从别的镜像源拉取,再打标签
xxxxxxxxxx
make docker-build docker-push IMG=ccr.ccs.tencentyun.com/timchowwww/kubebuilder-operator-demo:v20221108
xxxxxxxxxx
make deploy IMG=ccr.ccs.tencentyun.com/timchowwww/kubebuilder-operator-demo:v20221108
通过如下命令查看部署状态:
xxxxxxxxxx
kubectl -n kubebuilder-operator-demo-system get all
通过如下命令查看 Pod 输出的日志(注意替换 Pod 的名称):
xxxxxxxxxx
kubectl -n kubebuilder-operator-demo-system logs -f kubebuilder-operator-demo-controller-manager-74fb7bf75-522tg
创建 CR,同时观察 Pod 的输出:
x
kubectl apply -f test/redis.yaml
多改几次 .spec.port 的值,观察输出。