kubebuilder学习记录

kubebuilder学习参考文章:
kubebuilder github
使用 kubebuilder 创建 operator 示例
kubebuilder云原生开发

一、项目创建

  • 创建项目文件目录
mkdir kubebuilder-example
cd kubebuilder-example
  • 初始化module
    通过mod管理,不需要将go项目放在GOPATH目录下,但是在通过kubebuilder创建架子之前,需要初始化一下go.mod
 ~/kubebuilder-example  go mod init example.io
go: creating new go.mod: module example.io

内容如下

 ~//kubebuilder-example  cat go.mod
module example.io

go 1.14
  • kubebuilder脚手架搭建项目
 ~/kubebuilder-example  kubebuilder init --domain example.io
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.5.0
go: downloading sigs.k8s.io/controller-runtime v0.5.0
go: downloading k8s.io/apimachinery v0.17.2
go: downloading k8s.io/client-go v0.17.2
......
Next: define a resource with:
$ kubebuilder create api

创建完成后,内容如下

~/kubebuilder-example  tree 
├── Dockerfile
├── Makefile
├── PROJECT
├── bin
│   └── manager
├── config
│   ├── certmanager
│   ├── crd
│   ├── default
│   ├── manager
│   ├── prometheus
│   ├── rbac
│   ├── samples
│   └── webhook
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go

创建示例api如下

~/GolandProjects/kubebuilder-example  kubebuilder create api --group webapp --version v1 --kind Guestbook
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing scaffold for you to edit...
api/v1/guestbook_types.go
controllers/guestbook_controller.go
......
go build -o bin/manager main.go

创建完成后

~/kubebuilder-example  tree 
├── Dockerfile
├── Makefile
├── PROJECT
├── api
│   └── v1
│       ├── groupversion_info.go
│       ├── guestbook_types.go
│       └── zz_generated.deepcopy.go
├── bin
│   └── manager
├── config
│   ├── certmanager
│   ├── crd
│   ├── default
│   ├── manager
│   ├── prometheus
│   ├── rbac
│   ├── samples
│   └── webhook
├── controllers
│   ├── guestbook_controller.go
│   └── suite_test.go
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go
  • 安装crd
$ make install

本地部署 controller,便于调试

$ make run

将在本地看到调试和输出

将 controller 部署到 Kubernetes

执行下面的命令部署 controller 到 Kubernetes 上,这一步将会在本地构建 controller 的镜像,并推送到 DockerHub 上,然后在 Kubernetes 上部署 Deployment 资源。

make docker-build docker-push IMG=woshiwoniu/kubebuilder-example:latest
make deploy IMG=woshiwoniu/kubebuilder-example:latest

在初始化项目时,kubebuilder 会自动根据项目名称创建一个 Namespace,如本文中的 kubebuilder-example-system,查看 Deployment 对象和 Pod 资源。

$ kubectl get deployment -n kubebuilder-example-system
NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
kubebuilder-example-controller-manager   1/1     1            1           3h26m
$ kubectl get pod -n kubebuilder-example-system
NAME                                                      READY   STATUS    RESTARTS   AGE
kubebuilder-example-controller-manager-77b4c685f9-2npz8   2/2     Running   0          3h16m

创建 CR
Kubebuilder 在初始化项目的时候已生成了示例 CR,执行下面的命令部署 CR。

kubectl apply -f config/samples/webapp_v1_guestbook.yaml

执行下面的命令查看新创建的 CR。

$ kubectl get guestbooks.webapp.example.io guestbook-sample -o yaml

至此一个基本的 Operator 框架已经创建完成,但这个 Operator 只是修改了 etcd 中的数据而已,实际上什么事情也没做,因为我们没有在 Operator 中的增加业务逻辑。

增加业务逻辑
下面我们将修改 CRD 的数据结构并在 controller 中增加一些日志输出。

修改 CRD
我们将修改上文中使用 kubebuilder 命令生成的默认 CRD 配置,在 CRD 中增加 FirstName、LastName 和 Status 字段。

下面是修改后的 api/v1/guestbook_types.go 文件的内容,对应修改的地方已在代码中注释说明。


/*


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.
*/

package v1

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

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// GuestbookSpec defines the desired state of Guestbook
type GuestbookSpec struct {
    // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
    // Important: Run "make" to regenerate code after modifying this file

    // Foo is an example field of Guestbook. Edit Guestbook_types.go to remove/update
  // 添加两个新的字段
    FirstName string `json:"firstname"`
    LastName  string `json:"lastname"`
}

