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

推荐订阅源

博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
P
Palo Alto Networks Blog
SecWiki News
SecWiki News
S
Secure Thoughts
P
Privacy International News Feed
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Tenable Blog
W
WeLiveSecurity
Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
Arctic Wolf
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Spread Privacy
Spread Privacy
V2EX - 技术
V2EX - 技术
Project Zero
Project Zero
C
CERT Recently Published Vulnerability Notes
Security Archives - TechRepublic
Security Archives - TechRepublic
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
Hacker News - Newest:
Hacker News - Newest: "LLM"
S
Schneier on Security
L
Lohrmann on Cybersecurity
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Scott Helme
Scott Helme
H
Hacker News: Front Page
博客园 - Franky
月光博客
月光博客
D
DataBreaches.Net
Know Your Adversary
Know Your Adversary
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
O
OpenAI News
N
Netflix TechBlog - Medium
G
GRAHAM CLULEY
Engineering at Meta
Engineering at Meta
博客园 - 叶小钗
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog
人人都是产品经理
人人都是产品经理
I
Intezer
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
IT之家
IT之家
V
Vulnerabilities – Threatpost
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LangChain Blog
Google Online Security Blog
Google Online Security Blog
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
雷峰网
雷峰网

Mohuishou

如何实现支持多集群的 Kubernetes Operator? 第三方应用如何调用我们 kubebuilder 生成的自定义资源? Kubernetes 简明教程 k8s job 为何迟迟不能结束? Go 工程化(十一) 如何优雅的写出 repo 层代码 Go 工程化(十) 如何在整洁架构中使用事务? 给博客添加章节目录 使用 Notion Database 管理静态博客文章 一个普通 Go 开发的三年 4. localhost 就一定是 localhost 么? Go可用性(七) 总结: 一张图串联可用性知识点 Go可用性(六) 熔断 10. 总结 9. kubebuilder 进阶: 源码分析 8. kubebuilder 进阶: webhook 7. kubebuilder 进阶: 测试 6. kubebuilder 实战: status & event 5. kubebuilder 实战: CRUD 4. kustomize 简明教程 2. Kind: 如何快速搭建本地 K8s 开发环境? 1. Operator概述: 如何对 Kubernetes 进行扩展 Go可用性(五) 自适应限流 Go可用性(四) 漏桶算法 Go可用性(三) 令牌桶的实现 rate/limt Go可用性(二) 令牌桶原理及使用 Go可用性(一) 隔离设计 Go并发编程(十二) Singleflight Go工程化(九) 项目重构实践 Go工程化(八) 单元测试 Go工程化(七) Go Module Go工程化(六) 配置管理 Go工程化(五) API 设计下: 基于 protobuf 自动生成 gin 代码 Go工程化(四) API 设计上: 项目结构 & 设计 Go工程化(三) 依赖注入框架 wire Go工程化(二) 项目目录结构 Go工程化(一) 架构整洁之道阅读笔记 Go并发编程(十一) 总结 Go并发编程(十) 深入理解 Channel Go并发编程(九) 深入理解 Context Go并发编程(八) 深入理解 sync.Once Go并发编程(七) 深入理解 errgroup Go并发编程(六) 深入理解 WaitGroup Go并发编程(五) 深入理解 sync/atomic Go并发编程(四) 深入理解 Mutex Go并发编程(三) data race Go并发编程(二) Go 内存模型 Go并发编程(一) goroutine Go错误处理最佳实践 微服务(二) 服务发现&多租户 微服务(一) 微服务概览 5. 栈下: 深入理解 defer 4. 栈上: 如何实现一个计算器 Go Struct 初始化风格的抉择 3. 数组下: 使用 GDB 调试 Golang 代码 2. 数组上: 深入理解 slice 1. 链表: 深入理解container/list&LRU缓存的实现 Go设计模式24-总结(更新完毕) Go设计模式23-中介模式 Go设计模式22-解释器模式 Go设计模式21-命令模式 Go设计模式20-备忘录模式 Go设计模式19-访问者模式 Go设计模式18-迭代器模式 Go设计模式17-状态模式 Go设计模式16-职责链模式(Gin的中间件实现) Go设计模式15-策略模式 Go模板模式14-模板模式 Go设计模式13-观察者模式(实现简单的EventBus) Go设计模式12-享元模式 Go设计模式11-组合模式 Go设计模式10-门面模式 Go设计模式09-适配器模式 Go设计模式08-装饰器模式 Go设计模式07-桥接模式 Go设计模式06-代理模式(generate实现类似动态代理) Go设计模式05-创建型模式总结 Go设计模式04-原型模式 Go设计模式03-建造者模式 Go设计模式02-工厂模式&DI容器 笔记-让你最快速地改善代码质量的20条编程规范 Go设计模式01-单例模式 一点拙见-如何写好一个技术预研报告? Go Web小技巧(四)在单个仓库中支持多个 go mod 模块 Go Web 小技巧(三)Gin 参数绑定 Go Web 小技巧(二)GORM 使用自定义类型 Go Web 小技巧(一)简化Gin接口代码 善用工具之postman高级用法概述 go generate and ast hexo-next-algolia-search全文搜索 docker镜像瘦身&优化 GORM避坑指南之含关联关系的更新 Github Actions介绍&自动构建Github Pages博客 在blog中内嵌在线PPT 记一次net http内存泄漏 使用TravisCI自动部署Blog 使用Goland调试Go程序 一个十分边缘的gorm的bug Httprouter介绍及源码阅读 Gin源码阅读 从0.1开始
3. KubeBuilder 简明教程
Mohuishou · 2021-05-08 · via Mohuishou

