![image](https://img2022.cnblogs.com/blog/2222036/202206/2222036-20220615234228500-2123434127.png)
1:问题简介
容器在主机的内核上运行,并获得时钟,但时区不是来自内核,而是来自用户空间。在大多数情况下,默认使用协调世界时 (UTC)。
时区的不一致,会带来很多困扰。即使代码与时区无关,但容器日志与系统日志时间相关联排查问题也会让人头疼。一些应用程序使用机器的时区作为默认时区,并希望用户设置时区。当集群中容器的时区不一致时,管理会很不容易。
2:什么是k8tz
k8tz是开源项目:github.com/k8tz/k8tz
k8tz是一个 Kubernetes 准入控制器和一个将时区注入 Pod 的 CLI 工具。可以用作手动工具来自动转换 Deployment 和 Pod 可以作为准入控制器安装并使用注释来完全自动化创建 Pod 的过程。
k8tz 可以使用 hostPath的方式,或者将 emptyDir 注入 initContainer并用 TZif(时区信息格式) 文件填充卷。然后将 emptyDir挂载到 Pod 每个容器的 /etc/localtime和 /usr/share/zoneinfo。为了确保所需的时区有效,它向所有容器添加了 TZ环境变量。
3:部署并使用k8tz
官方提供的是Helm部署:
helm repo add k8tz https://k8tz.github.io/k8tz/
helm install k8tz k8tz/k8tz --set timezone=Asia/Shanghai
# 这里 --set timezone=<自定义>
查看 Pod 状态、Mutatingwebhookconfigurations、Service 等资源是否正常:
[root@kubernetes-master-1 ~]# kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io k8tz
NAME WEBHOOKS AGE
k8tz 1 2m20s
[root@kubernetes-master-1 ~]# kubectl get pod -n k8tz
NAME READY STATUS RESTARTS AGE
k8tz-c766b769-2xr7w 1/1 Running 0 109s
[root@kubernetes-master-1 ~]# kubectl get svc -n k8tz
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8tz ClusterIP 100.1.124.219 <none> 443/TCP 2m46s
# 测试一个Pod
[root@kubernetes-master-1 ~]# date
Wed Jun 15 23:11:34 CST 2022
[root@kubernetes-master-1 ~]# kubectl exec -it nginx-6fb79bc456-rnsrs /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # date
Wed Jun 15 15:11:44 UTC 2022
# 这里发现 Pod和主机的时区是不同的
# 官方其实提供了三种方式去同步时间,第一种是:InitContainer 第二种就是注解(annotations),第三种就是hostpath,我这里用注解操作
删除原来的测试容器
[root@kubernetes-master-1 ~]# cat nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
annotations:
k8tz.io/timezone: Asia/Shanghai # 这里就是写如想要的时区即可
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
[root@kubernetes-master-1 ~]# kubectl apply -f nginx.yaml
deployment.apps/nginx created
# 我们可以看一下真个过程
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 13s default-scheduler Successfully assigned default/nginx-6fb79bc456-hlnz6 to kubernetes-worker-2
Normal Pulling 13s kubelet Pulling image "quay.io/k8tz/k8tz:0.5.0"
Normal Pulled 2s kubelet Successfully pulled image "quay.io/k8tz/k8tz:0.5.0" in 10.57934198s
Normal Created 2s kubelet Created container k8tz
Normal Started 2s kubelet Started container k8tz
Normal Pulled 1s kubelet Container image "nginx:alpine" already present on machine
Normal Created 1s kubelet Created container nginx
Normal Started 1s kubelet Started container nginx
# 这里其实也是类似于走了一个 initcontainer的过程
# 查看Pod时区
[root@kubernetes-master-1 ~]# kubectl exec -it nginx-6fb79bc456-hlnz6 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
Defaulted container "nginx" out of: nginx, k8tz (init)
/ # date
Wed Jun 15 23:16:42 CST 2022 # 发现Pod时区已经是在上海了
# 当然了,我们既然能注入时区,当然也可以禁止注入时区,这里可以选择使用注解 k8tz.io/inject: false,但是如果禁止注入时区和注入时区同时出现了,那么注入时区的优先级会比禁止注入时区优先级高
# 下面我们可以使用注解hostpath挂载本地的时区进去 k8tz.io/strategy: hostPath
# 这个其实暂时还不能看出来,因为我主机也是上海
[root@kubernetes-master-1 ~]# kubectl exec -it nginx-6fb79bc456-v75mz /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
Defaulted container "nginx" out of: nginx, k8tz (init)
/ # date
Wed Jun 15 23:23:48 CST 2022
# annotations 也可以在命名空间中指定,并影响在命名空间中创建的所有 pod。下面创建一个 demo namespace 用于测试:
[root@kubernetes-master-1 ~]# ls | grep nginx
nginx1.yaml
nginx2.yaml
nginx3.yaml
nginx4.yaml
nginx5.yaml
# 这里是5个Pod的yaml
# 创建 ns
[root@kubernetes-master-1 ~]# kubectl create ns demo
namespace/demo created
[root@kubernetes-master-1 ~]# kubectl get ns
NAME STATUS AGE
default Active 41m
demo Active 5s
---
# 将注解写入ns
k8tz.io/strategy=hostPath
k8tz.io/timezone=Asia/Shanghai
[root@kubernetes-master-1 ~]# kubectl annotate ns demo k8tz.io/strategy=hostPath
namespace/demo annotated
[root@kubernetes-master-1 ~]# kubectl annotate ns demo k8tz.io/timezone=Asia/Shanghai
namespace/demo annotated
# 上面将策略设置为 hostPath 注入方式。因为安装 k8tz 时默认时区已经设置为 Asia/Shanghai,但是Nginx的时区并不是上海,所以这里将 demo namespace 时区设置为 Asia/Shanghai,方便区分。
# 此时创建的 Pod 不需要加任何注解,只要是在这个demo的命名空间下的pod时区都是Asia/Shanghai,接下来测试一下
[root@kubernetes-master-1 ~]# mv *.yaml nginx/
[root@kubernetes-master-1 ~]# ls
anaconda-ks.cfg nginx
[root@kubernetes-master-1 ~]# ls nginx/
nginx1.yaml nginx2.yaml nginx3.yaml nginx4.yaml nginx5.yaml
# 创建Pod
[root@kubernetes-master-1 ~]# kubectl apply -f nginx
deployment.apps/nginx1 created
deployment.apps/nginx2 created
deployment.apps/nginx3 created
deployment.apps/nginx4 created
deployment.apps/nginx5 created
[root@kubernetes-master-1 ~]# kubectl get pod -n demo
NAME READY STATUS RESTARTS AGE
nginx1-58fd7d585c-4gt9s 1/1 Running 0 104s
nginx2-6f66b664b6-ngj5h 1/1 Running 0 104s
nginx3-6d8b8c6c-kdd6c 1/1 Running 0 104s
nginx4-7946dfbc9b-57pf6 1/1 Running 0 104s
nginx5-ccc464b49-t6v6z 1/1 Running 0 20s
# 查看时区
[root@kubernetes-master-1 ~]# for i in $(kubectl get pod -n demo | grep -v "NAME" | awk '{print $1}');do kubectl exec -it -n demo $i -- date;done
Wed Jun 15 23:37:23 CST 2022
Wed Jun 15 23:37:23 CST 2022
Wed Jun 15 23:37:23 CST 2022
Wed Jun 15 23:37:23 CST 2022
Wed Jun 15 23:37:24 CST 2022
# 发现时区全部统一了
4:总结
Kubernetes 中的时区问题有多种解决方案,这些解决方案可以手动实现,但在此过程中存在一些挑战和限制。
使用 k8tz可以自动执行该过程,确保系统中所有组件的时区一致,并且所有组件都可以访问有关不同时区的信息。并且无需额外设置或更改现有资源即可工作,即使在节点上没有所需文件时也是如此。