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 service
import (
"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 {
// 获取 clientSet
myClientSet := 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.")
}
// 符号 ~ 需要转换为 ~0
if strings.Contains(key, "~") {
key = strings.Replace(key, "~", "~0", -1)
}
if strings.Contains(key, "/") {
// 符号 / 需要转换为 ~1
key = strings.Replace(key, "/", "~1", -1)
}
// 需要修改的 annotation 的键值对
patchObj := struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value"`
}{
Op: "replace", // 可以使用add 或 replace
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
}
// 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 {
// 获取 clientSet
myClientSet := 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
}
// 符号 ~ 需要转换为 ~0
if strings.Contains(key, "~") {
key = strings.Replace(key, "~", "~0", -1)
}
// 符号 / 需要转换为 ~1
if 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 service
import (
"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中文文档