惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
量子位
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
B
Blog
U
Unit 42
C
Check Point Blog
I
InfoQ
aimingoo的专栏
aimingoo的专栏
雷峰网
雷峰网
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 【当耐特】
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
H
Help Net Security
MongoDB | Blog
MongoDB | Blog
博客园 - Franky
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
云风的 BLOG
云风的 BLOG
宝玉的分享
宝玉的分享
爱范儿
爱范儿

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19)
如何使用 KubeBuilder 开发一个 Operator
微信公众号 · 2019-09-25 · via 陈少文的网站

Please enable Javascript to view the contents

通过 Operator 的方案,可以对 Kubernetes 的功能进行友好地扩展。Operatpr = CRD + Controller。首先通过 yaml 定义,生成 CRD ,然后 Controller 不断地监听 etcd 中的数据,执行相应动作。开发 Operator 时,有很多繁琐且重复的事情。KubeBuilder 可以帮助我们快速生成骨架代码,开发一个 Kubernetes 的扩展功能, 更多介绍可以参考文档:Kubernetes 复杂有状态应用管理框架 – Operator 。本篇文档,主要是尝试使用 KubeBuilder 开发一个 Operator 。

1. 环境准备

  • Go 开发环境

  • 远程 Kubernetes 环境

我准备的是,单节点 Kubernetes 1.15.3 。

  • 本地 Kubectl 访问远程集群的权限

将集群 /etc/kubernetes/admin.conf 拷贝到本地 ~/.kube/config 即可。

2. Hello,Kubebuilder

2.1 安装 kubebuilder、kustomize

以 OS X 为例,当前 kubebuilder 版本为 2.x :

1
2
brew install kubebuilder
brew install kustomize

2.2 初始化项目

1
2
3
4
export GOPATH=$(go env GOPATH)
mkdir -p $GOPATH/src/github.com/kube-api
cd $GOPATH/src/github.com/kube-api
kubebuilder init --domain k8s.chenshaowen.com --license apache2 --owner "chenshaowen"

初始化工程之后,KubeBuilder 会生成一系列配置和代码框架。

 1
 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
39
tree -L 3
.
├── Dockerfile
├── Makefile
├── PROJECT
├── bin
│   └── manager
├── config
│   ├── certmanager
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_prometheus_metrics_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── manager
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── rbac
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   └── role_binding.yaml
│   └── webhook
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go
8 directories, 28 files

2.3. 新增 API

1
2
3
4
5
6
kubebuilder create api --group groupa --version v1beta1 --kind ApiExampleA
Create Resource [y/n]
y
Create Controller [y/n]
y
......

KubeBuilder 会将 CRD 和 Controller 添加到工程中。

 1
 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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
tree -L 3
.
├── Dockerfile
├── Makefile
├── PROJECT # 新增 resources 部分
├── api
│   └── v1beta1 # 新增 API 描述
│       ├── apiexamplea_types.go
│       ├── groupversion_info.go
│       └── zz_generated.deepcopy.go
├── bin
│   └── manager
├── config
│   ├── certmanager
│   │   ├── certificate.yaml
│   │   ├── kustomization.yaml
│   │   └── kustomizeconfig.yaml
│   ├── crd # 新增 CRD 定义
│   │   ├── kustomization.yaml
│   │   ├── kustomizeconfig.yaml
│   │   └── patches
│   ├── default
│   │   ├── kustomization.yaml
│   │   ├── manager_auth_proxy_patch.yaml
│   │   ├── manager_prometheus_metrics_patch.yaml
│   │   ├── manager_webhook_patch.yaml
│   │   └── webhookcainjection_patch.yaml
│   ├── manager
│   │   ├── kustomization.yaml
│   │   └── manager.yaml
│   ├── rbac
│   │   ├── auth_proxy_role.yaml
│   │   ├── auth_proxy_role_binding.yaml
│   │   ├── auth_proxy_service.yaml
│   │   ├── kustomization.yaml
│   │   ├── leader_election_role.yaml
│   │   ├── leader_election_role_binding.yaml
│   │   └── role_binding.yaml
│   ├── samples # 新增创建 CRD 对象示例
│   │   └── groupa_v1beta1_apiexamplea.yaml
│   └── webhook
│       ├── kustomization.yaml
│       ├── kustomizeconfig.yaml
│       └── service.yaml
├── controllers # 新增 Controller
│   ├── apiexamplea_controller.go
│   └── suite_test.go
├── go.mod # 新增依赖包
├── go.sum
├── hack
│   └── boilerplate.go.txt
└── main.go # 新增处理逻辑
14 directories, 36 files