// GuestbookStatus defines the observed state of Guestbook
type GuestbookStatus struct {
    // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    // Important: Run "make" to regenerate code after modifying this file
    Status string `json:"Status"`
}

// +kubebuilder:object:root=true
// 在这里增加 status 的说明
// +kubebuilder:subresource:status

// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   GuestbookSpec   `json:"spec,omitempty"`
    Status GuestbookStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// GuestbookList contains a list of Guestbook
type GuestbookList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []Guestbook `json:"items"`
}

func init() {
    SchemeBuilder.Register(&Guestbook{}, &GuestbookList{})
}

上面的代码比原先使用 kubebuilder 生成的默认代码增加了以下内容:

    FirstName string `json:"firstname"`
    LastName  string `json:"lastname"`
    Status string `json:"Status"`
    // +kubebuilder:subresource:status

修改 Reconcile 函数
Reconcile 函数是 Operator 的核心逻辑,Operator 的业务逻辑都位于 controllers/guestbook_controller.go 文件的 func (r *GuestbookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) 函数中。

// +kubebuilder:rbac:groups=webapp.example.io,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=webapp.example.io,resources=guestbooks/status,verbs=get;update;patch

func (r *GuestbookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
    _ = context.Background()
    _ = r.Log.WithValues("guestbook", req.NamespacedName)

    // your logic here
    ctx := context.Background()
    _ = r.Log.WithValues("apiexamplea", req.NamespacedName)

  // 获取当前的 CR,并打印
    obj := &webappv1.Guestbook{}
    if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
        log.Println(err, "Unable to fetch object")
    } else {
        log.Println("Geeting from Kubebuilder to", obj.Spec.FirstName, obj.Spec.LastName)
    }

  // 初始化 CR 的 Status 为 Running
    obj.Status.Status = "Running"
    if err := r.Status().Update(ctx, obj); err != nil {
        log.Println(err, "unable to update status")
    }

    return ctrl.Result{}, nil
}

这段代码的业务逻辑是当发现有 guestbooks.webapp.example.io 的 CR 变更时,在控制台中输出日志。

运行测试
修改好 Operator 的业务逻辑后,再测试一下新的逻辑是否可以正常运行。

部署 CRD

跟上文的做法一样,执行下面的命令部署 CRD。

make install

运行 controller

跟上文的做法一样,执行下面的命令运行 controller。为了方便起见,我们将在本地运行 controller,当然您也可以将其部署到 Kubernetes 上运行。

make run

保持该窗口在前台运行。

部署 CR

修改 config/samples/webapp_v1_guestbook.yaml 文件中的配置,将之前默认的foo字段删除,添加firstname和lastname。

apiVersion: webapp.example.io/v1
kind: Guestbook
metadata:
  name: guestbook-sample
spec:
  # Add fields here
  firstname: Jimmy
  lastname: Song

将其应用到 Kubernetes。

kubectl apply -f config/samples/webapp_v1_guestbook.yaml
此时转到上文中运行 controller 的窗口,将在命令行前台中看到如下输出。

go fmt ./...
go vet ./...
/Users/test/Workspace/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
go run ./main.go
2020-06-07T16:48:29.966+0800    INFO    controller-runtime.metrics    metrics server is starting to listen    {"addr": ":8080"}
2020-06-07T16:48:29.967+0800    INFO    setup    starting manager
2020-06-07T16:48:29.967+0800    INFO    controller-runtime.manager    starting metrics server    {"path": "/metrics"}
2020-06-07T16:48:29.967+0800    INFO    controller-runtime.controller    Starting EventSource    {"controller": "guestbook", "source": "kind source: /, Kind="}
2020-06-07T16:48:30.068+0800    INFO    controller-runtime.controller    Starting Controller    {"controller": "guestbook"}
2020-06-07T16:48:30.068+0800    INFO    controller-runtime.controller    Starting workers    {"controller": "guestbook", "worker count": 1}
2020/06/07 16:48:30 Geeting from Kubebuilder to Jimmy Song
2020-06-07T16:48:30.080+0800    DEBUG    controller-runtime.controller    Successfully Reconciled    {"controller": "guestbook", "request": "kubebuilder-example-system/guestbook-sample"}

从上面的日志中,可以看到这条输出。

2020/06/07 16:48:30 Geeting from Kubebuilder to Jimmy Song

这正是在 Reconcile 函数中的输出。

删除 CR
使用下面的命令删除 CR,这里的资源类型以Kind的小写加上apiVersion拼接。

kubectl delete guestbooks.webapp.example.io guestbook-sample
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容