如何在Kubernetes 里添加自定義的 API 對象(一)


環境:

golang 1.15 依賴包采用go module

實例:現在往 Kubernetes 添加一個名叫 Network 的 API 資源類型。它的作用是,一旦用戶創建一個 Network 對象,那么 Kubernetes 就應該使用這個對象定義的網絡參數,調用真實的網絡插件,為用戶創建一個真正的“網絡”。這樣,將來用戶創建的 Pod,就可以聲明使用這個“網絡”了。

結構如下:

MacBook-Pro kubernetes % tree k8s-controller-custom-resource -L 5

├── go.mod
├── hack
│   ├── boilerplate.go.txt
│   ├── tools.go
│   └── update-codegen.sh
├── pkg
│   └── apis
│       └── samplecrd
│           ├── register.go
│           └── v1
│               ├── doc.go
│               ├── register.go
│               └── types.go

1、初始化項目

#創建目錄
$ mkdir k8s-controller-custom-resource && cd k8s-controller-custom-resource
#初始化項目,生成go.mod文件
$ go mod init k8s-controller-custom-resource
# 獲取依賴
$ go get k8s.io/apimachinery@v0.0.0-20190425132440-17f84483f500
$ go get k8s.io/client-go@v0.0.0-20190425172711-65184652c889
$ go get k8s.io/code-generator@v0.0.0-20190419212335-ff26e7842f9d

2、初始化crd資源類型

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

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

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

然后,我在 pkg/apis/samplecrd 目錄下創建了一個 register.go 文件,用來放置后面要用到的全局變量。這個文件的內容如下所示:


package samplecrd

const (
 GroupName = "samplecrd.k8s.io"
 Version   = "v1"
)

接着,我需要在 pkg/apis/samplecrd/v1 目錄下添加一個 doc.go 文件(Golang 的文檔源文件)。這個文件里的內容如下所示:


// +k8s:deepcopy-gen=package

// +groupName=samplecrd.k8s.io
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 字段里的內容)。這個文件的主要內容如下所示:

package v1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Network describes a Network resource
type Network struct {
	// TypeMeta is the metadata for the resource, like kind and apiversion
	metav1.TypeMeta `json:",inline"`
	// ObjectMeta contains the metadata for the particular object, including
	// things like...
	//  - name
	//  - namespace
	//  - self link
	//  - labels
	//  - ... etc ...
	metav1.ObjectMeta `json:"metadata,omitempty"`

	// Spec is the custom resource spec
	Spec NetworkSpec `json:"spec"`
}

// NetworkSpec is the spec for a Network resource
type NetworkSpec struct {
	// Cidr and Gateway are example custom spec fields
	//
	// this is where you would put your custom resource data
	Cidr    string `json:"cidr"`
	Gateway string `json:"gateway"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// NetworkList is a list of Network resources
type NetworkList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`

	Items []Network `json:"items"`
}

最后,我需要再編寫一個 pkg/apis/samplecrd/v1/register.go 文件。

package v1

import (
	"k8s-controller-custom-resource/pkg/apis/samplecrd"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// GroupVersion is the identifier for the API which includes
// the name of the group and the version of the API
var SchemeGroupVersion = schema.GroupVersion{
	Group:   samplecrd.GroupName,
	Version: samplecrd.Version,
}

// addKnownTypes adds our types to the API scheme by registering
// Network and NetworkList
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(
		SchemeGroupVersion,
		&Network{},
		&NetworkList{},
	)

	// register the type in the scheme
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
	return nil
}

這樣,Network 對象的定義工作就全部完成了。可以看到,它其實定義了兩部分內容:

第一部分是,自定義資源類型的 API 描述,包括:組(Group)、版本(Version)、資源類型(Resource)等。

第二部分是,自定義資源類型的對象描述,包括:Spec、Status 等。 

3、使用 Kubernetes 提供的代碼生成工具,為上面定義的 Network 資源類型自動生成 clientset、informer 和 lister。

生成代碼主要為下一章的controller使用。其中,clientset 就是操作 Network 對象所需要使用的客戶端,而 informer 和 lister 這兩個包的主要功能,我會在下一篇文章中重點講解。這個代碼生成工具名叫k8s.io/code-generator,使用方法如下所示:

  • 在項目跟路徑創建目錄
mkdir hack && cd hack
  • 建立tools.go來依賴code-generator,因為在沒有代碼使用code-generator時,go module 默認不會為我們依賴此包
// +build tools

/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// This package imports things required by build scripts, to force `go mod` to see them as dependencies
package tools

