PodPreset 是一种 K8s API 资源,用于在创建 Pod 时注入其他运行时需要的信息,这些信息包括 secrets、volume mounts、environment variables 等,我们可以使用标签选择器来指定某个或某些 Pod,来将 PodPreset 预设信息应用上去。使用 PodPreset 的好处就是我们可以将一些常用 Pod 预设信息配置为模板,这样就不需要显式为每个 Pod 提供所有信息,简化 Pod 初始化配置,还能起到配置统一的效果。
本次演示环境,我是在本机 MAC OS 上操作,以下是安装的软件及版本:
注意:这里 Kubernetes 集群搭建使用 Minikube 来完成,Minikube 启动的单节点 k8s Node 实例是需要运行在本机的 VM 虚拟机里面,所以需要提前安装好 VM,这里我选择 Oracle VirtualBox。k8s 运行底层使用 Docker 容器,所以本机需要安装好 Docker 环境,这里忽略 Docker、VirtualBox、Minikube、Kubectl 的安装过程,着重介绍一下如何配置 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
配置即可。Minikube 方式启动集群,可以在启动时追加如下命令:
minikube start --extra-config=apiserver.runtime-config=settings.k8s.io/v1alpha1=true --extra-config=apiserver.enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodPreset`
如果觉得以上命令太复杂,还可以通过修改 Yaml 方式配置,因为 Minikube 通过 Static Pod 的方式用 Kubelet 启动各组件服务,所以可以更改对应组件的 Yaml 来激活 PodPreset,通过修改 /etc/kubernetes/manifests/kube-apiserver.yaml
文件增加如下配置,修改完成后 Kubelet 会自动重启 kube-apiserver 各组件。
$ vim /etc/kubernetes/manifests/kube-apiserver.yaml
- --runtime-config=settings.k8s.io/v1alpha1=true #新增该配置
- --enable-admission-plugins=NamespaceLifecycle...,PodPreset #最后边增加 ,PodPreset 支持
截取修改后部分 kube-apiserver.yaml
文件如下:
spec:
containers:
- command:
- kube-apiserver
- --authorization-mode=Node,RBAC
- --enable-admission-plugins=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodPreset
- --runtime-config=settings.k8s.io/v1alpha1=true
- --advertise-address=172.30.12.98
- --allow-privileged=true
- --client-ca-file=/var/lib/minikube/certs/ca.crt
- --enable-bootstrap-token-auth=true
待组件重启完毕后,可以再次检查是否已支持 PodPreset。
$ kubectl api-versions | grep settings.k8s.io
settings.k8s.io/v1alpha1
现在我们演示一下,如何使用 PodPreset 注入信息到 Pod 中,这里举两个示例,一个是匹配指定 Pod 加载配置,另一个是匹配某个 Namespace 下所有 Pod 加载配置。
上边提到过 使用标签选择器来指定某个或某些 Pod,来将 PodPreset 预设信息应用上去
,这里我们来演示下如何匹配指定 Pod 加载配置。首先新建 PodPreset Yaml 资源文件。
$ 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: {}
可以看到如下几个关键信息:
settings.k8s.io/v1alpha1
selector. matchLabels
通过 Labels 匹配标签包含 role: busybox-why
的 Podenv
环境变量 PODPRESET_MESSAGE=This is podpreset message.
到匹配的 Pod 中volumes
卷挂载目录到匹配的 Pod 中的 /opt/logs
目录创建一下该 PodPreset 资源。
$ 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 资源文件。
$ 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 资源。
$ 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 信息是否正确注入吧!
$ 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 文件看下。
# 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"
资源版本号。
上边演示了匹配一个或多个指定 Pod 注入信息,如果我们想针对某个 Namespace 下的所有的 Pod 注入信息该如何配置呢?方法就是配置 selector.matchLabels
时匹配所有即可。
$ 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= 6379
和 TZ=Asia/Shanghai
两个公用环境变量配置。注意:这里的 TZ=Asia/Shanghai
环境变量配置可以用于修改 Pod 所属时区,之前我们修改 Centos 容器内部时间方式,可以参照 Docker/K8s 解决容器内时区不一致方案 文章,这里提供一个新的简便的方式配置时区,从而实现该命名空间所有的 Pod 统一更改时区(毕竟 Centos 默认时间为 UTC
)。接下来,创建一下该 PodPreset 资源。
$ 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 信息。
$ 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
$ 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 资源,并分别验证是否注入信息成功。
$ 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
# 分别进入容器内验证是否注入成功
$ 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
$ 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,接下来演示一下。
$ 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 资源,验证信息是否注入容器进去。
$ 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 容器挂载配置为同一路径时,会报错提示冲突。
最后要提一下注意的问题:
v1alpha1
版本,还不成熟,例如当我们对已创建的 PodPreset 执行非常少量的修改时,重新 apply 或者 replace 时,服务端并没有更新过来(亲测会有问题,只能删除重建),大家可以自己尝试下。参考资料