环境:

  1. golang 1.15 依赖包采用go module

实例:现在往 Kubernetes 添加一个名叫 Network 的 API 资源类型。它的作用是,一旦用户创建一个 Network 对象,那么 Kubernetes 就应该使用这个对象定义的网络参数,调用真实的网络插件,为用户创建一个真正的“网络”。这样,将来用户创建的 Pod,就可以声明使用这个“网络”了。

结构如下:

  1. MacBook-Pro kubernetes % tree k8s-controller-custom-resource -L 5
  2. ├── go.mod
  3. ├── hack
  4.    ├── boilerplate.go.txt
  5.    ├── tools.go
  6.    └── update-codegen.sh
  7. ├── pkg
  8.    └── apis
  9.    └── samplecrd
  10.    ├── register.go
  11.    └── v1
  12.    ├── doc.go
  13.    ├── register.go
  14.    └── types.go

1、初始化项目

  1. #创建目录
  2. $ mkdir k8s-controller-custom-resource && cd k8s-controller-custom-resource
  3. #初始化项目,生成go.mod文件
  4. $ go mod init k8s-controller-custom-resource
  5. # 获取依赖
  6. $ go get k8s.io/apimachinery@v0.0.0-20190425132440-17f84483f500
  7. $ go get k8s.io/client-go@v0.0.0-20190425172711-65184652c889
  8. $ go get k8s.io/code-generator@v0.0.0-20190419212335-ff26e7842f9d

2、初始化crd资源类型

在初始化了项目后,需要建立好自己的crd struct,然后使用code-generator生成我们的代码.

  1. mkdir -p pkg/apis/samplecrd/v1 && cd pkg/apis/samplecrd

其中,pkg/apis/samplecrd 就是 API 组的名字,v1 是版本。

然后,我在 pkg/apis/samplecrd 目录下创建了一个 register.go 文件,用来放置后面要用到的全局变量。这个文件的内容如下所示:


  1. package samplecrd
  2. const (
  3. GroupName = "samplecrd.k8s.io"
  4. Version = "v1"
  5. )

接着,我需要在 pkg/apis/samplecrd/v1 目录下添加一个 doc.go 文件(Golang 的文档源文件)。这个文件里的内容如下所示:


  1. // +k8s:deepcopy-gen=package
  2. // +groupName=samplecrd.k8s.io
  3. package v1

在这个文件中,你会看到 +<tag_name>[=value]格式的注释,这就是 Kubernetes 进行代码生成要用的 Annotation 风格的注释。其中,+k8s:deepcopy-gen=package 意思是,请为整个 v1 包里的所有类型定义自动生成 DeepCopy 方法;而+groupName=samplecrd.k8s.io,则定义了这个包对应的 API 组的名字。可以看到,这些定义在 doc.go 文件的注释,起到的是全局的代码生成控制的作用,所以也被称为 Global Tags。

接下来,我需要添加 types.go 文件。顾名思义,它的作用就是定义一个 Network 类型到底有哪些字段(比如,spec 字段里的内容)。这个文件的主要内容如下所示:

  1. package v1
  2. import (
  3. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  4. )
  5. // +genclient
  6. // +genclient:noStatus
  7. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
  8. // Network describes a Network resource
  9. type Network struct {
  10. // TypeMeta is the metadata for the resource, like kind and apiversion
  11. metav1.TypeMeta `json:",inline"`
  12. // ObjectMeta contains the metadata for the particular object, including
  13. // things like...
  14. // - name
  15. // - namespace
  16. // - self link
  17. // - labels
  18. // - ... etc ...
  19. metav1.ObjectMeta `json:"metadata,omitempty"`
  20. // Spec is the custom resource spec
  21. Spec NetworkSpec `json:"spec"`
  22. }
  23. // NetworkSpec is the spec for a Network resource
  24. type NetworkSpec struct {
  25. // Cidr and Gateway are example custom spec fields
  26. //
  27. // this is where you would put your custom resource data
  28. Cidr string `json:"cidr"`
  29. Gateway string `json:"gateway"`
  30. }
  31. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
  32. // NetworkList is a list of Network resources
  33. type NetworkList struct {
  34. metav1.TypeMeta `json:",inline"`
  35. metav1.ListMeta `json:"metadata"`
  36. Items []Network `json:"items"`
  37. }

