CRD官方文档
kubernetes 有两种机制供用户扩展API
CRD
Custom resources
Custom controllers 自定义控制器
Operator模式
通俗理解:CR即创建一个自定义资源,CRD是对资源的描述,CC是提供CRD对象的管理。
CRD本身只是一段声明,用于定义用户自定义的资源对象。但仅有CRD的定义并没有实际作用,用户还需要提供管理CRD对象的CRD控制器(CRD Controller),才能实现对CRD对象的管理。CRD控制器通常可以通过Go语言进行开发,并需要遵循Kubernetes的控制器开发规范,基于客户端库client-go进行开发,需要实现Informer、ResourceEventHandler、Workqueue等组件具体的功能处理逻辑。
crd在很多k8s周边开源项目中有使用,比如ingress-controller 、istio 、hpa和众多的operator。
Kubebuilder
Kubebuilder 是一个基于 CRD 来构建 Kubernetes API 的框架,可以使用 CRD 来构建 API、Controller 和 Admission Webhook。
从零开始写一个 CRD 及其Controller ,它的开发方式经历过不同的阶段,从最早的参考 K8S 官方的控制器代码并手动复制,到用 client-gen 生成框架代码,到现在使用 kubebuilder ,已经非常方便我们完成 CRD/Controller,甚至 Operator 的开发(当然 Operator 的开发也有专用的 operator-sdk开源框架)。
Centos中安装golang、kubebuilder、kustomize环境
kubernetes集群部署
golang 1.15.5
kubebuilder 2.3.1 (推荐使用二进制方式安装)
kustomize
kubernetes集群 1.20.1
export GO111MODULE=on
以强制启用 Go module,它是目前最新的 Golang 包依赖管理工具,也是官方推荐,govender,godep 等工具已经不建议继续使用go env -w GOPROXY=goproxy.cn,direct
开启代理,配置默认从 goproxy.cn 拉去 Go Module 的依赖包,如果不存在走默认的方式,goproxy.cn 是七牛云维护的一个 golang 包代理库,测试下来性能是最好的,可以拉取很多被墙掉的包go version #查看go的版本
kubebuilder version
kubectl get nodes # 查看k8s集群的版本
go mod init my.domain
## 这两个复杂的命令可以通过kubebuilder --help查看
# 初始化
kubebuilder init --domain example.com --license apache2 --owner "The Kubernetes authors"
# 创建CRD api
kubebuilder create api --group webapp --version v1 --kind Frigate
# 安装CRD
make install
# 启动controller(本地)
make run
我们首先将使用自动配置创建一个项目,该项目在创建 CR 时不会触发任何资源生成。
创建的项目路径位于 $GOPATH/kubebuilder-example。
go mod init my.domain
go mod init:初始化go mod, 生成go.mod文件,后可接参数指定 module 名
在项目路径下使用下面的命令初始化项目。
kubebuilder init --domain example.com --license apache2 --owner "The Kubernetes authors"
这时需要保证你的终端能访问 K8S 的测试集群,简单就是用 kubectl cluster-info
看看是否出错,如果不出错,就可以 go run main.go
了
开始执行,发现正常输出日志了
kubebuilder create api --group webapp --version v1 --kind Frigate
注意, group / version / kind 这三个属性组合起来来标识一个 K8S 的 CRD。
kind 要首字母大写而且不能有特殊符号。
在创建过程中,我们可以选择让 KubeBuilder 来是否生成 Resource / Controller 等。
执行上面的命令之后,KubeBuilder 就帮我们创建了两个文件 api/v1/frigate_types.go
和controllers/frigate_controller.go
, 前者是这个 CRD 需要定义哪些属性,而后者是对 CRD 的 Reconcile 的处理逻辑(也就是增删改 CRD 的逻辑), 我们后面再讲这两个文件。
先来 make install
一下, 将其安装到 K8S cluster 中
make install
kubectl get crd
有两种方式运行 controller:
要想在本地运行 controller,需要执行:
make run
按照其他相关博客 提示:
请修改DockerFile中:
a. 将FROM golang:1.12.5 as builder 替换成 FROM golang:1.13 as builder
b. 在COPY go.sum 下加上ENV GOPROXY=https://goproxy.cn,direct
c. 将FROM gcr.io/distroless/static:nonroot 替换成 FROM golang:1.13
d. 删除USER nonroot:nonroot
修改了相关部分:如下
make docker-build docker-push IMG=registry.cn-beijing.aliyuncs.com/anan_java/go_project_01:v1.0
注意:这个仓库是自己在阿里云建的仓库,可以使用自己的仓库名
成功构建镜像并上传到服务器
注意:此处如果出现问题,参考文末
对于中国大陆用户,可能无法访问 Google 镜像仓库 gcr.io,因此需要修改 config/default/manager_auth_proxy_patch.yaml 文件中的镜像地址:
vim config/default/manager_auth_proxy_patch.yaml
替换成: image: registry.cn-hangzhou.aliyuncs.com/kubenode/kube-rbac-proxy:v0.4.0
make deploy IMG=registry.cn-beijing.aliyuncs.com/anan_java/go_project_01:v1.0
在初始化项目时,kubebuilder 会自动根据项目名称创建一个 Namespace,如本文中的 kubebuilder-example-system,查看 Deployment 对象和 Pod 资源。
看到running好开心,这个地方调了好多次!
注意:此处如果出现问题,参考文末
Kubebuilder 在初始化项目的时候已生成了示例 CR。
可以在源码目录下看到config文件下有个sample文件夹,里面有例子:
执行下面的命令部署 CR
kubectl apply -f config/samples/webapp_v1_frigate.yaml
执行下面的命令查看新创建的 CR
kubectl get frigate.webapp.example.com frigate-sample -o yaml
下面我们将修改 CRD 的数据结构并在 controller 中增加一些日志输出。
我们将修改上文中使用 kubebuilder 命令生成的默认 CRD 配置,在 CRD 中增加 FirstName、LastName 和 Status 字段。
修改 api/v1/frigate_types.go
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Status string `json:"Status"`
修改 controllers/frigate_controller.go
# 添加log包
# 添加如下代码
_ = r.Log.WithValues("apiexamplea", req.NamespacedName)
// 获取当前的 CR,并打印
obj := &webappv1.Frigate{}
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
log.Println(err, "Unable to fetch object")
} else {
log.Println("Geeting from Kubebuilder to", obj.Spec.FirstName, obj.Spec.LastName)
}
// 初始化 CR 的 Status 为 Running
obj.Status.Status = "Running"
if err := r.Status().Update(ctx, obj); err != nil {
log.Println(err, "unable to update status")
}
这段代码的业务逻辑是当发现有 CR 变更时,在控制台中输出日志。
修改好 业务逻辑后,再测试一下新的逻辑是否可以正常运行
make install # 部署CRD
make run # 本地运行controller 也可以将其部署到 Kubernetes 上运行
修改 config/samples/webapp_v1_frigate.yaml 文件中的配置。
将其应用到 Kubernetes。
kubectl apply -f config/samples/webapp_v1_frigate.yaml
此时转到上文中运行 controller 的窗口,将在命令行前台中看到如下输出。
Geeting from Kubebuilder to Ning An 这正是在 Reconcile 函数中的输出。
kubectl get frigate.webapp.example.com frigate-sample -o yaml
这正是我们在 CRD 里定义的字段。
使用下面的命令删除 CR。
kubectl delete frigate.webapp.example.com frigate-sample
此时在 controller 的前台输出中可以看到以下内容。
因为该 CR 被删除,因此日志中会提示资源找不到。
make uninstall
此时在 controller 的前台输出中可以看到以下内容:
部署结束!
注意:
unable to start manager {“error”: “error listening on :8080: listen tcp :8080: bind: address already in use”}
提示8080端口被占用,这是因为自己昨天运行了一下go run main.go,今天又运行了一下
解决方法: 找到占用8080端口的进程,kill掉即可
netstat -tnlp | grep 80
kill -9 进程号
注意:如果make run时出现如下错误,说明改行变量声明有问题,将 ctx :=...
删掉即可
curl: (35) Network file descriptor is not connected
make: *** [test] 错误 35
有篇博客提到一些二进制文件的问题
要把 etcd / apiserver 等二进制可执行文件。这个在解压的 kubebuilder 的文件中可以找到。
如果构建有问题,需要放到 /usr/local/kubebuilder/bin/ 中
可是自己通过源码安装,没有二进制文件
所以,选择选择以二进制的方式重新安装kubebuilder
(至于怎么卸载呢?就把之前的那个文件夹删掉并且删除相关的环境变量)
go: github.com/go-logr/[email protected]: Get https://proxy.golang.org/github.com/go-logr/logr/@v/v0.1.0.mod: dial tcp 172.217.160.113:443: connect: connection refused
The command ‘/bin/sh -c go mod download’ returned a non-zero code: 1
make: *** [docker-build] 错误 1
请修改DockerFile中:
a. 将FROM golang:1.12.5 as builder 替换成 FROM golang:1.13 as builder
b. 在COPY go.sum 下加上ENV GOPROXY=https://goproxy.cn,direct
c. 将FROM gcr.io/distroless/static:nonroot 替换成 FROM golang:1.13
d. 删除USER nonroot:nonroot
修改了相关部分:如下
make docker-build docker-push IMG=registry.cn-beijing.aliyuncs.com/anan_java/go_project_01:v1.0
# 重新安装
go install sigs.k8s.io/kustomize/kustomize/v3
vim config/default/manager_auth_proxy_patch.yaml
替换成: image: registry.cn-hangzhou.aliyuncs.com/kubenode/kube-rbac-proxy:v0.4.0
然后删除系统创建的资源,重新构建镜像并发布,从make docker build那部分开始
注意:第一次从这个部分开始出现了错误,删除CRD重头开始了
第二次从这个部分开始就正确了
# 自己删除了 镜像,命名空间,还有仓库里的镜像
docker rmi 镜像号
kubectl delete ns 命名空间
手动删除仓库里的镜像
构建镜像时出现:
实在看不下去了,直接删除CRDmake uninstall
重新开始了
CRD介绍:
Kubernetes中CRD的介绍和使用
kubernetes1.9管中窥豹-CRD概念、使用场景及实例
Kuberneters(K8s)CRD资源详解
kubernetes CRD
CRD及Controller创建:
K8S中编写自己的CRD及Controller简明指南 主参考 Kind: Frigate
使用 kubebuilder 创建 operator 示例 主参考 --kind Guestbook
kubernetes CRD开发指南 --kind VirtulMachine
云计算虚拟化:k8s进阶-CRD项目部署
Kubebuilder:
Kubernetes CRD 开发实践