k8s中设置annotation的方法总结
annotation是什么
在 Kubernetes 中,Annotations 是一种用于向 Kubernetes 对象附加非标识性元数据的机制。
annotation有什么用
annotation与 Labels 类似,但有一些关键区别和特定用途。 常用于存储与对象相关的配置信息、工具信息、元数据等,但这些信息不会影响 Kubernetes 对象的调度或生命周期管理。
注意相比labels来说, annotation具有不可见性
: Annotations 不会被 Kubernetes API 用于选择或路由对象,因此不会影响调度决策或资源管理。
annotation的设置方式
我们可以为常见的资源种类,pod、pvc、pv、deployment、statefulset等设置annotation.
对于 annotation 的操作,只有3种:增加、删除、更新。(如果需要查看可以kubectl get pod -oyaml方式从详细信息中过滤)
方式一:kubectl annotate命令
# 为pod设置一个新的 annotation
root@dg02-k8s-pnode1:~# kubectl annotate pod ubuntu1604 it/city="shenzhen"
pod/ubuntu1604 annotated# 为pod修改存在的 annotation 对应的key/value
root@dg02-k8s-pnode1:~# kubectl annotate pod ubuntu1604 it/city="shanghai" --overwrite
pod/ubuntu1604 annotated# 删除 annotation 对应的key/value
root@dg02-k8s-pnode1:~# kubectl annotate pod ubuntu1604 it/city-
pod/ubuntu1604 annotated
方式二: kubectl patch命令
这里需要注意,在patch时,对于json串中的~
,/
需要分别转义为~0
和~1
# 增
kubectl patch pod --type=json -p='[{"op": "add", "path": "/metadata/annotations/it~1city", "value": "shenzhen"}]' ubuntu1604
# 改
kubectl patch pod --type=json -p='[{"op": "replace", "path": "/metadata/annotations/it~1city", "value": "shanghai"}]' ubuntu1604
# 删
kubectl patch pod --type=json -p='[{"op": "remove", "path": "/metadata/annotations/it~1city", "value": ""}]' ubuntu1604
方式三: client-go
除了前2种使用kubectl命令的方式,开发人员通常使用client-go对资源操控annotation
使用Patch方式更新K8S的 API Objects 一共有三种方式:strategic merge patch, json-patch,json merge patch。本文介绍最常用的json-patch,其他2种方式,请参考其他文献
本次示例以给一个pod新增一个annotation为例,直接上代码:
package serviceimport ("encoding/json""fmt""github.com/pkg/errors""go.uber.org/zap"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/types""kubecmdb/internal/buildk8s""kubecmdb/utils""strings"
)// AnnotationReplace 更新pod的annotation
func AnnotationReplace(clusterName, namespace, name, key string, value interface{}) error {// 获取 clientSetmyClientSet := buildk8s.GetK8SClientSet(clusterName)// 判断 pod 是否存在_, err := myClientSet.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})if err != nil {utils.Error("[annotation]", zap.String("err", err.Error()))return errors.Wrapf(err, "AnnotationAdd pod get err.")}// 符号 ~ 需要转换为 ~0if strings.Contains(key, "~") {key = strings.Replace(key, "~", "~0", -1)}if strings.Contains(key, "/") {// 符号 / 需要转换为 ~1key = strings.Replace(key, "/", "~1", -1)}// 需要修改的 annotation 的键值对patchObj := struct {Op string `json:"op"`Path string `json:"path"`Value interface{} `json:"value"`}{Op: "replace", // 可以使用add 或 replacePath: "/metadata/annotations/" + key,Value: value,}// 转换为json串var patchObjs []interface{}patchObjs = append(patchObjs, patchObj)patchData, err := json.Marshal(patchObjs)if err != nil {utils.Error("[annotation]", zap.String("err", err.Error()))return errors.Wrapf(err, "AnnotationAdd Marshal err.")}// 使用 Patch 方法修改//patchData:=fmt.Sprintf("'[{\"op\": \"replace\", \"path\": \"/metadata/annotations/it~1domain\", \"value\": \"xxx\"}]'")fmt.Printf("patchData=%v\n", string(patchData))_, err = myClientSet.CoreV1().Pods(namespace).Patch(name, types.JSONPatchType, patchData)if err != nil {utils.Error("[annotation]", zap.String("err", err.Error()))return errors.Wrapf(err, "AnnotationAdd Patch err.")}return nil}// AnnotationAdd 添加pod的annotation
func AnnotationAdd(clusterName, namespace, name, key string,value interface{}) error {return AnnotationReplace(clusterName, namespace, name, key, value)
}// AnnotationRemove 删除pod的annotation
func AnnotationRemove(clusterName, namespace, name, key string) error {// 获取 clientSetmyClientSet := buildk8s.GetK8SClientSet(clusterName)pod, err := myClientSet.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})if err != nil {utils.Error("[annotation]", zap.String("err", err.Error()))return errors.Wrapf(err, "AnnotationAdd pod get err.")}// 如果不存在,返回操作成功if _,ok := pod.ObjectMeta.Annotations[key];!ok {return nil}// 符号 ~ 需要转换为 ~0if strings.Contains(key, "~") {key = strings.Replace(key, "~", "~0", -1)}// 符号 / 需要转换为 ~1if strings.Contains(key, "/") {key = strings.Replace(key, "/", "~1", -1)}// 需要修改的 annotation 的键值对patchObj := struct {Op string `json:"op"`Path string `json:"path"`Value interface{} `json:"value"`}{Op: "remove",Path: "/metadata/annotations/" + key,Value: "", // 不需要填 value}// 转换为json串var patchObjs []interface{}patchObjs = append(patchObjs, patchObj)patchData, err := json.Marshal(patchObjs)if err != nil {utils.Error("[annotation]", zap.String("err", err.Error()))return errors.Wrapf(err, "AnnotationAdd Marshal err.")}// 使用 Patch 方法修改//patchData:=fmt.Sprintf("'[{\"op\": \"replace\", \"path\": \"/metadata/annotations/it~1domain\", \"value\": \"xxx\"}]'")fmt.Printf("patchData=%v\n", string(patchData))_, err = myClientSet.CoreV1().Pods(namespace).Patch(name, types.JSONPatchType, patchData)if err != nil {utils.Error("[annotation]", zap.String("err", err.Error()))return errors.Wrapf(err, "AnnotationAdd Patch err.")}return nil
}
单元测试
package serviceimport ("testing"
)// 更改
// go test -run "^TestAnnotationReplace$" -v
func TestAnnotationReplace(t *testing.T) {err := AnnotationReplace("dg11test", "public", "ubuntu1604", "it/city", "shanghai")if err != nil {t.Fatal(err)}
}// 添加
// go test -run "^TestAnnotationAdd$" -v
func TestAnnotationAdd(t *testing.T) {err := AnnotationAdd("dg11test", "public", "ubuntu1604", "it/city", "shenzhen")if err != nil {t.Fatal(err)}
}//删除
// go test -run "^TestAnnotationRemove$" -v
func TestAnnotationRemove(t *testing.T) {err := AnnotationRemove("dg11test", "public", "ubuntu1604", "it/city", )if err != nil {t.Fatal(err)}
}
参考文献
K8S client-go Patch example
kuberntes中文文档