注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用

Operator 概述

Operator 是 Kubernetes 的扩展软件,它利用 定制资源 管理应用及其组件。 Operator 遵循 Kubernetes 的理念,特别是在控制器 方面[1]

k8s 的是一个高度自动化的系统,其中涵盖了常见应用程序所需的大部分功能,例如服务发现,负载均衡,HPA等等,这些功能是由 k8s 自带的一些控制器实现的,但是需求总是永无止境的,当我们有类似需求但是 k8s 又无法很好的满足的时候我们就可以使用 Operator 和 Custome Resource(自定义资源)来达到类似的效果。

例如常见的需求就有部署一个数据库,节点自动化运维,日志采集组件配置等等

从 Operator 理念的提出到现在已经有了很多工具可以帮助我们快速低成本的开发,其中最常用的就是 CoreOS 开源的 operator-sdk[3]和 k8s sig 小组维护的 kubebuilder[2],我们这个系列选用 kubebuilder。

开始之前我们先了解两个马上就会涉及到的核心概念

GV & GVK & GVR

  • GV: Api Group & Version

    • API Group 是相关 API 功能的集合
    • 每个 Group 拥有一或多个 Versions
  • GVK: Group Version Kind

    • 每个 GV 都包含 N 个 api 类型,称之为 Kinds,不同 Version 同一个 Kinds 可能不同
  • GVR: Group Version Resource

    • ResourceKind 的对象标识,一般来 KindResource1:1 的,但是有时候存在 1:n 的关系,不过对于 Operator 来说都是 1:1 的关系

举个🌰,我们在 k8s 中的 yaml 文件都有下面这么两行,例如上篇文章我们部署的 nginx deployment

1
2
3
4
apiVersion: apps/v1 # 这个是 GV,G 是 apps,V 是 v1
kind: Deployment # 这个就是 Kind
sepc: # 加上下放的 spec 就是 Resource了
...

根据 GVK K8s 就能找到你到底要创建什么类型的资源,根据你定义的 Spec 创建好资源之后就成为了 Resource,也就是 GVR。GVK/GVR 就是 K8s 资源的坐标,是我们创建/删除/修改/读取资源的基础[4]

安装

  • 访问官方仓库下载已经编译好的二进制文件: Releases · kubernetes-sigs/kubebuilder (github.com)

    • 本文编写的时候 kubebuilder 已经推出了 v3.0.0-rc.0 版本,所以为了避免刚写完新版就已经 release 了的尴尬情况,本文直接使用的是 3.0 版本
    • 下载好了之后记得将对应文件加入 PATH 当中
  • 安装成功之后使用 kubebuilder version 可以查看安装的版本信息

    1
    2
    ❯ kubebuilder version
    Version: main.version{KubeBuilderVersion:"3.0.0-rc.0", KubernetesVendor:"1.19.2", GitCommit:"90fe4124c4c6965c6bfac63339888956952cda90", BuildDate:"2021-04-08T17:36:28Z", GoOs:"linux", GoArch:"amd64"}

项目初始化

先创建一个空文件夹,然后在文件夹内执行下方命令

1
kubebuilder init --domain lailin.xyz --repo github.com/mohuishou/blog-code/k8s-operator/02-kubebuilder
  • –-domain lailin.xyz 我们的项目的域名
  • --repo xxx 是仓库地址,同时也是 go mode中的repo地址

如果你 golang 版本过低或者过高都有可能出现下方的错误信息,我这里是因为使用的 1.16 版本太高了

1
2021/04/25 20:47:14 failed to initialize project: unable to run pre-scaffold tasks of "base.go.kubebuilder.io/v3": go version 'go1.16' is incompatible because 'requires 1.13 <= version < 1.16'. You can skip this check using the --skip-go-version-check flag

这种情况下可以添加 --skip-go-version-check 忽略这个错误,但是还是建议使用官方推荐的版本

1
kubebuilder init --domain lailin.xyz --repo github.com/mohuishou/blog-code/k8s-operator/02-kubebuilder --skip-go-version-check

项目目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.
├── Dockerfile
├── Makefile # 这里定义了很多脚本命令,例如运行测试,开始执行等
├── PROJECT # 这里是 kubebuilder 的一些元数据信息
├── config
│ ├── default # 一些默认配置
│ ├── manager # 部署 crd 所需的 yaml
│ ├── prometheus # 监控指标数据采集配置
│ └── rbac # 部署所需的 rbac 授权 yaml
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
└── main.go

