构建Operator项目

环境准备

Go准备

下载安装包

下载地址:
(1)go官网:https://go.dev/dl/
(2)go中文社区:https://studygolang.com/dl

支持下载windows、mac OS、Linux等操作系统的二进制文件,下载即可使用
go1.17.12版本下载页面截图
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
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/
kubeconfig文件

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下载安装
操作使用

使用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]

构建operator项目

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创建结构

    新增目录中核心代码是该文件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)
}

Operator编码

1、CRD设计
2、业务逻辑设计编码
3、部署运行
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容