2.4 修改配置,适配国内环境

在容器中进行编译时,由于国内网络问题,会导致拉取不到 Go 依赖包和依赖镜像,需要修改 Dockerfile 文件。

  • 增加 GO 代理
  • 修改镜像源
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@@ -7,7 +7,7 @@ COPY go.mod go.mod
 COPY go.sum go.sum
 # cache deps before building and copying source so that we don't need to re-download as much
 # and so that source changes don't invalidate our downloaded layer
-RUN go mod download
+RUN GOPROXY=https://gocenter.io go mod download

 # Copy the go source
 COPY main.go main.go
@@ -19,7 +19,7 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager

 # Use distroless as minimal base image to package the manager binary
 # Refer to https://github.com/GoogleContainerTools/distroless for more details
-FROM gcr.io/distroless/static:latest
+FROM gcr.azk8s.cn/distroless/static:latest
 WORKDIR /
 COPY --from=builder /workspace/manager .
 ENTRYPOINT ["/manager"]

2.5. 构建并推送镜像测试

  1. 本地构建并推送镜像

由于使用的是远程 Kubernetes 环境,需要借助镜像仓库进行部署。

  • 修改镜像名称
1
2
3
4
5
6
7
@@ -1,6 +1,6 @@

 # Image URL to use all building/pushing image targets
-IMG ?= controller:latest
+IMG ?= docker.io/shaowenchen/controller:latest
 # Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
 CRD_OPTIONS ?= "crd:trivialVersions=true"
  • 登陆 docker.io 的镜像仓库
1
2
3
docker login docker.io -u shaowenchen
Password:
Login Succeeded
  • 构建并推送镜像
1
make docker-build & make docker-push

也可以通过,在执行 make docker-build 等命令时,增加 IMG 变量修改镜像名称。

  1. 部署到 Kubernetes
  • 安装 kustomize
  • 部署 CRD
  • 查看 CRD
1
2
3
kubectl get crd
NAME                                      CREATED AT
apiexampleas.groupa.k8s.chenshaowen.com   2019-09-24T07:24:45Z
  • 部署 Controller
  • 查看 deployment
1
2
3
kubectl get deploy  -n kube-api-system
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
kube-api-controller-manager   1/1     1            1           46s
  • 创建 CRD 对象
1
kubectl apply -f config/samples/groupa_v1beta1_apiexamplea.yaml
  • 查看 CRD 对象
1
2
3
4
kubectl get apiexampleas.groupa.k8s.chenshaowen.com

NAME                 AGE
apiexamplea-sample   61s
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
kubectl get apiexampleas.groupa.k8s.chenshaowen.com apiexamplea-sample  -o yaml

apiVersion: groupa.k8s.chenshaowen.com/v1beta1
kind: ApiExampleA
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"groupa.k8s.chenshaowen.com/v1beta1","kind":"ApiExampleA","metadata":{"annotations":{},"name":"apiexamplea-sample","namespace":"default"},"spec":{"foo":"bar"}}
  creationTimestamp: "2019-09-24T07:29:16Z"
  generation: 1
  name: apiexamplea-sample
  namespace: default
  resourceVersion: "635450"
  selfLink: /apis/groupa.k8s.chenshaowen.com/v1beta1/namespaces/default/apiexampleas/apiexamplea-sample
  uid: 05398ab4-7d4a-4f2e-af30-b59e61680c7e
spec:
  foo: bar

3. 在 Project 中写入逻辑

通过上面的操作,我们新增了 Kubernetes 对象类型 apiexampleas.groupa.k8s.chenshaowen.comApiExampleA),并实例化对象进行操作。

