在生产环境业务pod中误用UTC时间其实比较普遍,使用kubernetes的朋友会经常观察到pod的工作负载容器的时间(以下简称pod时间)比所在节点的系统时间晚了8小时,并且可能只有一部分pod存在时间戳落后8小时的情况。在大部分在线业务系统对时间都非常敏感,时间不同步可能会引发严重的业务故障。以下典型应用场景对时钟同步有强要求:
1、https通讯
2、调用采用签名算法保护的接口,签名生成算法包含时间戳
3、时间戳会被持久化存储
4、有基于时序的业务处理逻辑
部分使用kubernetes产品的用户会把pod时间延迟8小时的现象归咎给kubrnetes,但该问题本周上是容器镜像的时区配置不当所致。绝大多数开源的os基础镜像默认都是UTC时间,用户在构建业务系统镜像时,应该在Dockerfile中定制自己的时区,一旦遗漏这一关键步骤将导致基于该镜像启动的容器与主机本地不同步,放在kubernetes应用场景,就会出现pod内部时间落后节点8小时。
按kubernetes的官方部署要求,在国内使用kubernetes, 集群节点一般统一使用中国CST时间(UTC+8),通过ntp或chrony与权威时钟源保持时钟同步。登录节点执行date -R
指令进行查看节点时间:
[root@0000000g-wcgp0q8ads ~]# date -R
Sat, 06 Apr 2024 18:37:16 +0800
验证pod实例的工作容器当前时间可以使用kubectl指令,例如查看default命名空间下,名为kubia-mannual
的pod工作容器时间:
使用kubectl exec
指令可查看pod的工作负载容器当前的时间:
[root@0000000g-wcgp0q8ads ~]# kubectl exec kubia-manual -n default -- date -R
Sat, 06 Apr 2024 10:37:18 +0000
若发现工作容器的时间戳时区为+0000
,代表使用的该pod内部用了UTC时间, 中国CST时间比标准UTC时间快8小时
在解释了时间不同步的原因后,接下来聊聊在生产环境中遇到该问题时该如何处理
重新构建容器镜像
重新构建镜像是最彻底的解决方案,所有出现时钟同步的容器镜像都需要重新构建镜像
以Dockerfile方式构建镜像为例,在镜像的Dockerfile中增加以下语句:
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
构建镜像后,需基于新镜像重新发布应用方可生效。若镜像数量较多,重构和发布新镜像任务量会比较大,时间也比较久。如果需要临时应急修复,则可以可以参考下文挂载主机时区配置到pod容器的方案。
挂载主机的时区配置到pod容器
该方案是将主机的/etc/localtime
文件以hostPath类型数据卷的方式挂载到pod的/etc/localtime
,使得pod时区信息与主机节点保持同步。该方法需要修改启动pod的deployment或deamonset, 以下以Deployment资源类型修改为例,假定原始定义如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
command: ["nginx", "-c", "/etc/nginx/nginx.conf" ]
增加hostPath类型数据卷,并挂载到容器/etc/localtime
路径下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nginx
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:a
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
command: ["nginx", "-c", "/etc/nginx/nginx.conf" ]
volumeMounts:
- name: timezone
mountPath: "/etc/localtime"
volumes:
- name: timezone
hostPath:
path: /etc/localtime
type: File