从零开始构建operator(一)构建新工程

引言

kubernetes已是云原生领域事实上的标准,operator作为kubernetes的扩展插件应用也越来越多,几乎所有运行与kubernetes之上的应用程序大都提供相应的operator。本文将描述了如何从零开始构建一个operator的开发过程,其中脚手架框架使用的是operator SDK。

前置条件

创建一个新工程

operator SDK提供了命令行工具,帮助我们创建工程以及其他需要的资源。

mkdir -p $HOME/code/znbase-operator
cd $HOME/code/znbase-operator
# we'll use a domain of inspur.com
# so all API groups will be <group>.inspur.com
operator-sdk init --domain inspur.com --repo github.com/inspur/znbase-operator

其中:

  • domain:domain将作为API组的后缀,格式为:<group>.<domain>
  • repo: 本工程的golang包名,如果当前工作目录不是$GOPATH/src,该值不能省略;

当看到如下信息,说明已创建成功:

operator-sdk init --domain inspur.com --repo github.com/inspur/znbase-operator
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.8.3
Update dependencies:
$ go mod tidy
Next: define a resource with:
$ operator-sdk create api

工程目录结构

生成的工程目录结构如下:

├── config
│   ├── default
│   ├── manager
│   ├── manifests
│   ├── prometheus
│   ├── rbac
│   └── scorecard
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

其中比较重要的文件和目录如下:

  • config: 目录下是所有的yaml配置文件,包括创建CRD、role、监控、controller相关的deployment和service等。
  • Dockerfile:用于生成docker镜像的文件,使用的基础镜像国内用户可能无法下载,需要替换为其他可下载镜像;
  • Makefile:编译控制文件,内部定义了所以的编译、部署命令;
  • main.go:应用程序入口文件;

如需详细信息,请查看官方文档:kubebuilder项目布局

至此,我们已经构建了一个最简单的可运行operator项目。

编译

执行make build命令,显示如下:

make build

/home/chensj/code/znbase-operator/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go build -o bin/manager main.go

生成可执行文件bin/manager,该文件是可以直接运行的,当然这个operator什么事也没干。

在goland中调试

点击run -> Edit Configurations…,然后点击“+”添加一个go build实例,配置项保持默认即可。

点击run -> Debug '…'开始进入调试模式。

需要注意的是在调试带有webhook的operator时在本地需要有TLS证书,所以建议初次调试时最好不要带webhook,当熟悉了operator开发模式后再调试webhook。

main.go解析

main.go是operator的入口文件,整个文件包括注释不到100行,很简洁。接下来,我们看看main里都做了哪些事。

解析启动参数

func main() {
	...
	flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
	flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
	flag.BoolVar(&enableLeaderElection, "leader-elect", false,"Enable leader election for controller manager.")

	opts.BindFlags(flag.CommandLine)
	flag.Parse()
    ...
}

首先看到解析启动参数metrics-bind-address、health-probe-bind-address和leader-elect。分别代表采集监控指标地址、健康检查地址和operator是否是高可用部署,一般情况下保持默认即可。

创建Manager对象

manager是operator的核心对象,其定义位于sigs.k8s.io/controller-runtime@v0.8.3/pkg/manager/manager.go,其内部维护了对kubernetes集群的操作client,以及operator运行所需的资源。在main.go中创建manager对象的代码如下:

func main() {
	...
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
		Scheme:                 scheme,
		MetricsBindAddress:     metricsAddr,
		Port:                   9443,
		HealthProbeBindAddress: probeAddr,
		LeaderElection:         enableLeaderElection,
		LeaderElectionID:       "308d9f16.inspur.com",
	})
    ...

看起来比较复杂,主要是通过ctrl.Options配置对象向构造函数里传递不同的参数,以此控制manager的行为。ctrl.Options的成员很多,但一般情况下这段代码保持原样即可,如需修改可以通过源码查看其成员的说明,这里不在详述。

添加健康检查handler

这段代码的作用是添加健康检查点的处理函数,这里使用的是healthz包提供的默认方法,一般情况下不需要修改。

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
		setupLog.Error(err, "unable to set up health check")
		os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
	setupLog.Error(err, "unable to set up ready check")
	os.Exit(1)
}

启动manager

这段代码的作用是启动operator,之后operator将一直运行下去。

if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}

至此我们完成最简单的operator创建工作,该operator是在本地运行,但是什么也没干。接下来我们给这个operator添加新的API和controller,让它真正工作起来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值