最后,我需要再编写一个 pkg/apis/samplecrd/v1/register.go 文件。

  1. package v1
  2. import (
  3. "k8s-controller-custom-resource/pkg/apis/samplecrd"
  4. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  5. "k8s.io/apimachinery/pkg/runtime"
  6. "k8s.io/apimachinery/pkg/runtime/schema"
  7. )
  8. // GroupVersion is the identifier for the API which includes
  9. // the name of the group and the version of the API
  10. var SchemeGroupVersion = schema.GroupVersion{
  11. Group: samplecrd.GroupName,
  12. Version: samplecrd.Version,
  13. }
  14. // addKnownTypes adds our types to the API scheme by registering
  15. // Network and NetworkList
  16. func addKnownTypes(scheme *runtime.Scheme) error {
  17. scheme.AddKnownTypes(
  18. SchemeGroupVersion,
  19. &Network{},
  20. &NetworkList{},
  21. )
  22. // register the type in the scheme
  23. metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
  24. return nil
  25. }

这样,Network 对象的定义工作就全部完成了。可以看到,它其实定义了两部分内容:

第一部分是,自定义资源类型的 API 描述,包括:组(Group)、版本(Version)、资源类型(Resource)等。

第二部分是,自定义资源类型的对象描述,包括:Spec、Status 等。

3、使用 Kubernetes 提供的代码生成工具,为上面定义的 Network 资源类型自动生成 clientset、informer 和 lister。

