使用 Go 构建 Kubernetes 应用
点击上方 "编程技术圈"关注, 星标或置顶一起成长
后台回复“大礼包”有惊喜礼包!
每日英文
There is a time in life that is full of uneasiness.We have no other choice but to face it.
生命中总有那么一段时光,充满不安,可是除了勇敢面对,我们别无选择。
每日掏心话
你过得快不快乐,只有你自己知道。如果用乐观旷达,积极向上的心态去看待,那么,坏机会也会成为好机会。
责编:乐乐 | 来自:Linux爱好者
编程技术圈(ID:study_tech)第 1168 次推文
往日回顾:记住看小电影前一定要检查网址是不是 HTTPS 的,不然…
正文
Kubernetes项目使用Go语言编写,对Go api原生支持非常便捷。本篇文章介绍了如何使用kubernetes client-go实践一个简单的与K8s交互过程。
kubernetes 的Go Client项目(client-go)
go client是k8s client中最古老的一个,具有很多特性。Client-go 没有使用Swagger生成器,它使用的是源于k8s项目中的源代码生成工具,这个工具的目的是要生成k8s风格的对象和序列化程序。
该项目是一组包的集合,该包能够满足从REST风格的原语到复杂client的不同的编程需求。
RESTClient是一个基础包,它使用api-machinery
库中的类型作为一组REST原语提供对API的访问。作为对RESTClient
之上的抽象,_clientset_将是你创建k8s client工具的起点。它暴露了公开化的API资源及其对应的序列化。
注意:在 client-go中还包含了如discovery, dynamic, 和 scale这样的包,虽然本次不介绍这些包,但是了解它们的能力还是很重要的。
一个简单的k8s client 工具
让我们再次回顾我们将要构建的工具,来说明go client的用法。pvcwatch是一个简单的命令行工具,它可以监听集群中声明的PVC容量。当总数到达一个阈值的时候,他会采取一个action(在这个例子中是在屏幕上通知显示)
你能在github上找到完整的例子
这个例子是为了展示k8s的go client的以下几个方面:- 如何去连接 - 资源列表的检索和遍历 - 对象监听
Setup
client-go支持Godep和dep作为vendor的管理程序,我觉得dep便于使用所以继续使用dep。例如,以下是client-go v6.0和k8s API v1.9所需最低限度的Gopkg.toml
。
[[constraint]]name = "k8s.io/api"version = "kubernetes-1.9.0"
[[constraint]]name = "k8s.io/apimachinery"version = "kubernetes-1.9.0"
[[constraint]]name = "k8s.io/client-go"version = "6.0.0"
运行dep ensure
确保剩下的工作。
连接 API Server
我们Go client的第一步就是建立一个与API Server的连接。为了做到这一点,我们要使用实体包中的clientcmd
,如下代码所示:
import (
..."k8s.io/client-go/tools/clientcmd"
)
func main() {kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config",)config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)if err != nil {log.Fatal(err)}
...
}
_Client-go_通过提供实体功能来从不同的上下文中获取你的配置,从而使之成为一个不重要的任务。
从config文件
正如上面的例子所做的那样,你能从kubeconfig文件启动配置来连接API server。当你的代码运行在集群之外的时候这是一个理想的方案。clientcmd.BuildConfigFromFlags("", configFile)
从集群
当你的代码运行在这个集群中的时候,你可以用上面的函数并且不使用任何参数,这个函数就会通过集群的信息去连接api server。
在公众号编程技术圈后台回复“架构整洁”,获取一份惊喜礼包。
clientcmd.BuildConfigFromFlags("", "")
或者我们可以通过rest包来创建一个使用集群中的信息去配置启动的(译者注:k8s里所有的Pod都会以Volume的方式自动挂载k8s里面默认的ServiceAccount,所以会用默认的ServiceAccount的授权信息),如下:
import "k8s.io/client-go/rest"
...
rest.InClusterConfig()
创建一个clientset
我们需要创建一个序列化的client为了让我们获取API对象。在kubernetes
包中的Clientset类型定义,提供了去访问公开的API对象的序列化client,如下:
type Clientset struct {*authenticationv1beta1.AuthenticationV1beta1Client*authorizationv1.AuthorizationV1Client
...*corev1.CoreV1Client
}
一旦我们有正确的配置连接,我们就能使用这个配置去初始化一个clientset,如下:
func main() {config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)...clientset, err := kubernetes.NewForConfig(config)if err != nil {log.Fatal(err)}
}
对于我们的例子,我们使用的是v1
的API对象。下一步,我们要使用clientset通过CoreV1()
去访问核心api资源,如下:
func main() {...clientset, err := kubernetes.NewForConfig(config)if err != nil {log.Fatal(err)}api := clientset.CoreV1()
}
你能在这里看到可以获得clientsets。
获取集群的PVC列表
我们对clientset执行的最基本操作之一获取存储的API对象的列表。在我们的例子中,我们将要拿到一个namespace下面的pvc列表,如下:
import (
...metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func main() {var ns, label, field stringflag.StringVar(&ns, "namespace", "", "namespace")flag.StringVar(&label, "l", "", "Label selector")flag.StringVar(&field, "f", "", "Field selector")
...api := clientset.CoreV1()// setup list optionslistOptions := metav1.ListOptions{LabelSelector: label, FieldSelector: field,}pvcs, err := api.PersistentVolumeClaims(ns).List(listOptions)if err != nil {log.Fatal(err)}printPVCs(pvcs)
...
}
在上面的代码中,我们使用ListOptions
指定 label 和 field selectors (还有namespace)来缩小pvc列表的范围,这个结果的返回类型是v1.PeristentVolumeClaimList
。下面的这个代码展示了我们如何去遍历和打印从api server中获取的pvc列表。
func printPVCs(pvcs *v1.PersistentVolumeClaimList) {template := "%-32s%-8s%-8s\n"fmt.Printf(template, "NAME", "STATUS", "CAPACITY")for _, pvc := range pvcs.Items {quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]fmt.Printf(template, pvc.Name, string(pvc.Status.Phase), quant.String())}
}
监听集群中pvc
k8s的Go client框架支持为指定的API对象在其生命周期事件中监听集群的能力,包括创建,更新,删除一个指定对象时候触发的CREATED
,MODIFIED
,DELETED
事件。对于我们的命令行工具,我们将要监听在集群中已经声明的PVC的总量。
对于某一个namespace,当pvc的容量到达了某一个阈值(比如说200Gi),我们将会采取某个动作。为了简单起见,我们将要在屏幕上打印个通知。但是在更复杂的实现中,可以使用相同的办法触发一个自动操作。
启动监听功能
现在让我们为PersistentVolumeClaim
这个资源通过Watch
去创建一个监听器。然后这个监听器通过ResultChan
从go的channel中访问事件通知。
func main() {
...api := clientset.CoreV1()listOptions := metav1.ListOptions{LabelSelector: label, FieldSelector: field,}watcher, err :=api.PersistentVolumeClaims(ns).Watch(listOptions)if err != nil {log.Fatal(err)}ch := watcher.ResultChan()
...
}
循环事件
接下来我们将要处理资源事件。但是在我们处理事件之前,我们先声明resource.Quantity
类型的的两个变量为maxClaimsQuant
和totalClaimQuant
来分别表示我们的申请资源阈值(译者注:代表某个ns下集群中运行的PVC申请的上限)和运行总数。
import("k8s.io/apimachinery/pkg/api/resource"...
)
func main() {var maxClaims stringflag.StringVar(&maxClaims, "max-claims", "200Gi", "Maximum total claims to watch")var totalClaimedQuant resource.QuantitymaxClaimedQuant := resource.MustParse(maxClaims)
...ch := watcher.ResultChan()for event := range ch {pvc, ok := event.Object.(*v1.PersistentVolumeClaim)if !ok {log.Fatal("unexpected type")}...}
}
在上面的for-range
循环中,watcher的channel用于处理来自服务器传入的通知。每个事件赋值给变量event,并且event.Object
的类型被声明为PersistentVolumeClaim
类型,所以我们能从中提取出来。
处理ADDED事件
当一个新的PVC创建的时候,event.Type
的值被设置为watch.Added
。然后我们用下面的代码去获取新增的声明的容量(quant
),将其添加到正在运行的总容量中(totalClaimedQuant
)。最后我们去检查是否当前的容量总值大于当初设定的最大值(maxClaimedQuant
),如果大于的话我们就触发一个事件。
import("k8s.io/apimachinery/pkg/watch"...
)
func main() {
...for event := range ch {pvc, ok := event.Object.(*v1.PersistentVolumeClaim)if !ok {log.Fatal("unexpected type")}quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]switch event.Type {case watch.Added:totalClaimedQuant.Add(quant)log.Printf("PVC %s added, claim size %s\n", pvc.Name, quant.String())if totalClaimedQuant.Cmp(maxClaimedQuant) == 1 {log.Printf("\nClaim overage reached: max %s at %s",maxClaimedQuant.String(),totalClaimedQuant.String())// trigger actionlog.Println("*** Taking action ***")}}...}}
}
处理DELETED事件
代码也会在PVC被删除的时候做出反应,它执行相反的逻辑以及把被删除的这个PVC申请的容量在正在运行的容量的总值里面减去。
在公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。
func main() {
...for event := range ch {...switch event.Type {case watch.Deleted:quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]totalClaimedQuant.Sub(quant)log.Printf("PVC %s removed, size %s\n", pvc.Name, quant.String())if totalClaimedQuant.Cmp(maxClaimedQuant) <= 0 {log.Printf("Claim usage normal: max %s at %s",maxClaimedQuant.String(),totalClaimedQuant.String(),)// trigger actionlog.Println("*** Taking action ***")}}...}
}
运行程序
当程序在一个运行中的集群被执行的时候,首先会列出PVC的列表。然后开始监听集群中新的PersistentVolumeClaim
事件。
$> ./pvcwatch
Using kubeconfig: /Users/vladimir/.kube/config
--- PVCs ----
NAME STATUS CAPACITY
my-redis-redis Bound 50Gi
my-redis2-redis Bound 100Gi
-----------------------------
Total capacity claimed: 150Gi
-----------------------------
--- PVC Watch (max claims 200Gi) ----
2018/02/13 21:55:03 PVC my-redis2-redis added, claim size 100Gi
2018/02/13 21:55:03
At 50.0% claim capcity (100Gi/200Gi)
2018/02/13 21:55:03 PVC my-redis-redis added, claim size 50Gi
2018/02/13 21:55:03
At 75.0% claim capcity (150Gi/200Gi)
下面让我们部署一个应用到集群中,这个应用会申请75Gi
容量的存储。(例如,让我们通过helm去部署一个实例influxdb)。
helm install --name my-influx \
--set persistence.enabled=true,persistence.size=75Gi stable/influxdb
正如下面你看到的,我们的工具立刻反应出来有个新的声明以及一个警告因为当前的运行的声明总量已经大于我们设定的阈值。
--- PVC Watch (max claims 200Gi) ----
...
2018/02/13 21:55:03
At 75.0% claim capcity (150Gi/200Gi)
2018/02/13 22:01:29 PVC my-influx-influxdb added, claim size 75Gi
2018/02/13 22:01:29
Claim overage reached: max 200Gi at 225Gi
2018/02/13 22:01:29 *** Taking action ***
2018/02/13 22:01:29
At 112.5% claim capcity (225Gi/200Gi)
相反,从集群中删除一个PVC的时候,该工具会相应展示提示信息。
...
At 112.5% claim capcity (225Gi/200Gi)
2018/02/14 11:30:36 PVC my-redis2-redis removed, size 100Gi
2018/02/14 11:30:36 Claim usage normal: max 200Gi at 125Gi
2018/02/14 11:30:36 *** Taking action ***
总结
这篇文章是进行的系列的一部分,使用Go语言的官方k8s客户端与API server进行交互。和以前一样,这个代码会逐步的去实现一个命令行工具去监听指定namespace下面的PVC的大小。这个代码实现了一个简单的监听列表去触发从服务器返回的资源事件。
PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!
欢迎加入后端架构师交流群,在后台回复“学习”即可。
猜你还想看
阿里、腾讯、百度、华为、京东最新面试题汇集
图解 Git 工作原理,看了秒懂!
入职腾讯第九年,我辞职了
12 个顶级 Bug 跟踪工具(建议收藏)
BAT等大厂Java面试经验总结
别找了,想获取 Java大厂面试题学习资料
扫下方二维码回复「手册」就好了
嘿,你在看吗?
使用 Go 构建 Kubernetes 应用相关推荐
- 我如何构建Kubernetes集群,以便我的同事可以更快地部署应用程序
by cheungpat 通过cheungpat 我如何构建Kubernetes集群,以便我的同事可以更快地部署应用程序 (How I built a Kubernetes cluster so my ...
- 树莓派开始玩转linux pdf_用树莓派构建 Kubernetes 集群 | Linux 中国
将 Kubernetes 安装在多个树莓派上,实现自己的"家庭私有云"容器服务. • 来源:linux.cn • 作者:Chris Collins • 译者:Xingyu.Wang ...
- 在 VMware vSphere 中构建 Kubernetes 存储环境
作者:马伟,青云科技容器顾问,云原生爱好者,目前专注于云原生技术,云原生领域技术栈涉及 Kubernetes.KubeSphere.kubekey等. 相信很多小伙伴和企业在构建容器集群时都会考虑存储 ...
- 深入构建Kubernetes基础架构
原文发表于kubernetes中文社区,为作者原创翻译 ,原文地址 更多kubernetes文章,请多关注kubernetes中文社区 目录 架构 入口点:DNS 内容分发网络(CDN) 负载均衡器 ...
- 基于Centos7构建Kubernetes平台
防伪码:我已经过了餐桌上有只鸡就一定能吃到鸡腿的年纪了. Kubernetes作为Docker生态圈中重要一员,是Google多年大规模容器管理技术的开源版本,是产线实践经验的最佳表现[G1].如Ur ...
- OpenYurt 深度解读:如何构建 Kubernetes 原生云边高效协同网络?
作者 | 郑超 导读:OpenYurt 是阿里巴巴开源的云边协同一体化架构,与同类开源方案相比,OpenYurt 拥有可实现边缘计算全场景覆盖的能力.在之前的一篇文章中,我们介绍了 OpenYurt ...
- 使用minikube在windows构建kubernetes群集
关注公众号"风色年代"订阅更多精彩文章,本博大部分文章为转载并已标明原文出处,如有再转敬请保留,请自觉尊重原创作者的劳动成果! 原文:http://www.cnblogs.com/ ...
- 基于Kubernetes构建Docker集群管理详解
from: 基于Kubernetes构建Docker集群管理详解 Kubernetes是Google开源的容器集群管理系统,基于Docker构建一个容器的调度服务,提供资源调度.均衡容灾.服务注册.动 ...
- Kubernetes构建过程分析
构建方式 Kubernetes的构建方式可以分为3种,分别是本地环境构建.容器环境构建.Bazel环境构建. Kubernetes构建方式: 本地环境构建 make make all 容器环境构建 m ...
最新文章
- SQLServer之DEFAULT约束
- ATT将在伦敦建设第二个数据中心
- 知识图谱基础知识(一): 概念和构建
- 【模板小程序】求M~N范围内的质数个数
- SAP HANA,S/4HANA 和 SAP BTP 的辨析
- 织梦服务器怎么修改,织梦dedecms更换服务器搬家教程
- python批量运行cmd_python 批量ssh并执行命令
- 一个发人深省的经典理财故事
- 内存调试工具Electric Fence
- 操作系统形式化验证实践教程(1) - 证明第一个定理
- 飞轮效应中的复利:相信时间的力量
- 优锘科技:渲染引擎T3D:WebGL端数字孪生应用最优解
- 原始人到春秋战国历史常识整理
- 降级论,升维思考,降维攻击
- 计算机中1 tb的硬盘容量大小等于,大脑记忆容量等于多大硬盘?
- 新手预算2000元左右买什么吉他好?高性价比单板民谣吉他推荐
- 数据集加载的几种方法
- 中国分省30米DEM(NASA 2020版)
- ps参考线设置,ps参考线定位,ps参考线怎么用
- 安装mysql最后一步未响应(解决方法)
热门文章
- Git和Gitee的使用(仅分享一下自己成功的过程)
- 再说说微软为什么会转型成功
- 从ARM处理器,看“贵云黔芯”国产自主安全解决方案
- Java中Number转为百分比
- OAuth2.0实现自定义颁发token
- DBA之路:小小DBA一年工作总结
- StoryDALL-E复现(基于预训练文本到图像Transformer的故事续编)
- 联想开机启动项按哪个_联想启动u盘按什么键_联想笔记本按哪个键进入u盘启动-win7之家...
- 惠普1005打印机自检页_hp1005打印机自检报告.docx
- Ubuntu16.04系统nvidia显卡上图形界面及OpenGL环境搭建心得