这些操作仅仅只是对 etcd 数据的操作,没有触发有效动作。下面,尝试往工程中注入一点自定义逻辑。实现一个简单的功能:给自定义的 CRD 增加两个字段,FirstName、SecondName ;创建对象时,在 Controller 中获取这两个字段,并输出到日志中。

  1. 修改代码
  • 增加 CRD 字段

api/v1beta1/apiexamplea_types.go 文件 ApiExampleASpec 结构体中增加两个字段:

1
2
3
4
5
6
type ApiExampleASpec struct {
	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
	// Important: Run "make" to regenerate code after modifying this file
	FirstName  string `json:"firstname"` // add
	SecondName string `json:"secondname"` // add
}
  • 增加 Controller 逻辑

首先在 import 中新增 log 包:

1
2
3
import (
  "log" // add
  ...

然后在 Reconcile 函数中,处理逻辑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func (r *ApiExampleAReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
	// _ = context.Background()
	// _ = r.Log.WithValues("apiexamplea", req.NamespacedName)

	// // your logic here

	// return ctrl.Result{}, nil
	ctx := context.Background()
	_ = r.Log.WithValues("apiexamplea", req.NamespacedName)

	obja := &groupav1beta1.ApiExampleA{}
	if err := r.Get(ctx, req.NamespacedName, obja); err != nil {
		log.Println(err, "unable to fetch New Object")
	} else {
		log.Println("fetch New Object:", obja.Spec.FirstName, obja.Spec.SecondName)
	}

	return ctrl.Result{}, nil
}
  1. 修改镜像 tag

修改镜像 tag 是为了远程 Kubernetes 集群远程部署 Deployment 时,能够重新拉取镜像,使用指定的镜像进行部署。

修改 Makefile 文件中的变量 IMG 为:IMG ?= docker.io/shaowenchen/controller:1

  1. 构建发布
1
make & make docker-build & make docker-push
  1. 部署
  1. 生成一个 CRD 对象实例

config/samples/groupa_v1beta1_apiexamplea.yaml 文件中修改 name 值,并在 spec 字段新增两个字段:

1
2
3
4
5
6
7
8
9
apiVersion: groupa.k8s.chenshaowen.com/v1beta1
kind: ApiExampleA
metadata:
  name: apiexamplea-sample2
spec:
  # Add fields here
  # foo: bar
  firstname: shaowen
  secondname: chen

创建 CRD 对象

1
kubectl create -f config/samples/groupa_v1beta1_apiexamplea.yaml

查看 Controller 的 Pod Name

1
2
3
kubectl get pod -n kube-api-system
NAME                                           READY   STATUS    RESTARTS   AGE
kube-api-controller-manager-7d8bb9fc6f-8bmg9   2/2     Running   0          22m

查看创建日志

1
2
3
4
5
6
7
8
9
kubectl logs kube-api-controller-manager-7d8bb9fc6f-8bmg9 -c manager -n kube-api-system
2019-09-25T07:09:51.124Z	INFO	controller-runtime.metrics	metrics server is starting to listen	{"addr": "127.0.0.1:8080"}
2019-09-25T07:09:51.216Z	INFO	controller-runtime.controller	Starting EventSource	{"controller": "apiexamplea", "source": "kind source: /, Kind="}
2019-09-25T07:09:51.217Z	INFO	setup	starting manager
2019-09-25T07:09:51.217Z	INFO	controller-runtime.manager	starting metrics server	{"path": "/metrics"}
2019-09-25T07:10:08.111Z	INFO	controller-runtime.controller	Starting Controller	{"controller": "apiexamplea"}
2019-09-25T07:10:08.111Z	DEBUG	controller-runtime.manager.events	Normal	{"object": {"kind":"ConfigMap","namespace":"kube-api-system","name":"controller-leader-election-helper","uid":"bf307b9a-829f-478e-9306-68b6c47671fa","apiVersion":"v1","resourceVersion":"871886"}, "reason": "LeaderElection", "message": "kube-api-controller-manager-7d8bb9fc6f-8bmg9_77815cc0-df63-11e9-b8c4-e6f6cfac380f became leader"}
2019-09-25T07:10:08.211Z	INFO	controller-runtime.controller	Starting workers	{"controller": "apiexamplea", "worker count": 1}
2019/09/25 07:10:08 fetch New Object: shaowen chen

4. 参考


微信公众号