Kubernetes Operator开发之 一、Opeator SDK helloword

Operator SDK User Guide

Operator capability level

每种operator类型需要不同的能力。对于你的operator为项目选择什么类型时,了解每个项目类型的特性和限制是很重要的。

Phase I Phase II Phase III Phase IV Phase V
基本安装 无缝升级 完整生命周期 深入理解 自动驾驶
自动化应用程序配置和配置管理 支持补丁和小版本升级 应用程序生命周期,存储(备份,故障恢复) metrics、alert、log处理和工作负载分析 水平/横向扩展,自动配置调优,异常检测,调度调优
Helm Helm
Ansible Ansible Ansible Ansible Ansible
GO GO GO GO GO

kubebuilder vs operator-sdk

kubebuilder和operator-sdk支持的Go项目之间没有太大的区别。两者都使用controller-tools和controller-runtime,并且都支持基本相似的go包结构。

他们的不同点:

  • Operator SDK支持Ansible和Helm operator,这样很容易编写operator而不需要go,如果你对Ansible和Helm比较熟悉。
  • Operator SDK集成了Operator生命周期管理(OLM),这是Operator Framework的关键组件,对于2个集群操作很重要,比如管理员在线升级你的operator。
  • Operator SDK包含一个scorecard subcommand,帮助你了解operator是否遵循最佳实践。
  • Operator SDK包含一个e2e测试框架,它简化了针对实际集群测试操作符的工作。
  • Kubebuilder包含一个envtest包,允许operator开发人员使用独立的etcd和apiserver运行简单的测试。
  • Kubebuilder搭建了一个Makefile来帮助用户完成operator的任务(构建、测试、运行、代码生成等);Operator SDK目前使用内置的子命令。每种方法都有优缺点。SDK团队将来可能会迁移到基于makefile的方法。
  • Kubebuilder使用Kustomize构建部署清单;Operator SDK使用带有占位符的静态文件。
  • Kubebuilder最近改进了对许可和CRD转换webhook的支持,但还没有将其加入到SDK中。

Create a new project

operator-sdk new memcached-operator

SDK还支持使用Ansible或Helm开发操作员。Helm使用指南。

Operator project layout

File/Folder s Purpose
cmd 包含文件manager/main.go。operator的main程序。他将实例化一个新的manager,注册所有pkg/apis/...下的自定义资源定义和启动所有在pkg/controllers/...下的controller。
pkg/apis 包含自定义资源(CRD)API的树目录。用户可以展开编辑pkg/apis/<group>/<version>/<kind>_types.go文件,为每种资源类型定义API,并将这些包导入它们的控制器中,以监视这些资源类型。
pkg/controller 此pkg包含控制器实现。用户可以展开编辑pkg/controller/<kind>/<kind>_controller.go文件。定义控制器的协调逻辑来处理指定kind的资源类型。
build 包含Dockerfile编译辑脚本,用于编译operator。
deploy 包含用于注册CRD、设置RBAC和将operator部署为Deployment的各种YAML清单。
go.mod go.sum 描述该操作符的外部依赖项的Go mod清单。
vendor golang vendor目录,包含满足此项目中Go import 的外部依赖项目的本地副本。Go modules 管理vendor目录。除非使用—vendor标志初始化项目,或者go mod vendor在项目根目录中运行,否则此目录将不存在。

我们主要是开发pkg下api和controller。

Manager

main程序为operator里的cmd/manager/main.go, 用于初始化并运行Manager。

Manager将为pkg/api /…下所有自定义资源自动注册schema,和运行pkg/controller/…下的所有controller。

Manager可以限制namespace所有控制器要监视的资源:

mgr, err := manager.New(cfg, manager.Options{Namespace: namespace})

默认情况下这将是operator运行的namespace。如果需要查看所有的namespace,请将namespace设置为空:

mgr, err := manager.New(cfg, manager.Options{Namespace: ""})

也可以使用 MultiNamespacedCacheBuilder 查看一组特定的namespace:

var namespaces []string // List of Namespaces
// Create a new Cmd to provide shared dependencies and start components
mgr, err := manager.New(cfg, manager.Options{
   NewCache: cache.MultiNamespacedCacheBuilder(namespaces),
   MapperProvider:     restmapper.NewDynamicRESTMapper,
   MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
})

默认情况main程序将设置namager的namespace使用在deploy/operator.yaml定义的WATCH_NAMESPACE

Add a new Custom Resource Definition

增加一个名称为Memcached的Custom Resource Definition(CRD) API ,APIVersion cache.example.com/v1alpha1 和 Kind Memcached。

operator-sdk add api --api-version=cache.limingnihao.com/v1alpha1 --kind=Memcached

Define the spce and status

修改Memcached Custom Resource(CR)的spec和status在文件pkg/apis/cache/v1alpha1/memcached_types.go:

type MemcachedSpec struct {
    // Size is the size of the memcached deployment
    Size int32 `json:"size"`
}
type MemcachedStatus struct {
    // Nodes are the names of the memcached pods
    Nodes []string `json:"nodes"`
}

在修改*_types.go文件之后,运行下面命令更新和生成代码:

$ operator-sdk generate k8s
INFO[0000] Running deepcopy code-generation for Custom Resource group versions: [cache:[v1alpha1], ] 
INFO[0008] Code-generation complete.  

Updating CRD mainfests

现在MemcachedSpecMemcachedStatus 有一些 fields 和 possibly annotations, 必须更新API's group 和 kind 与 CRD一致. 所以需要运行下面命令:

$ operator-sdk generate crds
INFO[0000] Running CRD generator.                       
INFO[0000] CRD generation complete.         

storage version

创建 CustomResourceDefinition 时,会在 CustomResourceDefinition spec.versions 列表设置适当的稳定级和版本号。例如v1beta1表示第一个版本尚未稳定。所有自定义资源对象将首先存储在这个版本.

所以你项目的CRD必须精确地指定一个storage version.

如果转换涉及结构变更,并且需要自定义逻辑,转换应该使用 webhook。如果没有结构变更, 则使用 None 默认转换策略,不同版本时只有apiVersion字段有变更。

使用+kubebuilder:storageversion来marker指示API服务器应该使用的存储数据的GVK。该marker应该位于Memcached类型之上的注释中。
(没明白什么意思)

OpenAPI validation

当清单生成时,OpenAPIv3 schema被添加到spec.validation块中的CRD清单中。这个验证块允许Kubernetes在创建或更新Memcached Custom Resource时验证它的属性。

Markers (annotations) 可用于验证您的API配置。这些markers将始终具有+kubebuilder:validation前缀。例如,可以通过添加以下标记来添加enum类型规范:

// +kubebuilder:validation:Enum=Lion;Wolf;Dragon
type Alias string

CRD generationmarker文档讨论了markers在代码中的是用。完整的OpenAPIv3 validation markers请参考这里

运行下面命令,更新CRDdeploy/crds/cache.example.com_memcacheds_crd.yaml.

operator-sdk generate crds

一个生成YAML的例子如下:

spec:
  validation:
    openAPIV3Schema:
      properties:
        spec:
          properties:
            size:
              format: int32
              type: integer

要了解有关Custom Resource Definitions中的OpenAPI v3.0验证模式的更多信息,请参阅Kubernetes文档

Add a new Contrller

添加一个新的Controller到项目,将监视和协调Memcached资源:

$ operator-sdk add controller --api-version=cache.limingnihao.com/v1alpha1 --kind=Memcached

这将在pkg/controller/memcached/...下搭建一个新的Controller实现。
这个例子将生成文件pkg/controller/memcached/memcached_controller.gomemcached_controller.go是具体实现。

示例中的Controller将为所有的Memcached CR执行以下逻辑:

  • 创建一个memcached Deployment如果不存在。
  • 确保这些Deployment数量和Memcached CR spec定义的相同。
  • 使用带有memcached pods名字的状态更新Memcached CR状态。

接下来的两个小节将解释Controller如何监视资源以及如何触发协调循环。

Resources watched by the Controller

查看pkg/controller/memcached/memcached_controller.go的Controller实现,如何监听资源。

第一个监视对象是作为主要资源的Memcached类型。对于每个添加/更新/删除事件,会给那个Memcached对象发送一个调和Request(a namespace/name key):

// Watch for changes to primary resource Memcached
err = c.Watch(&source.Kind{Type: &cachev1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
if err != nil {
    return err
}

下面是对Deployments的监事,但是event handler将每个event映射到Deplyments所有者的Request。本例子中,Memcached对象是Deployment的创建者,这将允许controller将Deployments作为辅助资源监视。

// Watch for changes to secondary resource Pods and requeue the owner Memcached
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
    IsController: true,
    OwnerType:    &cachev1alpha1.Memcached{},
})
if err != nil {
    return err
}

Controller configurations

在初始化controller和生命watch参数时,有很多的配置。更多配置细节请参考controller godocs

  • 通过MaxConcurrentReconciles选项设置控制器的最大并发协调数。默认为1。
_, err := controller.New("memcached-controller", mgr, controller.Options{
   MaxConcurrentReconciles: 2,
   ...
})
  • 使用predicates过滤监视事件。
  • 选择EventHandelr的类型,可以将reconcile loop更改监听事件为reconcile request。对于operator更复杂的primary和secondary资源关系,可以使用EnqueueRequestsFromMapFunc handler,可以将监听事件转换为任务的reconcile request。EnqueueRequestForObject队列的一个请求包含事件源对象的Name和Namespace。

Reconcile loop

每个Controller都有一个Reconciler对象和一个实现了reconcile循环的reconcile()方法。reconcile loop通过Request argument查看主资源对象的Namespace/Name key,Memcached,从缓存:

