参照官方样例项目 kubernetes/sample-controller 中的部分内容编写,此文仅仅为一个流程记录,部分文件中 import
部分的相关依赖根据项目不用的命名情况需要作出相应的修改。
编程环境:
- Go v1.13.8
- MacOS 10.15.8
- Kubernetes v1.17.0
样例项目地址 schwarzeni/k8s-sample-controller-doc-demo
Project Setup
注意,由于后期使用 code-generator 时,code-generator 不支持 go module 模式,所以项目虽然依然可以使用 go module ,但是目录需要建成 GOPATH 的样式,例如如下
1 | go mod init github.com/schwarzeni/k8s-sample-controller-doc-demo |
此时项目 k8s-sample-controller-doc-demo 父文件夹路径应该为 github.com/schwarzeni/
安装相关的依赖,对于 1.17 版本的 Kubernetes ,下载 0.17.0 版本的相关客户端,下载 code-generator 时可能会报错,这个不用管
1 | go get -u k8s.io/code-generator@v0.17.0 |
建立 hack/tools.go
并写入如下内容,便于之后使用 go mod vendor
1 | // +build tools |
之后执行命令:
1 | go mod vendor |
此时项目结构如下:
1 | . |
文件 vendor/k8s.io/code-generator/generate-groups.sh
就是用来生成代码的脚本
Code Generation
首先先定义相关的 K8S 资源,然后使用 K8S 提供的工具生成相关的访问代码。这里的代码全部参照 kubernetes/sample-controller 中的相关代码。
在根目录下新建文件夹 pkg/apis/samplecontroller
作为定义资源的目录,在此目录下新建四个文件并填入相应的内容,IDE 可能会报错,这个不用管
1 | pkg/apis/samplecontroller |
register.go1
2
3
4package samplecontroller
// GroupName is the group name used in this package
const GroupName = "samplecontroller.k8s.io"
v1alpha1/doc.go1
2
3
4
5// +k8s:deepcopy-gen=package
// +groupName=samplecontroller.k8s.io
// Package v1alpha1 is the v1alpha1 version of the API.
package v1alpha1
v1alpha1/types.go1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Foo is a specification for a Foo resource
type Foo struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec FooSpec `json:"spec"`
Status FooStatus `json:"status"`
}
// FooSpec is the spec for a Foo resource
type FooSpec struct {
DeploymentName string `json:"deploymentName"`
Replicas *int32 `json:"replicas"`
}
// FooStatus is the status for a Foo resource
type FooStatus struct {
AvailableReplicas int32 `json:"availableReplicas"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// FooList is a list of Foo resources
type FooList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`
Items []Foo `json:"items"`
}
v1alpha1/register.go1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
samplecontroller "github.com/schwarzeni/k8s-sample-controller-doc-demo/pkg/apis/samplecontroller"
)
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: samplecontroller.GroupName, Version: "v1alpha1"}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
// SchemeBuilder initializes a scheme builder
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
// AddToScheme is a global function that registers this API group & version to a scheme
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Foo{},
&FooList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
再执行一次 go mod vendor
为自动生成的文件准备一个 header
hack/boilerplate.go.txt
1 | /* |
执行如下命令生成代码:(我在 Goland 的终端中执行此命令会报错,但是在普通终端中执行就没问题了,目前还不太清楚原因)
1 | bash vendor/k8s.io/code-generator/generate-groups.sh all \ |
对于 --output-base
,假如你的项目绝对路径为 /Users/nizhenyang/my-project/cloud/src/github.com/schwarzeni/k8s-sample-controller-doc-demo
,将后半段 github.com/schwarzeni/k8s-sample-controller-doc-demo
视为 GOPATH,则这个参数的值就是前半段路径。
执行完代码之后,在 pkg/
下会出现新生成的 generated
文件夹, 大致的结构如下
1 | pkg/generated |
在pkg/apis/samplecontroller/v1alpha1/
下新生成了 zz_generated.deepcopy.go
文件。
生成代码任务完成,再执行一次 go mod vendor
Testing
这里写一个测试程序来验证我们生产代码的可用性,首先,根据自定义资源的格式准备两份 yaml 配置文件:
crd.yaml
1 | apiVersion: apiextensions.k8s.io/v1beta1 |
example-foo.yaml
1 | apiVersion: samplecontroller.k8s.io/v1alpha1 |
执行命令 kubectl apply -f crd.yaml
创建资源定义
删除 vendor 目录,在项目根目录新建 main.go
,内容如下
1 | package main |
执行该程序
执行 kubectl apply -f foo-example.yaml
,发现程序输出了 “New Foo Added: example-foo”
执行 kubectl delete -f foo-example.yaml
,发现程序输出了 “Delete Foo : example-foo”