k8s secret对象详解
-
1. Secret 介绍-分为三大类
-
1.1 Opaque Secret方式
-
1.1.1 通过volume挂载和环境变量的区别
-
1.1.2 Secret 与 ConfigMap 对比
-
-
1.2 kubernetes.io/dockerconfigjson
-
1.3 Service Account类型
-
1.4 secret三种类型的原理
-
-
3.附录
-
3.1 K8S Configmap 和 Secret 作为 Volume 的热更新原理
-
热更新原理
-
参考文献
-
-
1. Secret 介绍-分为三大类
Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。
Secret有三种类型:
-
Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的
/run/secrets/kubernetes.io/serviceaccount目录中; -
Opaque:base64编码格式的Secret,用来存储密码、密钥等;
-
kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。
具体详见结构体定义:type Secret struct
1.1 Opaque Secret方式
Opaque类型的数据是一个map类型,要求value是base64编码格式:
$ echo -n "admin" | base64 YWRtaW4= $ echo -n "1f2d1e2e67df" | base64 MWYyZDFlMmU2N2Rm
secrets.yml
apiVersion: v1 kind: Secret metadata:name: mysecret type: Opaque data:password: MWYyZDFlMmU2N2Rmusername: YWRtaW4=
接着,就可以创建secret了:kubectl create -f secrets.yml。
创建好secret之后,有两种方式来使用它:
-
以Volume方式
-
以环境变量方式
(1)volume方式
#test-projected-volume.yamlapiVersion: v1 kind: Pod metadata:name: test-projected-volume spec:containers:- name: test-secret-volumeimage: busyboxargs:- sleep- "86400"volumeMounts:- name: mysql-credmountPath: "/projected-volume"readOnly: truevolumes:- name: mysql-credprojected:sources:- secret:name: user- secret:name: pass
当 Pod 变成 Running 状态之后,我们再验证一下这些 Secret 对象是不是已经在容器里了:
$ kubectl exec -it test-projected-volume -- /bin/sh $ ls /projected-volume/ user pass $ cat /projected-volume/user admin $ cat /projected-volume/pass
(2)通过环境变量
#pod-secret-env.yaml apiVersion: v1 kind: Pod metadata:name: pod-secret-env spec:containers:- name: myapp image: busybox args:- sleep- "86400" env:- name: SECRET_USERNAMEvalueFrom:secretKeyRef:name: mysecretkey: user- name: SECRET_PASSWORDvalueFrom:secretKeyRef:name: mysecretkey: passrestartPolicy: Never
pod运行成功后:
$ kubectl exec -it pod-secret-env -- /bin/sh
进入容器中查看环境变量: env
1.1.1 通过volume挂载和环境变量的区别
通过Volume挂载到容器内部时,当该Secret的值发生变化时,容器内部具备自动更新的能力,但是通过环境变量设置到容器内部该值不具备自动更新的能力。所以一般推荐使用Volume挂载的方式使用Secret。
热更新原理参考附录
1.1.2 Secret 与 ConfigMap 对比
最后我们来对比下Secret和ConfigMap这两种资源对象的异同点:
相同点:
key/value的形式
属于某个特定的namespace
可以导出到环境变量
可以通过目录/文件形式挂载
通过 volume 挂载的配置信息均可热更新
不同点:
Secret 可以被 ServerAccount 关联
Secret 可以存储 docker register 的鉴权信息,用在 ImagePullSecret 参数中,用于拉取私有仓库的镜像
Secret 支持 Base64 加密
Secret 分为 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque 三种类型,而 Configmap 不区分类型
1.2 kubernetes.io/dockerconfigjson
这个是为了应付 pull 私有image时候的权限问题。常见用法是:
(1)创建secrect
$ cat ~/.docker/config.json | base64 $ cat > myregistrykey.yaml <(2) 将这个secret和serviceaccount绑定
root@cld-kmaster1-1022:/home/ngadm# kubectl get serviceaccount -n test-nsp-gzchenyifan NAME SECRETS AGE default 1 3h28m root@cld-kmaster1-1022:/home/ngadm# kubectl get serviceaccount -n test-nsp-gzchenyifan -oyaml apiVersion: v1 items: - apiVersion: v1imagePullSecrets:- name: myregistrykeykind: ServiceAccountmetadata:creationTimestamp: "2022-11-03T06:00:30Z"name: defaultnamespace: test-testresourceVersion: "1540683279"selfLink: /api/v1/namespaces/test-nsp-gzchenyifan/serviceaccounts/defaultuid: 957739c2-cac9-4bae-bad9-0862ca413dd2secrets:- name: default-token-tb8xx //默认的secret kind: List metadata:resourceVersion: ""selfLink: ""// 再查看pod yaml的时候,就会发现指定了这个myregistrykeyimagePullSecrets:- name: nsp-dev1.3 Service Account类型
Service Account用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的
/run/secrets/kubernetes.io/serviceaccount目录中。$ kubectl run nginx --image nginx deployment "nginx" created $ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-3137573019-md1u2 1/1 Running 0 13s $ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount ca.crt namespace tokenserviceAccount资源介绍
参考github源码分析 https://github.com/zoux86/learning-k8s-source-code/blob/master/k8s/kube-apiserver/17-k8s%E4%B9%8Bserviceaccount.md
1.4 secret三种类型的原理
其实都是kubelet 的secretpulgin在起作用。如果是dockerconfig类型,他通过拉取secret的值,填充pod的imagePull策略。如果是service account, 他通过拉取sa, token值。
具体代码:pkg/volume/secret/secret.go
3.附录
3.1 K8S Configmap 和 Secret 作为 Volume 的热更新原理
configmap/secret 作为 volume 挂载在容器内,如果 configmap 值发生变化,最大等待时间在 kubelet resyncInterval(60s) 内 该 mount 的 key 就会变成最新值。比如 cilium pod 挂载 cilium-config configmap,如果修改该 configmap 的 debug:false 为 true, 最多等待 60s,容器内该 debug 文件值就是 true。
但是作为环境变量 env 和 volume subpath 不支持热更新,环境变量在初始化过程就固定了。
热更新原理
(1) kubelet 会在每 60s 内去 syncPod(),检查 pod 的 volume kubelet.volumeManager.WaitForAttachAndMount(pod), github.com/kubernetes/… github.com/kubernetes/…
这里重点是 ReprocessPod(),会把这个 pod 又标记为未处理,等待 desiredStateOfWorldPopulator 下一次循环去 MarkRemountRequired()
(2) desiredStateOfWorldPopulator 下一次循环,会走 findAndAddNewPods() -> processPodVolumes() 这里重点是 dswp.actualStateOfWorld.MarkRemountRequired(uniquePodName),在 actual 里 MarkRemountRequired github.com/kubernetes/… 这里会判断每一个 volumePlugin.RequiresRemount(),而对于 configmap/secret volume 是 true,对于 csi 是 false github.com/kubernetes/… github.com/kubernetes/… github.com/kubernetes/…
(3) 然后再下一次循环里去 mountAttachVolumes() PodExistsInVolume() 会走 podObj.remountRequired,因为 MarkRemountRequired() 已经设置了需要 remount,然后 mountAttachVolumes() 里走 MountVolume() 逻辑:github.com/kubernetes/… 这样就走 configmap/secret mount 逻辑。
(4) configmap/secret mount 会使用 emptyDir plugin 来创建落盘目录 configmap 用的 v1.StorageMediumDefault github.com/kubernetes/…
secret 用的 v1.StorageMediumMemory github.com/kubernetes/… , 对于 secret 首次 mount 会使用命令
mount -t tmpfs xxx: github.com/kubernetes/… github.com/kubernetes/…对于 configmap 这里的 wrapped 是 emptyDir,主要用来创建文件和权限
wrapped, err := b.plugin.host.NewWrapperMounter(b.volName, wrappedVolumeSpec(), &b.pod, *b.opts) wrapped.SetUpAt(dir, mounterArgs)// 这里的 getConfigMap 是 configmapManager 的 configMapManager.GetConfigMap() // https://github.com/kubernetes/kubernetes/blob/v1.19.7/pkg/kubelet/configmap/configmap_manager.go#L82-L91 // 注意,kubelet 默认使用 kubeletconfiginternal.WatchChangeDetectionStrategy 的 configmapManager,所以 configmap // 发生变化,configmapManager 立刻拿到最新的值:https://github.com/kubernetes/kubernetes/blob/v1.19.7/pkg/kubelet/kubelet.go#L538-L540 // 只是需要等待 kubelet 每次的 resyncInterval 60s 去 syncPod,所以每次修改 configmap 最大等待时间是 60s。 configMap, err := b.getConfigMap(b.pod.Namespace, b.source.Name)// 然后把最新的 configmap 对象数据写到每一个文件里 payload, err := MakePayload(b.source.Items, configMap, b.source.DefaultMode, optional) err = writer.Write(payload)复制代码参考文献
mounted-configmaps-are-updated-automatically
mounted-configmaps-are-updated-automatically
Kubernetes Pod 中的 ConfigMap 配置更新
分别测试使用 ConfigMap 挂载 Env 和 Volume 的情况
开始只有 NewCachingConfigMapManager(),除了 kubelet resyncInterval 时间还有个 ttl 时间,经过讨论后期加了 NewWatchingConfigMapManager, 直接 watch 立刻拿到最新的 configmap,只需要等待最大 kubelet resyncInterval 时间。下面链接是 issue 和 pr:
Kubelet watches necessary secrets/configmaps instead of periodic polling
Migrate kubelet to ConfigMapManager interface and use TTL-based caching manager
kubelet refresh times for configmaps is long and random
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
