PodPreset注入信息到 Pods

PodPreset 介绍

PodPreset 是一种 K8s API 资源,用于在创建 Pod 时注入其他运行时需要的信息,这些信息包括 secrets、volume mounts、environment variables 等,我们可以使用标签选择器来指定某个或某些 Pod,来将 PodPreset 预设信息应用上去。使用 PodPreset 的好处就是我们可以将一些常用 Pod 预设信息配置为模板,这样就不需要显式为每个 Pod 提供所有信息,简化 Pod 初始化配置,还能起到配置统一的效果。

K8s 启用 PodPreset 配置

K8s 默认不开启 PodPreset 支持的,其 API 类型为 settings.k8s.io/v1alpha1,如果不确认集群是否已开启 PodPreset 支持,可以通过 kubectl api-versions 命令查看是否存在该类型,或者 kubectl get podpreset 命令查看,如果没开启会提示 error: the server doesn't have a resource type "podpreset" 错误。

启用 PodPreset,可以通过 K8s ApiServer 增加 --runtime-config=settings.k8s.io/v1alpha1=true 配置即可。Kubeadm 方式安装集群,可以在/etc/kubernetes/manifests路径下的kube-apiserver.yaml中追加如下命令:

1
--runtime-config=api/all,settings.k8s.io/v1alpha1=true

admission中添加:

1
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeClaimResize,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,Priority,PodPreset

待组件自动重启完毕后,可以再次检查是否已支持 PodPreset。

1
2
$ kubectl api-versions | grep settings.k8s.io
settings.k8s.io/v1alpha1

PodPreset 注入信息示例

现在我们演示一下,如何使用 PodPreset 注入信息到 Pod 中,这里举两个示例,一个是匹配指定 Pod 加载配置,另一个是匹配某个 Namespace 下所有 Pod 加载配置。

匹配指定 Pod 加载配置

上边提到过 使用标签选择器来指定某个或某些 Pod,来将 PodPreset 预设信息应用上去,这里我们来演示下如何匹配指定 Pod 加载配置。首先新建 PodPreset Yaml 资源文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ vim podpreset-busybox-hwy.yaml
apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
name: busybox-hwy
namespace: wanyang3
spec:
selector:
matchLabels:
role: busybox-hwy
env:
- name: PODPRESET_MESSAGE
value: "This is podpreset message."
volumeMounts:
- mountPath: /opt/logs
name: logs-volume
volumes:
- name: logs-volume
emptyDir: {}

可以看到如下几个关键信息:

  • PodPreset 资源 ApiVersion 为 settings.k8s.io/v1alpha1
  • 这里 selector.matchLabels 通过 Labels 匹配标签包含 role: busybox-hwy 的 Pod
  • 注入了 env 环境变量 PODPRESET_MESSAGE=This is podpreset message. 到匹配的 Pod 中
  • 注入了 volumes 卷挂载目录到匹配的 Pod 中的 /opt/logs 目录

创建一下该 PodPreset 资源。

1
2
3
4
5
6
7
8
9
10
11
$ kubectl create ns wanyang3
namespace/wanyang3 created


$ kubectl apply -f podpreset-busybox-hwy.yaml
podpreset.settings.k8s.io/busybox-hwy created


$ kubectl get podpreset -n wanyang3
NAME CREATED AT
busybox-hwy 2019-07-07T02:10:31Z

接下来,我们来创建 Pod Yaml 资源文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vim pod-busybox-hwy.yaml 
apiVersion: v1
kind: Pod
metadata:
name: busybox-hwy
namespace: wanyang3
labels:
app: busybox-hwy
role: busybox-hwy
spec:
containers:
- name: busybox-hwy
image: busybox:latest
command: ["sleep", "60000"]

注意:这里我以 busybox 容器来测试,这里 labels role: busybox-hwy 要跟上边 PodPreset selector.matchLabels 匹配上,否则将没法注入信息。那么创建一下该 Pod 资源。

1
2
3
4
5
6
7
$ kubectl apply -f pod-busybox-hwy.yaml
pod/busybox-hwy created


$ kubectl get pod -n wanyang3
NAME READY STATUS RESTARTS AGE
busybox-hwy 1/1 Running 0 15s