生成代码主要为下一章的controller使用。其中,clientset 就是操作 Network 对象所需要使用的客户端,而 informer 和 lister 这两个包的主要功能,我会在下一篇文章中重点讲解。这个代码生成工具名叫k8s.io/code-generator,使用方法如下所示:

  • 在项目跟路径创建目录
  1. mkdir hack && cd hack
  • 建立tools.go来依赖code-generator,因为在没有代码使用code-generator时,go module 默认不会为我们依赖此包
  1. // +build tools
  2. /*
  3. Copyright 2019 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. // This package imports things required by build scripts, to force `go mod` to see them as dependencies
  15. package tools
  16. import _ "k8s.io/code-generator"
  • 编写构建脚本:update-codegen.sh
  1. #!/usr/bin/env bash
  2. # Copyright 2017 The Kubernetes Authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. set -o errexit
  16. set -o nounset
  17. set -o pipefail
  18. # generate the code with:
  19. # --output-base because this script should also be able to run inside the vendor dir of
  20. # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
  21. # instead of the $GOPATH directly. For normal projects this can be dropped.
  22. ../vendor/k8s.io/code-generator/generate-groups.sh \
  23. "deepcopy,client,informer,lister" \
  24. k8s-controller-custom-resource/pkg/client \
  25. k8s-controller-custom-resource/pkg/apis \
  26. samplecrd:v1 \
  27. --go-header-file $(pwd)/boilerplate.go.txt \
  28. --output-base $(pwd)/../../
  • 在构建api时,我们还提供了文件头,所以我们在此也创建文件头:boilerplate.go.txt
  1. /*
  2. Copyright The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  • 生成代码
  1. # 生成vendor文件夹
  2. $ go mod vendor
  3. # 进入项目根目录,为vendor中的code-generator赋予权限
  4. $ chmod -R 777 vendor
  5. # 调用脚本生成代码
  6. MacBook-Pro hack % ./update-codegen.sh
  7. Generating deepcopy funcs
  8. Generating clientset for samplecrd:v1 at k8s-controller-custom-resource/pkg/client/clientset
  9. Generating listers for samplecrd:v1 at k8s-controller-custom-resource/pkg/client/listers
  10. Generating informers for samplecrd:v1 at k8s-controller-custom-resource/pkg/client/informers

代码生成工作完成之后,我们再查看一下这个项目的目录结构:

  1. ├── go.mod
  2. ├── go.sum
  3. ├── hack
  4.    ├── boilerplate.go.txt
  5.    ├── tools.go
  6.    └── update-codegen.sh
  7. ├── pkg
  8.    ├── apis
  9.       └── samplecrd
  10.       ├── register.go
  11.       └── v1
  12.       ├── doc.go
  13.       ├── register.go
  14.       ├── types.go
  15.       └── zz_generated.deepcopy.go
  16.    └── client
  17.    ├── clientset
  18.    ├── informers
  19.    └── listers

其中,pkg/apis/samplecrd/v1 下面的 zz_generated.deepcopy.go 文件,就是自动生成的 DeepCopy 代码文件。而整个 client 目录,以及下面的三个包(clientset、informers、 listers),都是 Kubernetes 为 Network 类型生成的客户端库,这些库会在后面编写自定义控制器的时候用到。

4、在 Kubernetes 集群里创建一个 Network 类型的 API 对象

  • 创建CRD yaml文件:network.yaml

  1. apiVersion: apiextensions.k8s.io/v1beta1
  2. kind: CustomResourceDefinition
  3. metadata:
  4. name: networks.samplecrd.k8s.io
  5. spec:
  6. group: samplecrd.k8s.io
  7. version: v1
  8. names:
  9. kind: Network
  10. plural: networks
  11. scope: Namespaced

然后在k8s中创建crd,这个操作,就告诉了 Kubernetes,我现在要添加一个自定义的 API 对象。而这个对象的 API 信息,正是 network.yaml 里定义的内容。我们可以通过 kubectl get 命令,查看这个 CRD:

  1. MacBook-Pro k8s-controller-custom-resource % k8sdev apply -f crd/network.yaml
  2. customresourcedefinition.apiextensions.k8s.io/networks.samplecrd.k8s.io created
  3. MacBook-Pro k8s-controller-custom-resource % k8sdev get crd
  4. NAME CREATED AT
  5. networks.samplecrd.k8s.io 2022-02-14T08:50:46Z
  • 创建Network 对象的 YAML 文件,名叫 example-network.yaml

  1. apiVersion: samplecrd.k8s.io/v1
  2. kind: Network
  3. metadata:
  4. name: example-network
  5. spec:
  6. cidr: "192.168.0.0/16"
  7. gateway: "192.168.0.1"

在k8s中创建 Network 对象

  1. MacBook-Pro k8s-controller-custom-resource % k8sdev apply -f example/example-network.yaml
  2. network.samplecrd.k8s.io/example-network created

通过这个操作,就在 Kubernetes 集群里创建了一个 Network 对象。它的 API 资源路径是samplecrd.k8s.io/v1/networks。

这时候,你就可以通过 kubectl get 命令,查看到新创建的 Network 对象:

  1. MacBook-Pro k8s-controller-custom-resource % k8sdev get network
  2. NAME AGE
  3. example-network 69s

你还可以通过 kubectl describe 命令,看到这个 Network 对象的细节:

  1. MacBook-Pro k8s-controller-custom-resource % k8sdev describe network example-network
  2. Name: example-network
  3. Namespace: default
  4. Labels: <none>
  5. Annotations: <none>
  6. API Version: samplecrd.k8s.io/v1
  7. Kind: Network
  8. Metadata:
  9. Creation Timestamp: 2022-02-14T08:57:58Z
  10. Generation: 1
  11. Resource Version: 34001215910
  12. Self Link: /apis/samplecrd.k8s.io/v1/namespaces/default/networks/example-network
  13. UID: d2a3b4d8-4000-473d-976e-cf6acb050942
  14. Spec:
  15. Cidr: 192.168.0.0/16
  16. Gateway: 192.168.0.1
  17. Events: <none>

5、总结

在今天这篇文章中,为 Kubernetes 添加一个名叫 Network 的 API 资源类型。从而达到了通过标准的 kubectl create 和 get 操作,来管理自定义 API 对象的目的。不过,创建出这样一个自定义 API 对象,我们只是完成了 Kubernetes 声明式 API 的一半工作。

接下来的另一半工作是:为这个 API 对象编写一个自定义控制器(Custom Controller)。这样, Kubernetes 才能根据 Network API 对象的“增、删、改”操作,在真实环境中做出相应的响应。比如,“创建、删除、修改”真正的 Neutron 网络。而这,正是 Network 这个 API 对象所关注的“业务逻辑”。这个业务逻辑的实现过程,以及它所使用的 Kubernetes API 编程库的工作原理,就是在下一篇文章中主要内容。

参考:

code-generator使用

k8s-controller-custom-resource

如何在Kubernetes 里添加自定义的 API 对象(一)的更多相关文章

  1. 如何在Kubernetes里创建一个Nginx service

    Jerry之前的文章如何在Kubernetes里创建一个Nginx应用,已经使用kubectl命令行创建了Pod,但是在kubernetes中,Pod的IP地址会随着Pod的重启而变化,因此用Pod的 ...

  2. 如何在Kubernetes里给PostgreSQL创建secret

    创建一个initdb.sql文件,输入如下内容: -- This is a postgres initialization script for the postgres container. -- ...

  3. 如何在Kubernetes里创建一个Nginx应用

    使用命令行kubectl run --image=nginx nginx-app --port=80 创建一个名为nginx-app的应用 结果: deployment.apps/nginx-app ...

  4. kubernetes之常用核心资源对象

    部门产品线本身是做DEVOPS平台,最近部署架构也在往K8S上靠了,不得不学一下K8S.自己搭建了K8S集群与harbor仓库来学习. 1.kubernetes之常用核心资源对象 1.1.K8s服务部 ...

  5. Kubernetes的核心技术概念和API对象

    Kubernetes的核心技术概念和API对象 API对象是K8s集群中的管理操作单元.K8s集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持对该功能的管理操作.例如副本集 ...

  6. 【Kubernetes】声明式API与Kubernetes编程范式

    什么是声明式API呢? 答案是,kubectl apply命令. 举个栗子 在本地编写一个Deployment的YAML文件: apiVersion: apps/v1 kind: Deployment ...

  7. Chrome出了个小bug:论如何在Chrome下劫持原生只读对象

    Chrome出了个小bug:论如何在Chrome下劫持原生只读对象 概述 众所周知,虽然JavaScript是个很灵活的语言,浏览器里很多原生的方法都可以随意覆盖或者重写,比如alert.但是为了保证 ...

  8. 在SharePoint 2010 母版页里添加自定义用户控件

    在SharePoint 2010 母版页里添加自定义用户控件(译) 使用自定义用户控件的好处: 1.容易部署:2.易于控制显示或隐藏. (在使用的过程中)可能要面对的问题是:如何在用户控件里使用Sha ...

  9. [转]如何在 Git 里撤销(几乎)任何操作

    任何版本控制系统的一个最有的用特性就是“撤销 (undo)”你的错误操作的能力.在 Git 里,“撤销” 蕴含了不少略有差别的功能. 当你进行一次新的提交的时候,Git 会保存你代码库在那个特定时间点 ...

随机推荐

  1. k8s env、configmap、secret外部数据加载配置

    K8s提供了多种外部数据注入容器的方式,今天我们主要学习环境变量.ConfigMap以及Secret的使用和配置. 环境变量 在docker项目中,对一个容器添加环境变量可以在容器创建时通过-e EN ...

  2. DB2给表批量赋权

    使用DB2的for循环语句给表批量赋权,同理,稍加修改可作为其他批量操作. 值得注意的是: grant语句无法直接执行,需要使用execute immediate才能执行. 授权操作表的所有权限:gr ...

  3. let var const 区别

    let es6 语法 let是作用域是块级的,即{}内的范围 如果未声明变量就使用的话,报错ReferenceError,而var则会报错undefined(不存在变量提升) 只要块级作用域内存在le ...

  4. 缓存一致性性协议MESI笔记

    概述 今天的笔记只是讲解一下MESI的概念和使用场景的介绍,MESI(Modified Exclusive Shared Or Invalid)也称为伊利诺斯协议,是一种广泛使用的支持协会策略的缓存一 ...

  5. 使用.NET 6开发TodoList应用(26)——实现Configuration和Option的强类型绑定

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在上一篇文章使用.NET 6开发TodoList应用(25)--实现RefreshToken中,我们通过使用Configura ...

  6. Web开发之HTTP协议

    HTTP响应消息 一个HTTP响应代表服务器向客户端回送的数据. 一个完整的HTTP响应包括如下内容: 一个状态行.若干消息头.以及响应正文,其中的一些消息头和正文都是可选的,消息头和正文内容之间要用 ...

  7. Linux - 文件处理

    链接服务器 ssh 使用ssh:ssh -p22 username@host(服务器地址) 输入后会提示输入密码 -p22是ssh默认端口 可以不用 登录之后会默认处于 home 路径 xshell ...

  8. 【刷题-LeetCode】150 Evaluate Reverse Polish Notation

    Evaluate Reverse Polish Notation Evaluate the value of an arithmetic expression in Reverse Polish No ...

  9. 【解决了一个小问题】如何展示VictoriaMetrics组件上报的bucket数据

    VM体系还真的是不一(he)样(qun), 它上报的监控数据长这样: vmagent_remotewrite_block_size_rows_bucket{vmrange="2.448e+0 ...

  10. 【记录一个问题】android opencl c++: 不要Context, CommandQueue类的赋值函数

    一开始代码中这样写了: cl::Context ctx = cl::Context(CL_DEVICE_TYPE_GPU, NULL); cl::CommandQueue queue= cl::Com ...