关于我们
现在的开源软件多如牛毛,技术人无时无刻不在与开源软件打交道,我们在选择开源软件时会非常看重它的一个特性——可扩展性。包揽包干的框架我们固然喜欢,但是这个世界太复杂,总有满足不了的场景,这时候框架提供扩展性就是良心操作了。如果扩展机制提供的优雅高明,它不火就真没天理了。
本文来介绍下K8S的扩展机制,只需要简单几步,不需要动一行原有代码,就可以实现一个扩展功能。
自我介绍机制,给K8S一个机会“介绍”自己,了解之后才能“接纳”。
这个机制就是CRD(Custom Resource Definition)机制,K8S里有各种各样的资源,我们常见的例如 Depoyment、Pod等都是内置资源。CRD就是提供扩充资源对象的接口,在我们实现自己的业务逻辑需要扩展功能时,只需要定义相关的领域对象即可。简单示例如下:
\# crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: mes.tigerhou.k8s.io spec: group: tigerhou.k8s.io version: v1 names: kind: me plural: mes scope: Namespaced
如上,我们声明了一个简单命名空间级别的CRD,**相当于在K8S注册了一个身份**。接下来还要声明**我如何成为我**:
\# me.yaml apiVersion: tigerhou.k8s.io/v1 kind: Me metadata: name: simplename spec: name: "tigerhou" location: "beijing" 根据已经定义好的yaml文件执行以下命令: ➜ k8s kubectl apply -f crd.yaml customresourcedefinition.apiextensions.k8s.io "mes.tigerhou.k8s.io" created ➜ k8s kubectl apply -f me.yaml me.tigerhou.k8s.io "simplename" created 下面执行常用的get/describe命令 ➜ k8s kubectl get me NAME AGE simplename 30s ➜ k8s kubectl describe me simplename Name: simplename Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"tigerhou.k8s.io/v1","kind":"me","metadata":{"annotations":{},"name":"simplename","namespace":"default"},"spec":{"location":"beijing","na... API Version: tigerhou.k8s.io/v1 Kind: me Metadata: Creation Timestamp: 2019-07-20T22:13:53Z Generation: 1 Resource Version: 2031360 Self Link: /apis/tigerhou.k8s.io/v1/namespaces/default/mes/simplename UID: a8ed2b60-ab3b-11e9-9498-fa163e383d43 Spec: Location: beijing Name: tigerhou Events: <none>
可以看到K8S已经接纳了me,可以像默认资源一样执行一些操作了,第一步完成。
有了身份之后以实现自我价值,还能做什么?
现在只是个身份而已,类似面向对象编程里类的定义,光有类的定义其实没什么意义,真实的业务场景里还是要有操作、要有方法定义。这些在K8S中对应的就是自定义控制器,控制器听上去是个复杂的东西,示意图如下:
我们定义好的资源都会存在Etcd中,控制器就像一个永动机一样不厌其烦地从数据库中取出最新状态的资源,然后跟现有的资源状态做对比,如果不一样就做相应的处理。
看上去自己用代码实现上面这些逻辑让人难以接受,如果是从头编写代码也确实很复杂,不过K8S有用于代码自动生成的代码生成器。这个逻辑就是提供一个模版(官方模版:https://github.com/kubernetes/sample-controller.git),你只要实现一小部分代码即可。这部分代码比较多,限于篇幅这里简略部分代码。
├── controller.go
├── crd
│ └── crd.yaml
├── example
│ └── me..yaml
├── main.go
└── pkg
└── apis
└── tigerhou
├── register.go
└── v1
├── doc.go
├── register.go
└── **types.go**
基于第一部分的定义,要有相应的代码实现,这样才能针对这些领域对象的定义做**可编程扩展**。这部分的核心在types.go中定义:
package v1 ... // +genclient // +genclient:noStatus // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Me describes a crd resource type Me struct { metav1.ObjectMeta `json:"metadata,omitempty"` Spec mespec `json:"spec"` } // mespec is the spec for a me resource type mespec struct { name string `json:"name"` location string `json:"location"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // MeList is a list of me resources type MeList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata"` Items []Me `json:"items"` }
有了这个类型定义后,就可以采用代码生成工具生成代码:
\# 安装 k8s.io/code-generator
➜ go get -u k8s.io/code-generator/...
➜ cd $GOPATH/src/k8s.io/code-generator
\# 执行代码自动生成,其中 pkg/client 是生成目标目录,pkg/apis 是类型定义目录
➜ ./generate-groups.sh all "/pkg/client" "/pkg/apis"
生成后代码目录如下:
├── controller.go
├── crd
│ └── crl.yaml
├── example
│ └──me.yaml
├── main.go
└── pkg
├── apis
│ └── tigerhou
│ ├── constants.go
│ └── v1
│ ├── doc.go
│ ├── register.go
│ ├── types.go
│ └── zz_generated.deepcopy.go
└── client
├── clientset
├── informers
└── listers
**代码生成的核心是生成针对新添加资源对象的客户端操作工具**,有了这个client,后面在自定义控制器中就可以便捷地对该资源对象进行各种操作。
关于自定义控制器这部分代码比较多,而且需要先了解控制器的工作原理才能很好地理解,限于篇幅会在后面的文章中介绍。
写在最后:
我们这里简单介绍了K8S基于CRD的扩展机制,这是K8S对外提供的可编程模式接口,我们可以基于这个模式实现自己的业务逻辑。目前知名的服务治理框架Istio、复杂有状态应用的管理框架Operator等都是基于这种机制建立的。正是这种良好的可编程扩展机制催生了整个CNCF社区生态的繁荣,催生了基于K8S的各种创新项目。我们也受益于这种扩展机制,在给客户提供产品和服务能力时有了强大的技术支持。当现有的功能不能满足客户需求时,我们就可以通过这种编程接口进行二次开发,以K8S为依托,构建满足客户实际场景需求的产品能力。
Copyright ©2011 - 2016 北京百度云途腾科技有限责任公司 京ICP备14057888号 | 技术支持:因脉科技
北京市石景山区苹果园路2号院1号楼通景大厦602 010 - 5213 8045