client-go是kubernetes官方出的go语言操作k8s对象的sdk
一,基本操作
1.1 初始化配置
// 读取k8s配置,
config, err := clientcmd.BuildConfigFromFlags("", "/Users/guqingbo/.kube/config")
if err != nil {
klog.Fatal(err)
}
//根据配置创建客户端对象
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
klog.Fatal(err)
}
k8s配置放在用户目录下的.kube下面,我的k8s配置是上文启动minikube集群配置
1.2 操作资源
k8s的接口设计遵循了restful原则,对于各种资源,一般都有create,delete,update,get,patch这些标准的操作,并且client-go对各种内置资源进行了对象封装,如图:
1.2.1 pod Get
func (k kubernetesExample) getPod(ctx context.Context) {
pod, err := k.clientSet.CoreV1().Pods("kube-system").Get(ctx, "kube-apiserver-minikube", metav1.GetOptions{})
if err != nil {
k.logger.Error(err, "getPod")
return
}
k.logger.Info("getPod:%v", pod)
}
kubernetesExample是我demo封装的对象,无需关注,上述代码在minikube集群正常运行的情况下,可以轻松的获得apiserver的pod所有属性值
1.2.2 pod Patch
patch操作相对复杂,并且分为4中操作类型,详细解释可以看这篇文章:k8s.iswbm.com/extra/p03_k…
const (
JSONPatchType PatchType = "application/json-patch+json"
MergePatchType PatchType = "application/merge-patch+json"
StrategicMergePatchType PatchType = "application/strategic-merge-patch+json"
ApplyPatchType PatchType = "application/apply-patch+yaml"
)
//先添加标签,然后删除标签
func (k kubernetesExample) patchPod(ctx context.Context) {
//给pod的/metadata/annotations,增加一个alex:gu的标签
pod, err := k.clientSet.CoreV1().Pods("kube-system").
Patch(ctx, "kube-apiserver-minikube", types.JSONPatchType,
[]byte(`[{"op": "add", "path": "/metadata/annotations/alex", "value": "gu"}]`),
metav1.PatchOptions{})
if err != nil {
k.logger.Error(err, "patch add")
return
}
k.logger.Info("patch add:", "alex", pod.GetObjectMeta().GetAnnotations()["alex"])
//给pod的/metadata/annotations,移除alex:gu的标签
pod, err = k.clientSet.CoreV1().Pods("kube-system").
Patch(ctx, "kube-apiserver-minikube", types.JSONPatchType,
[]byte(`[{"op": "remove", "path": "/metadata/annotations/alex"}]`),
metav1.PatchOptions{})
if err != nil {
k.logger.Error(err, "patch remove")
return
}
k.logger.Info("patch remove:", "alex", pod.GetObjectMeta().GetAnnotations()["alex"])
}
如果只执行上面代码中的添加标签,不删除标签,然后在控制台执行
kubectl get pod kube-apiserver-minikube -oyaml -n kube-system|grep alex -C 5
可得到
一般k8s对象属性值很多,使用patch能节省非必要属性值传递,达到节省网络开销的目的,因此在k8s代码中,能在很多地方找到patch的应用,例如下面这段代码就是k8s源码中为pod添加ownerReferences属性
1.2.3 pod list,watch操作
func (k kubernetesExample) listWatchPod(ctx context.Context) {
podList, err := k.clientSet.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{})
if err != nil {
k.logger.Error(err, "list err")
return
}
k.logger.Info("list", "len", len(podList.Items))
//从list获得的最后记录开始watch
watcher, err := k.clientSet.CoreV1().Pods("kube-system").Watch(ctx, metav1.ListOptions{ResourceVersion: podList.GetResourceVersion()})
if err != nil {
k.logger.Error(err, "watch err")
return
}
go func() {
for {
select {
case <-ctx.Done():
return
case event := <-watcher.ResultChan():
k.logger.Info("watcher", "event", event)
}
}
}()
}
程序启动,首先会打印出在kube-system空间下pod数量为7,并会阻塞,然后给pod:kube-apiserver-minikube的annotation加key,value,保存后会收到MODIFIED的event事件
二,dynamic操作
对于上面的操作方式,资源都是有具体类型声明的,属于强类型,对于确定的k8s资源有很好的代码规范能力,但是无法操作自定义资源,因此client-go还有一套dynamic的操作资源方式
2.1 创建自定义资源
func (d dynamicExample) create(ctx context.Context) {
rs, err := d.dynamicClient.Resource(schema.GroupVersionResource{
Group: "examples.alex.com", Version: "v1", Resource: "alexdynamics",
}).
Namespace(metav1.NamespaceDefault).
Create(ctx, &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "examples.alex.com/v1",
"kind": "AlexDynamic",
"metadata": map[string]interface{}{
"name": "alex-demo",
},
},
}, metav1.CreateOptions{})
if err != nil {
d.logger.Error(err, "create")
return
}
d.logger.Info("create:", "rs", rs)
}
注意对象GVR,GVK值的填写,具体意义可以参考这篇文章:
blog.csdn.net/qq_24433609…
但是直接运行这段代码会报错:
实际上我们要在k8s中管理新的自定义资源,首先需要把自定义资源定义告诉k8s
2.2 CRD定义
#resourcedefinition.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# 名字必需与下面的 spec 字段匹配,并且格式为 '<名称的复数形式>.<组名>'
name: alexdynamics.examples.alex.com
spec:
# 组名称,用于 REST API: /apis/<组>/<版本>
group: examples.alex.com
# 列举此 CustomResourceDefinition 所支持的版本
versions:
- name: v1
# 每个版本都可以通过 served 标志来独立启用或禁止
served: true
# 其中一个且只有一个版本必需被标记为存储版本
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
cronSpec:
type: string
image:
type: string
replicas:
type: integer
# 可以是 Namespaced 或 Cluster
scope: Namespaced
names:
# 名称的复数形式,用于 URL:/apis/<组>/<版本>/<名称的复数形式>
plural: alexdynamics
# 名称的单数形式,作为命令行使用时和显示时的别名
singular: alexdynamic
# kind 通常是单数形式的驼峰命名(CamelCased)形式。你的资源清单会使用这一形式。
kind: AlexDynamic
# shortNames 允许你在命令行使用较短的字符串来匹配资源
shortNames:
- ad
注意这里定义的GVK,GVR要与上面代码的对应,详细文档见:
kubernetes.io/zh-cn/docs/…
然后执行:
kubectl apply -f resourcedefinition.yaml
然后运行代码,创建自定义资源,就不会报错了,接着执行:
kubectl get alexdynamic
即可像操作k8s原生资源一样,操作自定义资源
三,上述示例代码
github.com/RainAlways/… ,tag:client-go-example-1