成功创建,进入到容器内验证一下 PodPreset 信息是否正确注入吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ kubectl exec -it busybox-hwy -n wanyang3 /bin/sh
/ # printenv |grep PODPRESET
PODPRESET_MESSAGE=This is podpreset message.
/ # df -h
Filesystem Size Used Available Use% Mounted on
overlay 36.0G 9.3G 26.7G 26% /
tmpfs 64.0M 0 64.0M 0% /dev
tmpfs 1.8G 0 1.8G 0% /sys/fs/cgroup
/dev/mapper/centos-root
36.0G 9.3G 26.7G 26% /opt/logs
/dev/mapper/centos-root
36.0G 9.3G 26.7G 26% /dev/termination-log
/dev/mapper/centos-root
36.0G 9.3G 26.7G 26% /etc/resolv.conf
/dev/mapper/centos-root
36.0G 9.3G 26.7G 26% /etc/hostname
/dev/mapper/centos-root
36.0G 9.3G 26.7G 26% /etc/hosts
......

验证没有问题,PodPreset 信息注入到 Pod 里面了,而我们的 Pod yaml 文件就非常简洁了,从而避免了某一个配置更改,所有相关的 Pod 都需要更新 Yaml 配置的麻烦,是不是很方便!咱们在更深入了解一下 PodPreset 实现的方式,此时获取 Pod 的 Yaml 文件看下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# kubectl get pod busybox-hwy -n wanyang3 -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
podpreset.admission.kubernetes.io/podpreset-busybox-hwy: "24187"
creationTimestamp: 2019-07-07T02:22:27Z
labels:
app: busybox-hwy
role: busybox-hwy
name: busybox-hwy
namespace: wanyang3
resourceVersion: "24302"
selfLink: /api/v1/namespaces/wanyang3/pods/busybox-hwy
uid: 1066b217-a05e-11e9-aab0-080027a076a9
spec:
containers:
- command:
- sleep
- "60000"
env:
- name: PODPRESET_MESSAGE
value: This is podpreset message.
image: busybox:latest
imagePullPolicy: Always
name: busybox-hwy
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /opt/logs
name: logs-volume
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-nnbrm
readOnly: true
dnsPolicy: ClusterFirst
nodeName: minikube
......

可以看到,经过 k8s admission controller 之后此时的 Yaml 文件是将 PodPreset 和 Pod 资源 Merge 合并了,同时增加了 podpreset.admission.kubernetes.io/podpreset-busybox-hwy: "24187" 这样的注解,类似模板的 Include 功能,而这个 24187 资源号就是上边 podpreset-busybox-hwy 创建完成之后的 resourceVersion: "24187" 资源版本号。

匹配某个 Namespace 下所有 Pod 加载配置

上边演示了匹配一个或多个指定 Pod 注入信息,如果我们想针对某个 Namespace 下的所有的 Pod 注入信息该如何配置呢?方法就是配置 selector.matchLabels 时匹配所有即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vim podpreset-ns-test.yaml 
apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
name: podpreset-ns-test
namespace: podpreset-test
spec:
selector:
matchLabels: #关键在这里,匹配所有
env:
- name: DB_PORT
value: "6379"
- name: TZ
value: Asia/Shanghai

说明一下:这里 matchLabels: 设置为空,表示匹配该 Namespaces 下所有,这里匹配 podpreset-test 命名空间下所有 Pod,并注入了 DB_PORT= 6379TZ=Asia/Shanghai 两个公用环境变量配置。注意:这里的 TZ=Asia/Shanghai 环境变量配置可以用于修改 Pod 所属时区,从而实现该命名空间所有的 Pod 统一更改时区(毕竟 Centos 默认时间为 UTC)。接下来,创建一下该 PodPreset 资源。

1
2
3
4
5
6
7
8
9
10
11
$ kubectl create ns podpreset-test
namespace/podpreset-test created


$ kubectl apply -f podpreset-ns-test.yaml
podpreset.settings.k8s.io/podpreset-ns-test created


$ kubectl get podpreset -n podpreset-test
NAME CREATED AT
podpreset-ns-test 2019-07-07T03:52:42Z

然后,分别创建多个 Pod 来注入该 PodPreset 信息。

1
2
3
4
5
6
7
8
9
10
11
12
$ vim pod-nginx-test-1.yaml 
apiVersion: v1
kind: Pod
metadata:
name: nginx-test-1
namespace: podpreset-test
labels:
app: nginx-test-1
spec:
containers:
- name: nginx-test-1
image: nginx:latest
1
2
3
4
5
6
7
8
9
10
11
12
$ vim pod-nginx-test-2.yaml 
apiVersion: v1
kind: Pod
metadata:
name: nginx-test-2
namespace: podpreset-test
labels:
app: nginx-test-2
spec:
containers:
- name: nginx-test-2
image: nginx:latest

创建以上 Pod 资源,并分别验证是否注入信息成功。

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl apply -f pod-nginx-test-1.yaml
pod/nginx-test-1 created


$ kubectl apply -f pod-nginx-test-2.yaml
pod/nginx-test-2 created


$ kubectl get pod -n podpreset-test
NAME READY STATUS RESTARTS AGE
nginx-test-1 1/1 Running 0 26s
nginx-test-2 1/1 Running 0 20s

分别进入容器内验证是否注入成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ kubectl exec -it nginx-test-1 -n podpreset-test /bin/sh
# printenv
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=nginx-test-1
DB_PORT=6379
HOME=/root
PKG_RELEASE=1~stretch
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
NGINX_VERSION=1.17.1
......
PWD=/
TZ=Asia/Shanghai
# date
Sun Jul 7 12:16:53 CST 2019
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ kubectl exec -it nginx-test-2 -n podpreset-test /bin/sh
# printenv
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=nginx-test-2
DB_PORT=6379
HOME=/root
PKG_RELEASE=1~stretch
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
NGINX_VERSION=1.17.1
......
PWD=/
TZ=Asia/Shanghai
# date
Sun Jul 7 12:17:26 CST 2019

可以看到,该 Namespace 下的两个 Pod 都成功注入了配置信息,时区也改过来了,是不是很方便了。不过,如果想指定该 Namespace 下某个 Pod 不使用该 PodPreset 该如何配置呢?毕竟有些个性化的 Pod 不使用通用配置。我们可以配置 podpreset.admission.kubernetes.io/exclude: "true" 注解来注明该 Pod 不注入 PodPreset,接下来演示一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vim pod-nginx-test-3.yaml 
apiVersion: v1
kind: Pod
metadata:
name: nginx-test-3
namespace: podpreset-test
annotations:
podpreset.admission.kubernetes.io/exclude: "true"
labels:
app: nginx-test-3
spec:
containers:
- name: nginx-test-3
image: nginx:latest

创建该 Pod 资源,验证信息是否注入容器进去。

1
2
3
4
5
6
$ kubectl apply -f pod-nginx-test-3.yaml
$ kubectl exec -it nginx-test-3 -n podpreset-test /bin/sh
$ printenv | grep TZ
$ printenv | grep DB_PORT
$ date
Sun Jul 7 04:18:54 UTC 2019

可以看到,添加了忽略 PodPreset 注入 annotations 后,没有将信息注入进去,时间还是默认的 UTC 时间。

PodPreset 除了上边演示的两种用法外,还支持多 PodPreset 应用到同一 Pod,支持多种资源类型(ReplicaSet 等),支持从 ConfigMap 中取值。同时要说明一下,当 PodPreset 跟 Pod 配置有冲突时,例如 Pod Yaml 容器挂载配置跟 PodPreset 容器挂载配置为同一路径时,会报错提示冲突。

最后要提一下注意的问题:

  • 目前 PodPreset 的预设功能这块还在演进中,不过已经能大大简化了相关的管理工作,将这些公用配置从开发者手中分离出来,变成系统管理配置。
  • PodPreset 是 Namespace 级别的对象,其作用范围只能是同一个命名空间下容器。
  • 目前为 v1alpha1 版本,还不成熟,例如当我们对已创建的 PodPreset 执行非常少量的修改时,重新 apply 或者 replace 时,服务端并没有更新过来(亲测会有问题,只能删除重建),大家可以自己尝试下。

参考资料


PodPreset注入信息到 Pods
https://system51.github.io/2019/08/26/PodPreset/
作者
Mr.Ye
发布于
2019年8月26日
许可协议