创建 api

1
kubebuilder create api --group apps --version v1 --kind Application

执行之后我们可以发现项目结构发生了一些变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
├── api
│ └── v1
│ ├── application_types.go # 这里是定义 spec 的地方
│ ├── groupversion_info.go # GV 的定义,一般无需修改
│ └── zz_generated.deepcopy.go
├── config
│ ├── crd # 自动生成的 crd 文件,不用修改这里,只需要修改了 v1 中的 go 文件之后执行 make generate 即可
│ ├── default
│ ├── manager
│ ├── prometheus
│ ├── rbac
│ └── samples # 这里是 crd 示例文件,可以用来部署到集群当中
├── controllers
│ ├── application_controller.go # 在这里实现 controller 的逻辑
│ └── suite_test.go # 这里写测试

实现 Controller

定义 CR

1
2
3
4
5
6
7
8
9
10
11
// api/v1/application_types.go

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

// Product 该应用所属的产品
Product string `json:"product,omitempty"`
}

修改之后我们执行一下 make manifests generate 可以发现已经生成了相关的字段,并且代码中的字段注释也就是 yaml 文件中的注释

1
2
3
4
5
6
7
# config/crd/bases/apps.lailin.xyz_applications.yaml
......
properties:
product:
description: Product 该应用所属的产品
type: string
......

实现 controller

kubebuilder 已经帮我们实现了 Operator 所需的大部分逻辑,我们只需要在 Reconcile 中实现业务逻辑就行了

1
2
3
4
5
6
7
8
9
// controllers/application_controller.go

func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = r.Log.WithValues("application", req.NamespacedName)

r.Log.Info("app changed", "ns", req.Namespace)

return ctrl.Result{}, nil
}

逻辑修改好之后,我们先执行 make install 安装 CRD,然后执行 make run运行 controller

1
2
3
4
5
6
7
go run ./main.go
2021-04-25T21:55:55.578+0800 INFO controller-runtime.metrics metrics server is starting to listen {"addr": ":8080"}
2021-04-25T21:55:55.579+0800 INFO setup starting manager
2021-04-25T21:55:55.579+0800 INFO controller-runtime.manager starting metrics server {"path": "/metrics"}
2021-04-25T21:55:55.579+0800 INFO controller-runtime.manager.controller.application Starting EventSource {"reconciler group": "apps.lailin.xyz", "reconciler kind": "Application", "source": "kind source: /, Kind="}
2021-04-25T21:55:55.680+0800 INFO controller-runtime.manager.controller.application Starting Controller {"reconciler group": "apps.lailin.xyz", "reconciler kind": "Application"}
2021-04-25T21:55:55.680+0800 INFO controller-runtime.manager.controller.application Starting workers {"reconciler group": "apps.lailin.xyz", "reconciler kind": "Application", "worker count": 1}

然后我们部署一个测试的 crd kubectl apply -f config/samples/apps_v1_application.yaml

1
2
3
4
5
6
7
apiVersion: apps.lailin.xyz/v1
kind: Application
metadata:
name: application-sample
spec:
# Add fields here
product: test

然后可以看到之前写的日志逻辑已经触发

1
2021-04-25T21:57:12.618+0800    INFO    controllers.Application app changed     {"ns": "default"}

Kubebuilder 注释

在生成的代码当中我们可以看到很多 //+kubebuilder:xxx 开头的注释,对 Go 比较熟悉的同学应该知道这些注释是给对应的代码生成器服务的,在 Go 中有一个比较常用的套路就是利用 go gennerate生成对应的 go 代码。

kubebuilder 使用 controller-gen 生成代码和对应的 yaml 文件,这其中主要包含 CRD 生成、验证、处理还有 WebHook 的 RBAC 的生成功能,下面我简单介绍一下,完整版可以看 kubebuilder 的官方文档

  • CRD 生成
    • //+kubebuilder:subresource:status 开启 status 子资源,添加这个注释之后就可以对 status进行更新操作了
    • //+groupName=nodes.lailin.xyz 指定 groupname
    • //+kubebuilder:printcolumnkubectl get xxx 添加一列,这个挺有用的
    • ……
  • CRD 验证,利用这个功能,我们只需要添加一些注释,就给可以完成大部分需要校验的功能
    • //+kubebuilder:default:=<any> 给字段设置默认值
    • //+kubebuilder:validation:Pattern:=string 使用正则验证字段
    • ……
  • Webhook
    • //+kubebuilder:webhook 用于指定 webhook 如何生成,例如我们可以指定只监听 Update 事件的 webhook
  • RBAC 用于生成 rbac 的权限
    • //+kubebuilder:rbac

总结

这篇文章主要讲解了 kubebuilder的安装使用方式,以及涉及到的一些简单的概念,项目目录结构的说明,下一篇文章我们就一起来实现一个真实的 Operator 需求

参考文献

关注我获取更新

猜你喜欢