// Reconcile读取Memcached对象的集群状态,并根据读取的状态和Memcached. spec中的内容进行更改
// 如果返回error为非空或Result.Requeue为true,控制器将再次请求处理Request,否则在完成后将从队列中删除。
func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) {
  // Lookup the Memcached instance for this reconcile request
  memcached := &cachev1alpha1.Memcached{}
  err := r.client.Get(context.TODO(), request.NamespacedName, memcached)
  ...
}

根据返回值,Result和error,Request将重新请求,然后再次触发Reconcile loop:

// Reconcile successful - don't requeue
return reconcile.Result{}, nil

// Reconcile failed due to error - requeue
return reconcile.Result{}, err

// Requeue for any reason other than error
return reconcile.Result{Requeue: true}, nil

你还可以设置Result.RequeueAfter,设置在一些时间之后重新请求Request。

import "time"

// Reconcile for any reason than error after 5 seconds
return reconcile.Result{RequeueAfter: time.Second*5}, nil

Note: 返回带RequeueAfter的Result,是定期调整CR的方法。

For a guide on Reconcilers, Clients, and interacting with resource Events, see the Client API doc.

Build and run the operator

在运行operator之前,CRD必须在 Kubernetes apiserver注册:

$ kubectl create -f deploy/crds/cache.limingnihao.com_memcacheds_crd.yaml

然后有两种方法,运行operator:

  • 作为Kubernetes集群内部的Deployment。
  • 集群外部的一个Go程序。

1. Run as a Deployment inside the cluster

Note:operator-sdk buikd调用docker build,或者是buildah bud。如果使用buildah则跳过operator-sdk build的跳过下面的说明。如果使用docker确保docker守护进程正在运行,并且可以在没有sudo的情况下运行docker客户机。您可以通过运行docker version来检查,

Note:存在vendor/目录,运行

$ go mod vendor

构建memcached-operator image发布和注册:

$ operator-sdk build quay.io/$USERNAME/memcached-operator:v0.0.1
$ docker login quay.io
$ docker push quay.io/$USERNAME/memcached-operator:v0.0.1

# Update the operator manifest to use the built image name (if you are performing these steps on OSX, see note below)
$ sed -i "s|REPLACE_IMAGE|quay.io/$USERNAME/app-operator|g" deploy/operator.yaml
# On OSX use:
$ sed -i "" "s|REPLACE_IMAGE|quay.io/$USERNAME/app-operator|g" deploy/operator.yaml

或者只发布到本地
$ operator-sdk build memcached-operator:v0.0.1

Deployment清单在deploy/operator.yaml中生成。请确认更新deployment imageREPLACE_IMAGE,因为默认只是个占位符。

containers:
  - name: memcached-operator
    # Replace this with the built image name
    image: REPLACE_IMAGE
    imagePullPolicy: IfNotPresent

安装RBAC和发布memcached-operator:

kubectl create -f deploy/service_account.yaml
kubectl create -f deploy/role.yaml
kubectl create -f deploy/role_binding.yaml
kubectl create -f deploy/operator.yaml
kubectl create -f deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml

2.Run locally outside the cluster

此方法在开发周期中是首选的,以便更快地部署和测试。

在环境变量中设置operator的名称:

export OPERATOR_NAME=memcached-operator

使用$HOME/.kube/config中的默认Kubernetes配置文件在本地运行该operator:

$ operator-sdk run --local --namespace=default
2018/09/30 23:10:11 Go Version: go1.10.2
2018/09/30 23:10:11 Go OS/Arch: darwin/amd64
2018/09/30 23:10:11 operator-sdk Version: 0.0.6+git
2018/09/30 23:10:12 Registering Components.
2018/09/30 23:10:12 Starting the Cmd.

Create a Memcached CR

创建示例Memcached的CR使用deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml`生成:

$ cat deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
  name: "example-memcached"
spec:
  size: 3

$ kubectl apply -f deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml

确保memcache -operator为CR创建部署:

$ kubectl get deployment
NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
memcached-operator       1         1         1            1           2m
example-memcached        3         3         3            3           1m

检查pod和CR状态,确认memcached pods的状态变化:

Update the size

在memcached CR 将spec.size字段从3改成4:

apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
  name: "example-memcached"
spec:
  size: 4

$ kubectl apply -f deploy/crds/cache.example.com_v1alpha1_memcached_cr.yaml

确认operator的deployment数量发生改变:

kubectl get deployment

cleanup

清除所有resources:

kubectl delete -f deploy/crds/cache.limingnihao.com_v1alpha1_memcached_cr.yaml
kubectl delete -f deploy/operator.yaml
kubectl delete -f deploy/role_binding.yaml
kubectl delete -f deploy/role.yaml
kubectl delete -f deploy/service_account.yaml

Advanced Topics

Manage CR status conditions

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

推荐阅读更多精彩内容