环境准备
Go准备
下载安装包
支持下载windows、mac OS、Linux等操作系统的二进制文件,下载即可使用下载地址:
(1)go官网:https://go.dev/dl/
(2)go中文社区:https://studygolang.com/dl
linux系统下载安装
1、下载tar包
[root@node1 go]# wget https://go.dev/dl/go1.17.12.linux-amd64.tar.gz
[root@node1 go]# ls
go1.17.12.linux-amd64.tar.gz
2、解压并配置环境变量,将go的bin目录添加到PATH环境变量中
(1)解压:tar -zxvf go1.17.12.linux-amd64.tar.gz
(2)配置环境变量:vi /etc/profile,追加如下内容(GOROOOT为安装目录,GOPATH为工作目录)
export GOROOT=/opt/dev/go/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=/opt/dev/go/work
3、验证是否安装成功
(1)刷新配置立即生效:source /etc/profile
(2)查看当前版本:go version
(3)查看go环境变量:go env
4、配置国内模块代理
vi /etc/profile
export GOPROXY=https://goproxy.cn(或go env -w GOPROXY=https://goproxy.cn,direct)
source /etc/profile
5、编写demo代码进行测试
# 测试代码
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
# 运行:go run demo.go
[root@node1 project]# go run demo.go
Hello, World!
kubectl准备
下载安装
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
配置使用
1、配置可执行权限
chmod +x ./kubectl
2、将kubectl拷贝到全局可访问的目录
cp ./kubectl /usr/local/bin/kubectl
kubectl --help
3、新建~/.kube/目录,并将可访问的具有k8s环境的机器上的~/.kube/目录下的config文件,复制到该机器的~/.kube/目录下,此时就可以通过该机器使用kubectl命令访问kubernetes
mkdir ~/.kube/
kubebuilder准备
下载安装
注意下载的版本需要跟安装的go版本匹配:https://go.kubebuilder.io/dl
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 init创建Operator项目。帮助信息详见kubebuilder init --help
[root@node1 demo-operator]# kubebuilder init --help
Initialize a new project including the following files:
- a "go.mod" with project dependencies
- a "PROJECT" file that stores project configuration
- a "Makefile" with several useful make targets for the project
- several YAML files for project deployment under the "config" directory
- a "main.go" file that creates the manager that will run the project controllers
Usage:
kubebuilder init [flags]
Examples:
# Initialize a new project with your domain and name in copyright
kubebuilder init --plugins go/v3 --domain example.org --owner "Your name"
# Initialize a new project defining a specific project version
kubebuilder init --plugins go/v3 --project-version 3
Flags:
--component-config create a versioned ComponentConfig file, may be 'true' or 'false'
--domain string domain for groups (default "my.domain")
--fetch-deps ensure dependencies are downloaded (default true)
-h, --help help for init
--license string license to use to boilerplate, may be one of 'apache2', 'none' (default "apache2")
--owner string owner to add to the copyright
--project-name string name of this project
--project-version string project version (default "3")
--repo string name to use for go module (e.g., github.com/user/repo), defaults to the go package of the current working directory.
--skip-go-version-check if specified, skip checking the Go version
Global Flags:
--plugins strings plugin keys to be used for this subcommand execution
--plugins,指定生成代码的插件,默认使用"go.kubebuilder.io/v3"
--project-version 支持的项目版本,有2,3默认3
--repo module path,就是go mod init 指定的go module的名称
--owner,operator所有者,一般填写开发者邮箱
--domain组织名称,用于API Group等。参数必填,相当于kubernetes里面的group。创建Operator项目的位置可以在GOPATH目录也可以在使用go mod init初始化后的目录(需要打开go mod,GO111MODULE="on"
)。创建过程中golang可能会下载安装包,这时需要保证网络畅通。如果出现下载k8s.io相关包失败情况需要检查当前网络环境是否有访问国外网络的能力。
1、go mod创建项目
(1)mkdir demo-operator && cd demo-operator
(2)go mod init demo-operator
(3)kubebuilder init --domain cloud.com [--owner "gzx" --skip-go-version-check]
2、查看项目结构
创建完成后只有基础的配置文件和main.go文件。当前Operator可以编译、安装,但没有CRD相关资源,还需要进一步添加API文件和控制器文件
tree命令没有时可以使用yum install tree进行安装
[root@node1 demo-operator]# tree
.
├── 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
├── main.go
├── Makefile
├── PROJECT
└── README.md
结构说明:
1)config/default:基于kustomize制作的配置文件,为controller提供标准配置,可按自己需要修改
2)config/manager:一些和manager有关的细节配置,例如镜像的资源限制
3)config/rbac:顾名思义,如果像限制operator在kubernetes中的操作权限,就要通过rbac来做精细的权限配置了,这里面就是权限配置的细节
4)go.mod:module的配置文件,里面已经填充了几个重要依赖
5)Makefile:非常重要的工具,编译构建、部署、运行都会用到
6)PROJECT:kubebuilder工程的元数据,在生成各种API的时候会用到这里面的信息
3、创建API
- 构建过程中会出现是否创建资源和控制器的提示:创建资源表示kubebuilder会创建
GVK(Group Version Kind)
相关代码模板和CRD配置清单。 - 创建的GVK信息由命令参数
--group
、--version
和--kind
组成,group表示分组信息,version表示资源版本管理,kind是资源类型,资源创建过程中包括资源深拷贝代码和资源注册代码。 - 是否创建控制器表示kubebuilder是否创建GVK控制器注册代码和资源调谐代码,注册代码会使用controller-runtime包的API构建控制器注册代码,把控制器注册到控制器管理组件中,调谐函数是控制器业务逻辑处理的地方,具体业务逻辑需要用户完善。
创建过程中如果报错:failed to create API: unable to run post-scaffold tasks of "base.go.kubebuilder.io/v3": exit status 2
可能是缺少gcc编译器,需要安装:yum install gcc
# Operator的API,通过该资源/API实现组件配置和管理。
# 注意,Kind资源类型首字母需要大写
[root@node1 demo-operator]# kubebuilder create api --group operator --version v1 --kind Demo
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
api/v1/demo_types.go
controllers/demo_controller.go
Update dependencies:
$ go mod tidy
Running make:
$ make generate
mkdir -p /opt/dev/go/project/demo-operator/bin
test -s /opt/dev/go/project/demo-operator/bin/controller-gen || GOBIN=/opt/dev/go/project/demo-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2
go: downloading sigs.k8s.io/controller-tools v0.9.2
go: downloading github.com/spf13/cobra v1.4.0
go: downloading github.com/gobuffalo/flect v0.2.5
go: downloading k8s.io/apiextensions-apiserver v0.24.0
go: downloading k8s.io/apimachinery v0.24.0
go: downloading golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717
go: downloading github.com/fatih/color v1.12.0
go: downloading k8s.io/api v0.24.0
go: downloading gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
go: downloading k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
go: downloading k8s.io/klog/v2 v2.60.1
go: downloading sigs.k8s.io/structured-merge-diff/v4 v4.2.1
go: downloading github.com/mattn/go-colorable v0.1.8
go: downloading github.com/mattn/go-isatty v0.0.12
go: downloading golang.org/x/sys v0.0.0-20220209214540-3681064d5158
go: downloading golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
go: downloading sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2
go: downloading github.com/go-logr/logr v1.2.0
go: downloading golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
go: downloading golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
/opt/dev/go/project/demo-operator/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
# 【可选】也可以为Operator创建Config API,通过该资源/API实现组件配置和管理
# kubebuilder create api --group config --version v1 --kind Demo
# Operator管理的其它API,产品和公共基础组件自身需要创建
# kubebuilder create api --group demo --version v1 --kind Xxx
4、构建CR完成后需要根据提示执行make manifests
命令完成CR调整流程
- 构建过程选择创建资源和创建控制器,kubebuilder会在项目中新增Demo资源的描述文件demo_types.go,里面包括Demo相关的基础结构体,同时也会更新资源深拷贝文件zz_generated.deepcopy.go内容,提供Demo资源的深拷贝方法,新增Demo资源的CRD和RBAC配置文件,最后控制器相关的代码也会创建出来。
[root@node1 demo-operator]# make manifests
test -s /opt/dev/go/project/demo-operator/bin/controller-gen || GOBIN=/opt/dev/go/project/demo-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2
/opt/dev/go/project/demo-operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
[root@node1 demo-operator]#
5、安装到K8s集群中
(1)安装
// 安装API/CRD到集群中
[root@node1 demo-operator]# make install
test -s /opt/dev/go/project/demo-operator/bin/controller-gen || GOBIN=/opt/dev/go/project/demo-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2
/opt/dev/go/project/demo-operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/opt/dev/go/project/demo-operator/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/demoes.operator.cloud.com created
// 安装成功后,可通过api-versions查看该GV
[root@node1 demo-operator]# kubectl api-versions | grep operator
operator.ccos.io/v1
operator.cloud.com/v1
(1)卸载,从集群中将KV资源移除
[root@node1 demo-operator]# make uninstall
test -s /opt/dev/go/project/demo-operator/bin/controller-gen || GOBIN=/opt/dev/go/project/demo-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2
/opt/dev/go/project/demo-operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/opt/dev/go/project/demo-operator/bin/kustomize build config/crd | kubectl delete --ignore-not-found=false -f -
customresourcedefinition.apiextensions.k8s.io "demoes.operator.cloud.com" deleted
[root@node1 demo-operator]# kubectl api-versions | grep operator
[root@node1 demo-operator]#
make所有命令
[root@node1 demo-operator]# make help
Usage:
make <target>
General
help Display this help.
Development
manifests Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
generate Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
fmt Run go fmt against code.
vet Run go vet against code.
test Run tests.
Build
build Build manager binary.
run Run a controller from your host.
docker-build Build docker image with the manager.
docker-push Push docker image with the manager.
docker-buildx Build and push docker image for the manager for cross-platform support
Deployment
install Install CRDs into the K8s cluster specified in ~/.kube/config.
uninstall Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
deploy Deploy controller to the K8s cluster specified in ~/.kube/config.
undeploy Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
Build Dependencies
kustomize Download kustomize locally if necessary.
controller-gen Download controller-gen locally if necessary.
envtest Download envtest-setup locally if necessary.
Operator开发
项目结构
1、CRD结构(数据核心)
- CRD的数据结构,是对实际值和期望值的定义。而API是Operator的核心,也是设计整个CRD的关键
- 创建API的命令为
kubebuilder create api --group cloud.com --version v1 --kind Demo
,创建成功后会新增一些目录,如下,这些都是为crd服务
新增目录中核心代码是该文件api/v1/demo_types.go
中的数据结构的部分,如下: -
Demo struct
结构体定义了CRD的数据结构 -
DemoList
是针对Demo单个资源的对象集合
// DemoSpec defines the desired state of Demo
type DemoSpec struct {
libraryoperatorv1.OperatorSpec `json:",inline"`
}
// DemoStatus defines the observed state of Demo
type DemoStatus struct {
libraryoperatorv1.OperatorStatus `json:",inline"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Demo is the Schema for the demoes API
type Demo struct {
// metav1.TypeMeta:保存了资源的GVK(Group、Version、Kind)
metav1.TypeMeta `json:",inline"`
// metav1.ObjectMeta:保存了资源对象的名称和namespace
metav1.ObjectMeta `json:"metadata"`
// 期望状态,例如deployment在创建时指定pod的副本数
Spec DemoSpec `json:"spec"`
// 实际状态,例如deployment在创建时副本数没有达到预期值,其他还在创建中
Status DemoStatus `json:"status"`
}
//+kubebuilder:object:root=true
// DemoList contains a list of Demo
type DemoList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Demo `json:"items"`
}
demo_types.go所在目录下还有两个文件,这俩文件一般固定写法,无需修改
(1)groupversion_info.go
定义了GV,以及初始化注册到schema时要用到的实例SchemeBuilder
(2)zz_generated.deepcopy.go
用于实现实例的深拷贝
2、Controller结构(业务核心)
在operator开发过程中,尽管业务逻辑各不相同,但有两个共性:
- Status(实际状态)是由具体业务确定的,根据业务代码执行自定义的逻辑算出来的
- 核心业务的目标,就是是确保Status与Spec达成一致
而Controller的功能就是核心业务逻辑的具体实现,如demo中的demo_controller.go
文件中的代码就是controller,其包含如下三部分
(1)数据结构,定义了操作资源对象时用到的客户端工具client.Client、Kind和数据结构的关系Scheme。除了默认生成的,我们还可以定义其他数据,如日志工具logr.Logger
// DemoReconciler reconciles a Demo object
type DemoReconciler struct {
client.Client
Scheme *runtime.Scheme
}
(2)Reconcile
方法,调谐函数是controller的核心,是控制器业务逻辑处理的地方,具体业务逻辑需要用户完善(大部分代码都是写在这里面,主要做的事情就是获取status,保证status和spec达成一致)
// Reconcile方法前面的这些+kubebuilder:rbac前缀的注释,这些是用来确保controller在运行时有对应的资源操作权限
//+kubebuilder:rbac:groups=operator.cloud.com,resources=demoes,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=operator.cloud.com,resources=demoes/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=operator.cloud.com,resources=demoes/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Demo object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.0/pkg/reconcile
func (r *DemoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
// TODO(user): your logic here
return ctrl.Result{}, nil
}
(3)SetupWithManager
方法,在main.go中调用,指定了Demo这个资源的变化会被manager监控,从而触发Reconcile方法
// SetupWithManager sets up the controller with the Manager.
func (r *DemoReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&operatorv1.Demo{}).
Complete(r)
}