技术分享|当我谈Kubernetes扩展性时,我谈些什么?(一)

现在的开源软件多如牛毛,技术人无时无刻不在与开源软件打交道,我们在选择开源软件时会非常看重它的一个特性——可扩展性。包揽包干的框架我们固然喜欢,但是这个世界太复杂,总有满足不了的场景,这时候框架提供扩展性就是良心操作了。如果扩展机制提供的优雅高明,它不火就真没天理了。

本文来介绍下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:
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:

可以看到K8S已经接纳了me,可以像默认资源一样执行一些操作了,第一步完成。

有了身份之后以实现自我价值,还能做什么?

现在只是个身份而已,类似面向对象编程里类的定义,光有类的定义其实没什么意义,真实的业务场景里还是要有操作、要有方法定义。这些在K8S中对应的就是自定义控制器,控制器听上去是个复杂的东西,示意图如下:

扫描二维码关注公众号,回复: 11465000 查看本文章

我们定义好的资源都会存在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为依托,构建满足客户实际场景需求的产品能力。

猜你喜欢

转载自blog.csdn.net/T2Cloud/article/details/102474947