一、API资源对象CRD
Kubernetes 自定义资源定义(Custom Resource Definition,简称 CRD)是一种强大的 Kubernetes API 扩展机制,允许你定义和创建自己的资源类型,以满足您的应用程序或基础设施需求。
CRD 的核心思想是通过声明式的 API 来扩展 Kubernetes 的功能。你可以定义自己的资源结构,然后像操作 Kubernetes 内建资源一样操作这些自定义资源。这意味着您可以使用熟悉的Kubernetes工具如kubectl或Kubernetes控制器与管理您的自定义资源进行交互。
CRD提供了一种扩展Kubernetes平台以适应特定要求的方式,并能够构建自定义的运算符或控制器来自动化管理自定义资源。运算符可以监视自定义资源的更改并相应地采取操作,例如提供额外的资源、扩展或执行自定义操作。CRD已成为扩展Kubernetes的流行机制,在Kubernetes生态系统中的各种项目和框架中广泛使用,如Prometheus、Istio和Knative。
示例:
[root@aminglinux01 ~]# cat crd-example.yaml
apiVersion: apiextensions.k8s.io/v1 #指定所使用的 CRD API 的版本,此示例使用了apiextensions.k8s.io/v1 版本。
kind: CustomResourceDefinition #定义资源类型为 CustomResourceDefinition。
metadata: #定义元数据,其中 name 字段指定了 CRD 的名称myresources.example.com。
name: myresources.example.com ###name必须包含group字段
spec: #定义了 CRD 的规范。
group: example.com #指定 CRD 所属的 API 组,此示例中为 example.com。
versions: #定义 CRD 的版本列表。
- name: v1 #指定版本的名称,此示例中为 v1。
served: true #指定此版本是否由 API 服务器提供服务,设为 true 表示提供服务。
storage: truestorage: #指定此版本是否持久化存储数据,设为 true 表示持久化
存储。
schema:
openAPIV3Schema: #指定自定义资源的 OpenAPI v3 架构定义
description: Define CronTab YAML Spec
type: object #定义类型
properties: #定义对象属性
spec:
type: object
properties:
name: #自定义具体属性的名字
type: string
age:
type: integer
scope: Namespaced #指定资源的作用域,此示例中为 Namespaced,表示资源
在命名空间级别进行管理。
names: #定义了资源的名称相关信息。
plural: myresources #指定资源的复数形式名称,此示例中为 myresources。
singular: myresource #指定资源的单数形式名称,此示例中为 myresource。
kind: MyResource #指定资源的类型名称,此示例中为 MyResource。
shortNames: #指定资源的缩略名称列表,此示例中只包含一个缩
略名称 mr。
- mr
[root@aminglinux01 ~]#
说明:
和我们定义普通的资源对象比较类似,这里可以随意定义一个自定义的资源对象,但是在创建资源的时候,肯定不是任由我们随意去编写YAML 文件的,当我们把上面的 CRD 文件提交给 Kubernetes 之后,Kubernetes 会对我们提交的声明文件进行校验,从定义可以看出 CRD是基于 OpenAPI v3 schem 进行规范的。
- apiVersion:指定所使用的 CRD API 的版本,此示例使用了apiextensions.k8s.io/v1 版本。
- kind:定义资源类型为 CustomResourceDefinition。
- metadata:定义元数据,其中 name 字段指定了 CRD 的名称为myresources.example.com。name中必须包含group字段。
- spec:定义了 CRD 的规范。
- group:指定 CRD 所属的 API 组,此示例中为 example.com。
- versions:定义 CRD 的版本列表。
- name:指定版本的名称,此示例中为 v1。
- served:指定此版本是否由 API 服务器提供服务,设为 true 表示提供服务。
- storage:指定此版本是否持久化存储数据,设为 true 表示持久化存储。
- openAPIV3Schema: 指定自定义资源的 OpenAPI v3 架构定义
- type:定义类型
- properties:定义对象属性
- name/age:自定义具体属性的名字
- scope:指定资源的作用域,此示例中为 Namespaced,表示资源在命名空间级别进行管理。
- names:定义了资源的名称相关信息。
- plural:指定资源的复数形式名称,此示例中为 myresources。
- singular:指定资源的单数形式名称,此示例中为 myresource。
- kind:指定资源的类型名称,此示例中为 MyResource。
- shortNames:指定资源的缩略名称列表,此示例中只包含一个缩略名称 mr。
应用
kubectl apply -f crd-example.yaml
[root@aminglinux01 ~]# kubectl apply -f crd-example.yaml
customresourcedefinition.apiextensions.k8s.io/myresources.example.com created
[root@aminglinux01 ~]#
查看crd
kubectl get crd
[root@aminglinux01 ~]# kubectl get crd
NAME CREATED AT
bgpconfigurations.crd.projectcalico.org 2024-07-08T13:28:18Z
bgppeers.crd.projectcalico.org 2024-07-08T13:28:18Z
blockaffinities.crd.projectcalico.org 2024-07-08T13:28:18Z
caliconodestatuses.crd.projectcalico.org 2024-07-08T13:28:18Z
clusterinformations.crd.projectcalico.org 2024-07-08T13:28:18Z
felixconfigurations.crd.projectcalico.org 2024-07-08T13:28:18Z
globalconfigurations.k8s.nginx.org 2024-07-14T20:10:00Z
globalnetworkpolicies.crd.projectcalico.org 2024-07-08T13:28:18Z
globalnetworksets.crd.projectcalico.org 2024-07-08T13:28:18Z
hostendpoints.crd.projectcalico.org 2024-07-08T13:28:18Z
ipamblocks.crd.projectcalico.org 2024-07-08T13:28:18Z
ipamconfigs.crd.projectcalico.org 2024-07-08T13:28:18Z
ipamhandles.crd.projectcalico.org 2024-07-08T13:28:18Z
ippools.crd.projectcalico.org 2024-07-08T13:28:18Z
ipreservations.crd.projectcalico.org 2024-07-08T13:28:18Z
kubecontrollersconfigurations.crd.projectcalico.org 2024-07-08T13:28:18Z
myresources.example.com 2024-07-17T18:06:32Z
networkpolicies.crd.projectcalico.org 2024-07-08T13:28:18Z
networksets.crd.projectcalico.org 2024-07-08T13:28:18Z
policies.k8s.nginx.org 2024-07-14T20:10:00Z
transportservers.k8s.nginx.org 2024-07-14T20:10:00Z
virtualserverroutes.k8s.nginx.org 2024-07-14T20:10:00Z
virtualservers.k8s.nginx.org 2024-07-14T20:10:00Z
[root@aminglinux01 ~]#
一旦创建完自定义的CRD,那么就会生成一个自定义的API
/apis/example.com/v1/namespaces/*/myresources/...
创建自定义资源实例,基于前面CRD定义的资源
[root@aminglinux01 ~]# cat myresource-instance.yaml
apiVersion: example.com/v1
kind: MyResource ##和上面CRD里相对应
metadata:
name: myresource-instance
spec: ##以下两个key必须在CRD中有过定义
name: example
age: 25
[root@aminglinux01 ~]#
kubectl apply -f myresource-instance.yaml
[root@aminglinux01 ~]# kubectl apply -f myresource-instance.yaml
myresource.example.com/myresource-instance created
[root@aminglinux01 ~]#
查看MyResource
kubectl get MyResource #或者用短名称
kubectl get mr
[root@aminglinux01 ~]# kubectl get MyResource
NAME AGE
myresource-instance 51s
[root@aminglinux01 ~]# kubectl get mr
NAME AGE
myresource-instance 59s
[root@aminglinux01 ~]#
以上定义的CRD,仅仅是写入到了etcd中,并没有其它用处,要想让它有进一步作用,还得去定义Controller而Controller更多的是开发范畴的事情,咱们暂时先不涉及。
二、认识Operator
1.Operator理论知识
1)Operator是什么
你可以理解成Operator就是CRD+自定义Controller的实践应用。
Kubernetes Operator由CoreOS公司开发,它是一种自定义控制器,它扩展了 Kubernetes API 的功能,用于管理和自动化应用程序、服务或资源的生命周期。Operator 可以将复杂的操作封装到 Kubernetes中,以便在集群中创建、配置、部署和管理特定类型的应用程序或服务。
Operator 的核心思想是将应用程序的专业知识嵌入到自定义控制器中,以便控制器能够理解和管理特定类型的应用程序。这样一来,Operator 可以根据自定义资源的规范和状态,自动执行与应用程序相关的任务,如创建、更新、伸缩、备份和恢复等。Operator 还可以响应集群事件,自动修复故障和应用程序状态的健康性。
通过使用 Operator,开发人员和管理员可以更轻松地在 Kubernetes上管理复杂的应用程序和服务,减少手动操作的工作量,提高可靠性和可重复性。同时,Operator 的开放性设计使得可以创建适用于各种不同类型应用程序的自定义操作符,从数据库、消息队列到机器学习模型
等各种类型的应用程序都可以通过 Operator 进行管理。
2)Operator用来做什么
使用 Operator 有很多理由。通常情况下,要么是开发团队为他们的产品创建 Operator,要么是 DevOps 团队希望对第三方软件管理进行自动化。无论哪种方式,都应该从确定 Operator 应该负责哪些东西开始。
最基本的 Operator 用于部署,使用 kubectl apply 就可以创建一个用于响应 API 资源的数据库,但这比内置的 Kubernetes 资源(如StatefulSets 或 Deployments)好不了多少。复杂的 Operator 将提供更大的价值。如果你想要对数据库进行伸缩该怎么办?
如果是 StatefulSet,你可以执行 kubectl scale statefulset my-db --replicas 3,这样就可以得到 3 个实例。但如果这些实例需要不同的配置呢?是否需要指定一个实例为主实例,其他实例为副本?如果在添加新副本之前需要执行设置步骤,那该怎么办?在这种情况下,可以使用Operator。
更高级的 Operator 可以处理其他一些特性,如响应负载的自动伸缩、备份和恢复、与 Prometheus 等度量系统的集成,甚至可以进行故障检测和自动调优。任何具有传统“运行手册”文档的操作都可以被自动化、测试和依赖,并自动做出响应。
被管理的系统甚至不需要部署在 Kubernetes 上也能从 Operator 中获益。例如,主要的云服务提供商(如 Amazon Web Services、微软Azure 和谷歌云)提供 Kubenretes Operator 来管理其他云资源,如对象存储。用户可以通过配置 Kubernetes 应用程序的方式来配置云资源。运维团队可能对其他资源也采取同样的方法,使用 Operator 来管理任何东西——从第三方软件服务到硬件。
下面总结了一些常见的场景:
- 按需部署一个应用程序,并自动配置,比如Prometheus
- 需要备份和恢复应用程序的状态,如MySQL数据库
- 处理应用程序代码的升级以及相关更改,例如数据库架构或额外的配置设置
- 发布一个服务,要让不支持Kubernetes API的应用程序能够发现
- 模拟整个或部分集群中的故障以测试其弹性
- 在没有内部成员选举程序的情况下为分布式应用程序选择领导者
2.Operator初次上手
说明:需要大家有一点go的开发能力
目前主流的Operator开发框架有两个:kubebuilder和Operator-sdk,两者实际上并没有本质的区别,它们的核心都是使用官方的 controllertools和 controller-runtime。不过细节上稍有不同,比如
kubebuilder 有着更为完善的测试与部署以及代码生成的脚手架等;而operator-sdk 对 ansible operator 这类上层操作的支持更好一些。下面基于kubebuilder,讲解如何开发Operator。
环境准备
Kubebuilder工作依赖go环境,所以需要安装go,理应单独拿一台机器来安装Kubebuilder,但我们为了节省资源,就拿aminglinux03来安
1)安装go
Rocky8使用yum安装
yum install -y golang.x86_64
检测版本
go version
[root@aminglinux03 ~]# go version
go version go1.21.11 (Red Hat 1.21.11-1.module+el8.10.0+1831+fc70fba6) linux/amd64
[root@aminglinux03 ~]#
设置代理
go env -w GOPROXY=https://goproxy.cn,direct
2)安装docker
开发过程中会用到docker环境,由于我们部署k8s时,安装过containerd,当时配置过yum仓库,所以可以直接通过yum来安装docker
yum install -y docker-ce
启动服务
systemctl start docker
3)安装kubectl 以及配置直接访问k8s集群
由于是aminglinux03,已经安装过kubectl,如果没有安装请参考部署k8s集群的步骤来安装。而默认aminglinux03是无法直接访问k8s集群的,需要将aminglinux01下面的/root/.kube目录拷贝到aminglinux03才可以
##以下操作在aminglinux01上操作
scp -r /root/.kube aminglinux03:/root/
测试
##在aminglinux03上执行
kubectl get node
[root@aminglinux03 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
aminglinux01 Ready control-plane 13d v1.26.2
aminglinux02 Ready <none> 13d v1.26.2
aminglinux03 Ready <none> 13d v1.26.2
[root@aminglinux03 ~]#
4)安装kubebuilder
curl -k -L -o kubebuilder https://github.com/kubernetes-sigs/kubebuilder/releases/download/v4.1.0/kubebuilder_linux_amd64
chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
[root@aminglinux03 ~]# curl -k -L -o kubebuilder https://github.com/kubernetes-sigs/kubebuilder/releases/download/v4.1.0/kubebuilder_linux_amd64
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 13.5M 100 13.5M 0 0 136k 0 0:01:42 0:01:42 --:--:-- 112k
[root@aminglinux03 ~]# chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
测试
kubebuilder version
[root@aminglinux03 ~]# kubebuilder version
Version: main.version{KubeBuilderVersion:"3.15.0", KubernetesVendor:"1.27.1", GitCommit:"c01af8fb2cf7c8e11b06b6b491f7974fc1232d1a", BuildDate:"2024-05-15T10:16:58Z", GoOs:"linux", GoArch:"amd64"}
[root@aminglinux03 ~]#
创建Helloworld项目
1)初始化项目
export GOPATH=`go env GOPATH`
mkdir -p $GOPATH/src/helloworld
cd $GOPATH/src/helloworld
kubebuilder init --domain aminglinux.com
[root@aminglinux03 helloworld]# kubebuilder init --domain aminglinux.com
INFO Writing kustomize manifests for you to edit...
INFO Writing scaffold for you to edit...
INFO Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.17.3
go: downloading sigs.k8s.io/controller-runtime v0.17.3
go: downloading k8s.io/apimachinery v0.29.2
go: downloading k8s.io/client-go v0.29.2
go: downloading k8s.io/utils v0.0.0-20230726121419-3b25d923346b
go: downloading github.com/go-logr/logr v1.4.1
go: downloading k8s.io/api v0.29.2
go: downloading k8s.io/klog/v2 v2.110.1
go: downloading github.com/gogo/protobuf v1.3.2
go: downloading github.com/google/gofuzz v1.2.0
go: downloading sigs.k8s.io/structured-merge-diff/v4 v4.4.1
go: downloading k8s.io/component-base v0.29.2
go: downloading golang.org/x/net v0.19.0
go: downloading github.com/imdario/mergo v0.3.6
go: downloading github.com/spf13/pflag v1.0.5
go: downloading golang.org/x/term v0.15.0
go: downloading github.com/evanphx/json-patch/v5 v5.8.0
go: downloading github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
go: downloading github.com/evanphx/json-patch v4.12.0+incompatible
go: downloading golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
go: downloading github.com/prometheus/client_golang v1.18.0
go: downloading gomodules.xyz/jsonpatch/v2 v2.4.0
go: downloading k8s.io/apiextensions-apiserver v0.29.2
go: downloading gopkg.in/inf.v0 v0.9.1
go: downloading sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
go: downloading github.com/json-iterator/go v1.1.12
go: downloading gopkg.in/yaml.v2 v2.4.0
go: downloading sigs.k8s.io/yaml v1.4.0
go: downloading golang.org/x/oauth2 v0.12.0
go: downloading golang.org/x/time v0.3.0
go: downloading k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00
go: downloading github.com/google/gnostic-models v0.6.8
go: downloading github.com/golang/protobuf v1.5.3
go: downloading golang.org/x/sys v0.16.0
go: downloading github.com/google/go-cmp v0.6.0
go: downloading github.com/google/uuid v1.3.0
go: downloading github.com/fsnotify/fsnotify v1.7.0
go: downloading github.com/prometheus/client_model v0.5.0
go: downloading github.com/prometheus/common v0.45.0
go: downloading github.com/pkg/errors v0.9.1
go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
go: downloading github.com/modern-go/reflect2 v1.0.2
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading golang.org/x/text v0.14.0
go: downloading gopkg.in/yaml.v3 v3.0.1
go: downloading github.com/go-openapi/jsonreference v0.20.2
go: downloading github.com/go-openapi/swag v0.22.3
go: downloading google.golang.org/protobuf v1.31.0
go: downloading github.com/beorn7/perks v1.0.1
go: downloading github.com/cespare/xxhash/v2 v2.2.0
go: downloading github.com/prometheus/procfs v0.12.0
go: downloading github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0
go: downloading google.golang.org/appengine v1.6.7
go: downloading github.com/go-openapi/jsonpointer v0.19.6
go: downloading github.com/mailru/easyjson v0.7.7
go: downloading github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
go: downloading github.com/josharian/intern v1.0.0
go: downloading github.com/emicklei/go-restful/v3 v3.11.0
INFO Update dependencies:
$ go mod tidy
go: downloading github.com/onsi/ginkgo/v2 v2.14.0
go: downloading github.com/onsi/gomega v1.30.0
go: downloading github.com/stretchr/testify v1.8.4
go: downloading github.com/go-logr/zapr v1.3.0
go: downloading go.uber.org/zap v1.26.0
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading go.uber.org/goleak v1.3.0
go: downloading go.uber.org/multierr v1.11.0
go: downloading gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
go: downloading github.com/kr/pretty v0.3.1
go: downloading github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572
go: downloading golang.org/x/tools v0.16.1
go: downloading github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1
go: downloading github.com/kr/text v0.2.0
go: downloading github.com/rogpeppe/go-internal v1.10.0
Next: define a resource with:
$ kubebuilder create api
[root@aminglinux03 helloworld]#
初始化完成后,目录结构是:
├── cmd
│ └── main.go
├── config
│ ├── 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_binding.yaml
│ ├── auth_proxy_role.yaml
│ ├── auth_proxy_service.yaml
│ ├── kustomization.yaml
│ ├── leader_election_role_binding.yaml
│ ├── leader_election_role.yaml
│ ├── role_binding.yaml
│ └── service_account.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── Makefile
├── PROJECT
└── README.md
2)创建API(CRD + Controller)
先安装make,如果没有make会出问题
yum install -y make
创建API
kubebuilder create api --group webapp --version v1 --kind Guestbook ##打两次y
Create Resource [y/n]
y
reate Controller [y/n]
y
[root@aminglinux03 helloworld]# kubebuilder create api --group webapp --version v1 --kind Guestbook
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/guestbook_types.go
INFO api/v1/groupversion_info.go
INFO internal/controller/suite_test.go
INFO internal/controller/guestbook_controller.go
INFO internal/controller/guestbook_controller_test.go
INFO Update dependencies:
$ go mod tidy
INFO Running make:
$ make generate
mkdir -p /root/go/src/helloworld/bin
Downloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0
go: downloading sigs.k8s.io/controller-tools v0.14.0
go: downloading github.com/spf13/cobra v1.8.0
go: downloading github.com/gobuffalo/flect v1.0.2
go: downloading k8s.io/apiextensions-apiserver v0.29.0
go: downloading k8s.io/apimachinery v0.29.0
go: downloading github.com/fatih/color v1.16.0
go: downloading k8s.io/api v0.29.0
go: downloading github.com/mattn/go-colorable v0.1.13
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading golang.org/x/mod v0.14.0
go: downloading github.com/go-logr/logr v1.3.0
go: downloading golang.org/x/sys v0.15.0
/root/go/src/helloworld/bin/controller-gen-v0.14.0 object:headerFile="hack/boilerplate.go.txt" paths="./..."
Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:
$ make manifests
[root@aminglinux03 helloworld]#
3)构建和部署CRD
make install
[root@aminglinux03 helloworld]# make install
/root/go/src/helloworld/bin/controller-gen-v0.14.0 rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
Downloading sigs.k8s.io/kustomize/kustomize/v5@v5.3.0
go: downloading sigs.k8s.io/kustomize/kustomize/v5 v5.3.0
go: downloading github.com/spf13/cobra v1.7.0
go: downloading sigs.k8s.io/kustomize/api v0.16.0
go: downloading sigs.k8s.io/kustomize/cmd/config v0.13.0
go: downloading sigs.k8s.io/kustomize/kyaml v0.16.0
go: downloading golang.org/x/text v0.13.0
go: downloading golang.org/x/exp v0.0.0-20231006140011-7918f672742d
go: downloading github.com/go-errors/errors v1.4.2
go: downloading k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961
go: downloading github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00
go: downloading github.com/xlab/treeprint v1.2.0
go: downloading github.com/imdario/mergo v0.3.13
go: downloading gopkg.in/evanphx/json-patch.v5 v5.6.0
go: downloading google.golang.org/protobuf v1.30.0
go: downloading github.com/google/go-cmp v0.5.9
go: downloading github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
go: downloading go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5
/root/go/src/helloworld/bin/kustomize-v5.3.0 build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/guestbooks.webapp.aminglinux.com created
[root@aminglinux03 helloworld]#
这个过程会将CRD部署到k8s集群里
我们可以查看CRD
kubectl get crd |grep aminglinux.com
[root@aminglinux03 helloworld]# kubectl get crd |grep aminglinux.com
guestbooks.webapp.aminglinux.com 2024-07-18T20:03:28Z
[root@aminglinux03 helloworld]#
我们可以通过下面命令查看该CRD对应的yaml
$GOPATH/src/helloworld/bin/kustomize build config/crd
4)编辑Controller对应的源码,并编译
如果是生产环境,此时就要去编辑Controller对应的go程序啦,由于我们是体验过程,所以只做简单改动源码文件路径为:
$GOPATH/src/helloworld/internal/controller/guestbook_controller.go
[root@aminglinux03 controller]# ls
guestbook_controller.go guestbook_controller_test.go suite_test.go
[root@aminglinux03 controller]# pwd
/root/go/src/helloworld/internal/controller
[root@aminglinux03 controller]#
vi $GOPATH/src/helloworld/internal/controller/guestbook_controller.go
改动1:
增加一个依赖包fmt
改动2:
找到// : your logic here,在下面增加一行代码,用来打印堆栈信息
fmt.Println("Helloworld.")
改完后,执行
make run
这样就可以将该Controller运行起来了。会显示如下信息
test -s /root/go/src/helloworld/bin/controller-gen &&
/root/go/src/helloworld/bin/controller-gen --version | grep -q
v0.11.3 || \
GOBIN=/root/go/src/helloworld/bin go install
sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.3
/root/go/src/helloworld/bin/controller-gen rbac:roleName=managerrole
crd webhook paths="./..."
output:crd:artifacts:config=config/crd/bases
/root/go/src/helloworld/bin/controller-gen
object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go run ./cmd/main.go
2023-06-07T17:11:37+08:00 INFO controllerruntime.
metrics Metrics server is starting to
listen {"addr": ":8080"}
2023-06-07T17:11:37+08:00 INFO setup starting manager
2023-06-07T17:11:37+08:00 INFO Starting server {"path":
"/metrics", "kind": "metrics", "addr": "[::]:8080"}
2023-06-07T17:11:37+08:00 INFO Starting server {"kind":
"health probe", "addr": "[::]:8081"}
2023-06-07T17:11:37+08:00 INFO Starting
EventSource {"controller": "guestbook", "controllerGroup":
"webapp.aminglinux.com", "controllerKind": "Guestbook", "source":
"kind source: *v1.Guestbook"}
2023-06-07T17:11:37+08:00 INFO Starting
Controller {"controller": "guestbook", "controllerGroup":
"webapp.aminglinux.com", "controllerKind": "Guestbook"}
2023-06-07T17:11:38+08:00 INFO Starting
workers {"controller": "guestbook", "controllerGroup":
"webapp.aminglinux.com", "controllerKind": "Guestbook", "worker
count": 1}
说明:
不要按ctrc c中断,此时需要我们到k8s那边去
5)到k8s创建Guestbook资源的实例
现在kubernetes已经部署了Guestbook类型的CRD,而且对应的controller也已正在运行中,可以尝试创建Guestbook类型的实例了(相当于有了pod的定义后,才可以创建pod);
kubebuilder已经自动创建了一个类型的部署文件:
$GOPATH/src/helloworld/config/samples/webapp_v1_guestbook.yaml,内容如下,很简单,接下来咱们就用这个文件来创建Guestbook实例:
cat > guestbook.yaml <<EOF
apiVersion: webapp.aminglinux.com/v1
kind: Guestbook
metadata:
labels:
app.kubernetes.io/name: guestbook
app.kubernetes.io/instance: guestbook-sample
app.kubernetes.io/part-of: helloworld
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/created-by: helloworld
name: guestbook-sample
spec:
# TODO(user): Add fields here
foo: bar
EOF
应用此yaml
kubectl apply -f guestbook.yaml
回到aminglinux03的终端,可以看到多了一行输出
6)将Controller制作成镜像,并上传到远程仓库
首先需要有一个私有镜像仓库,用来存储编译好的镜像。如果有harbor直接使用harbor最好,如果没有,就是用docker的镜像仓库hub.docker.com,假设你已经有账号了。在编译镜像之前还需要登录到docker的镜像仓库
docker login https://hub.docker.com
我在这里使用的是harbor
docker login https://harbor.yuankeedu.com
给Dockerfile里增加GOPROXY设置
vi Dockerfile #在go mod download上面增加一行
RUN go env -w GOPROXY=https://goproxy.cn
Harbor这里,我已经创建项目aming,然后编译镜像
make docker-build docker-push
IMG=harbor.yuankeedu.com/aming/guestbook:v1
如果编译不过去,那就是网络问题,下载镜像有问题,此时就要做一个代理
按如下方法做代理
mkdir -p /etc/systemd/system/docker.service.d
cat > /etc/systemd/system/docker.service.d/proxy.conf
<<EOF
[Service]
Environment="HTTP_PROXY=http://t.lishiming.net:38089/"
Environment="HTTPS_PROXY=http://t.lishiming.net:38089/"
Environment="NO_PROXY=localhost,127.0.0.1,.yuankeedu.com"
EOF
##注意,上面的地址要换成你自己的,这个代理是我自己设置的,如
果你没有自己的代理,可以用我这个,但不保证一直能使用
systemclt daemon-reload
systemctl restart docerk
harbor那边已经成功上传镜像
7)在k8s里部署该镜像
部署之前,需要把之前设置的代理取消,否则会出错
unset http_proxy
unset https_proxy
修改kube-rbac-proxy镜像地址,因为自带的镜像下载不到
sed -i 's/gcr.io/gcr.lank8s.cn/'
./config/default/manager_auth_proxy_patch.yaml
将harbor项目改为公开,方便下载
在三个k8s node上手动将镜像下载下来
ctr -n k8s.io i pull
harbor.yuankeedu.com/aming/guestbook:v1
部署,这是在aminglinux03上执行的,当前目录还是在
$GOPATH/src/helloworld
make deploy IMG=harbor.yuankeedu.com/aming/guestbook:v1
查看pod
kubectl get po -n helloworld-system
此时,我们再次到k8s里去apply guestbook.yaml
kubectl delete -f guestbook.yaml
kubectl apply -f guestbook.yaml
再去查看helloworld-controller-manager-694854949d-wjkk5的log
kubectl -n helloworld-system logs helloworldcontroller-
manager-694854949d-wjkk5
就能看到最后面的 Helloworld 输出了。
8)清理
到aminglinux03,进入到$GOPATH/src/helloworld,执行
make uninstall
注意,它清理的是CRD资源,Controller并不会清理,要想删除
Controller,直接删除对应ns即可
kubectl delete ns helloworld-system