import _ "k8s.io/code-generator"
  • 編寫構建腳本:update-codegen.sh
#!/usr/bin/env bash

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

# generate the code with:
# --output-base    because this script should also be able to run inside the vendor dir of
#                  k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
#                  instead of the $GOPATH directly. For normal projects this can be dropped.
../vendor/k8s.io/code-generator/generate-groups.sh \
  "deepcopy,client,informer,lister" \
  k8s-controller-custom-resource/pkg/client \
  k8s-controller-custom-resource/pkg/apis \
  samplecrd:v1 \
  --go-header-file $(pwd)/boilerplate.go.txt \
  --output-base $(pwd)/../../ 

  • 在構建api時,我們還提供了文件頭,所以我們在此也創建文件頭:boilerplate.go.txt
/*
Copyright The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
  • 生成代碼
# 生成vendor文件夾
$ go mod vendor
# 進入項目根目錄,為vendor中的code-generator賦予權限
$ chmod -R 777 vendor
# 調用腳本生成代碼
MacBook-Pro hack % ./update-codegen.sh
Generating deepcopy funcs
Generating clientset for samplecrd:v1 at k8s-controller-custom-resource/pkg/client/clientset
Generating listers for samplecrd:v1 at k8s-controller-custom-resource/pkg/client/listers
Generating informers for samplecrd:v1 at k8s-controller-custom-resource/pkg/client/informers

代碼生成工作完成之后,我們再查看一下這個項目的目錄結構:

├── go.mod
├── go.sum
├── hack
│   ├── boilerplate.go.txt
│   ├── tools.go
│   └── update-codegen.sh
├── pkg
│   ├── apis
│   │   └── samplecrd
│   │       ├── register.go
│   │       └── v1
│   │           ├── doc.go
│   │           ├── register.go
│   │           ├── types.go
│   │           └── zz_generated.deepcopy.go
│   └── client
│       ├── clientset
│       ├── informers
│       └── listers

 其中,pkg/apis/samplecrd/v1 下面的 zz_generated.deepcopy.go 文件,就是自動生成的 DeepCopy 代碼文件。而整個 client 目錄,以及下面的三個包(clientset、informers、 listers),都是 Kubernetes 為 Network 類型生成的客戶端庫,這些庫會在后面編寫自定義控制器的時候用到。

4、在 Kubernetes 集群里創建一個 Network 類型的 API 對象

  • 創建CRD yaml文件:network.yaml

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: networks.samplecrd.k8s.io
spec:
  group: samplecrd.k8s.io
  version: v1
  names:
    kind: Network
    plural: networks
  scope: Namespaced

然后在k8s中創建crd,這個操作,就告訴了 Kubernetes,我現在要添加一個自定義的 API 對象。而這個對象的 API 信息,正是 network.yaml 里定義的內容。我們可以通過 kubectl get 命令,查看這個 CRD:

MacBook-Pro k8s-controller-custom-resource % k8sdev apply -f crd/network.yaml
customresourcedefinition.apiextensions.k8s.io/networks.samplecrd.k8s.io created

MacBook-Pro k8s-controller-custom-resource % k8sdev get crd
NAME                                  CREATED AT
networks.samplecrd.k8s.io             2022-02-14T08:50:46Z
  • 創建Network 對象的 YAML 文件,名叫 example-network.yaml

apiVersion: samplecrd.k8s.io/v1
kind: Network
metadata:
  name: example-network
spec:
  cidr: "192.168.0.0/16"
  gateway: "192.168.0.1"

在k8s中創建 Network 對象

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

通過這個操作,就在 Kubernetes 集群里創建了一個 Network 對象。它的 API 資源路徑是samplecrd.k8s.io/v1/networks。

這時候,你就可以通過 kubectl get 命令,查看到新創建的 Network 對象:

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

你還可以通過 kubectl describe 命令,看到這個 Network 對象的細節:

MacBook-Pro k8s-controller-custom-resource % k8sdev describe network  example-network
Name:         example-network
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  samplecrd.k8s.io/v1
Kind:         Network
Metadata:
  Creation Timestamp:  2022-02-14T08:57:58Z
  Generation:          1
  Resource Version:    34001215910
  Self Link:           /apis/samplecrd.k8s.io/v1/namespaces/default/networks/example-network
  UID:                 d2a3b4d8-4000-473d-976e-cf6acb050942
Spec:
  Cidr:     192.168.0.0/16
  Gateway:  192.168.0.1
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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM