在kubernetes中,新建的pod里面的时区默认是UTC-0,而对我们来说需要的时区是UTC-8,大家可能是这样来更改时区的:

  • 设置容器的时区环境变量
  • 挂载主机的时区文件到容器中

但是,难道每次每个容器都要做这样的配置才可以么?可否在系统层面设置,而无需在对应yaml文件体现呢?不然大量的yaml文件更改起来过于繁琐。答案是使用K8S的特性Pod Preset来控制容器启动前先配置好对应时区环境变量,或者挂载主机文件。

理解 Pod Preset


在 Pod 创建时,用户可以使用 PodPreset 对象将特定信息注入 Pod 中,这些信息可以包括 secret、 卷、卷挂载和环境变量

Pod Preset 是一种 API 资源,在 Pod 创建时,用户可以用它将额外的运行时需求信息注入 Pod。 使用标签选择器(label selector)来指定 Pod Preset 所适用的 Pod。

使用 Pod Preset 使得 Pod 模板编写者不必显式地为每个 Pod 设置信息。 这样,使用特定服务的 Pod 模板编写者不需要了解该服务的所有细节。

PodPreset 如何工作


Kubernetes 提供了准入控制器 (PodPreset),该控制器被启用时,会将 Pod Preset 应用于接收到的 Pod 创建请求中。 当出现 Pod 创建请求时,系统会执行以下操作:

  1. 检索所有可用 PodPresets 。
  2. 检查 PodPreset 的标签选择器与要创建的 Pod 的标签是否匹配。
  3. 尝试合并 PodPreset 中定义的各种资源,并注入要创建的 Pod。
  4. 发生错误时抛出事件,该事件记录了 pod 信息合并错误,同时在不注入 PodPreset 信息的情况下创建 Pod。
  5. 为改动的 Pod spec 添加注解,来表明它被 PodPreset 所修改。 注解形如: podpreset.admission.kubernetes.io/podpreset-“: ““。

一个 Pod 可能不与任何 Pod Preset 匹配,也可能匹配多个 Pod Preset。 同时,一个 PodPreset 可能不应用于任何 Pod,也可能应用于多个 Pod。 当 PodPreset 应用于一个或多个 Pod 时,Kubernetes 修改 pod spec。 对于 Env、 EnvFrom 和 VolumeMounts 的改动, Kubernetes 修改 pod 中所有容器的规格,对于卷的改动,Kubernetes 修改 Pod spec。

为特定 Pod 禁用 Pod Preset


在一些情况下,用户不希望 Pod 被 Pod Preset 所改动,这时,用户可以在 Pod spec 中添加形如 podpreset.admission.kubernetes.io/exclude: "true" 的注解。

启用 Pod Preset


在没有启动Pod Preset前,直接获取podpreset资源会报错:

1
2
[root@node-0 manifests]# kubectl get podpreset
error: the server doesn't have a resource type "podpreset"

为了在集群中使用 Pod Preset,必须确保以下几点:

  1. 已启用 API 类型 settings.k8s.io/v1alpha1/podpreset。 例如,这可以通过在 API 服务器的 –runtime-config 配置项中包含 settings.k8s.io/v1alpha1=true 来实现。在 minikube 部署的集群中,启动集群时添加此参数 –extra-config=apiserver.runtime-config=settings.k8s.io/v1alpha1=true。

  2. 已启用准入控制器 PodPreset。 启用的一种方式是在 API 服务器的 –enable-admission-plugins 配置项中包含 PodPreset 。在 minikube 部署的集群中,启动集群时添加以下参数:

1
--extra-config=apiserver.enable-admission-plugins=NamespaceLifecycle,Limi>tRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeR>estriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQu>ota,PodPreset
  1. 已经通过在相应的命名空间中创建 PodPreset 对象,定义了 Pod Preset。

编辑/etc/kubernetes/manifests/kube-apiserver.yaml,增加--runtime-config=settings.k8s.io/v1alpha1=true, 增加--enable-admission-plugins=PodPreset,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@node-1 manifests]# vim /etc/kubernetes/manifests/kube-apiserver.yaml 
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.235.21
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-admission-plugins=PodPreset # 需增加的配置
- --runtime-config=settings.k8s.io/v1alpha1=true # 需增加的配置
...

创建podpreset对应的yaml配置文件,这里需要注意的地方是,因为matchLabels为空,标示应用于所有容器,这个就是我们所期望的,即我们后续创建的所有pod的时区都会调整为上海时区:

1
2
3
4
5
6
7
8
9
10
11
[root@node-0 manifests]# vim preset.yaml
apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
name: allow-tz-env
spec:
selector:
matchLabels:
env:
- name: TZ
value: Asia/Shanghai

基于刚刚编写的配置文件创建podpreset:

1
2
[root@node-0 manifests]# kubectl apply -f preset.yaml 
podpreset.settings.k8s.io/allow-tz-env created

查看创建成功的Pod Preset列表:

1
2
3
[root@node-0 manifests]# kubectl get podpresets
NAME CREATED AT
allow-tz-env 2020-07-08T08:35:14Z

此时,创建其他pod,即可发现时区已经自动调整为上海时区了。通过查看pod的基本信息可以发现,在annotation中,podpreset的注解已经在新创建的pod信息里面了,这也就是开头所说的:

为改动的 Pod spec 添加注解,来表明它被 PodPreset 所修改。 注解形如: podpreset.admission.kubernetes.io/podpreset-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@node-0 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
tomcat-deploy-756cbb8484-qk7qr 1/1 Running 0 93s
[root@node-0 yaml]# kubectl describe pod tomcat-deploy-756cbb8484-qk7qr
Name: tomcat-deploy-756cbb8484-qk7qr
Namespace: default
Priority: 0
Node: node-1/192.168.235.21
Start Time: Wed, 08 Jul 2020 16:43:18 +0800
Labels: app=kom
pod-template-hash=756cbb8484
release=stabel
Annotations: cni.projectcalico.org/podIP: 172.51.84.146/32
podpreset.admission.kubernetes.io/podpreset-allow-tz-env: 9176367 # podpreset给pod的注解,表明该pod被podpreset所修改
Status: Running
IP: 172.51.84.146
...

进入容器内部查看环境变量,时区也已经调整为了上海:

1
2
3
4
5
6
7
8
[root@node-0 yaml]# kubectl exec -it tomcat-deploy-756cbb8484-qk7qr bash 
root@tomcat-deploy-756cbb8484-qk7qr:/# env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=tomcat-deploy-756cbb8484-qk7qr
PWD=/
TZ=Asia/Shanghai
...

小结


至此,我们就完成了容器的时区的”自动”配置了。Pod Preset的预设功能还是非常便利的,目前这块还在演进中,但是已经能大大简化了相关的管理工作,将这些配置从开发者手中解脱出来,变成系统管理配置。更多PodPreset实践可参考官方PodPreset示例