k8s容器部署时区问题处理
一、问题描述
在 K8s 环境下部署应用后,发现数据库中记录的时间比北京时间晚了 8 小时,导致按时间查询数据时无法查到正确结果。这是典型的时区不一致问题。
涩及的时区配置点:
- MySQL 数据库服务器的时区设置
- MySQL 数据库时区配置
- JDBC 数据库连接的时区配置
- 应用服务器时区配置
- 应用容器的时区配置
二、问题排查
2.1 服务器时区检查
首先确认各个服务器的时区,使用命令 date 或 date -R。
[root@host-172 ~]$ date
2023年 11月 15日 星期三 21:19:02 CST
[root@host-172 ~]$ date -R
Wed, 15 Nov 2023 21:19:06 +0800
结果显示服务器时区为 CST(东八区)。
2.2 数据库时区检查
在确认服务器时区后,进一步确认数据库的时区,在数据库执行下面命令:
show variables like '%time_zone%'
查询结果如下:
| variable_name | value |
|---|---|
| system_time_zone | CST |
| time_zone | SYSTEM |
上述查询结果表明,数据库服务器的时区为CST,数据默认使用服务器的时区则也是CST。
2.3 Java 获取时区机制
在Java代码中我们可以通过一下方式获取系统时区:
// 获取默认时区
TimeZone timeZone = TimeZone.getDefault();
运行结果如下:
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]
2.4 Java 默认时区获取逻辑
Java 获取默认时区的步骤:
- 查找
TZ环境变量 - 若未设置,读取
/etc/timezone文件 - 若文件不存在,比较
/etc/localtime与/usr/share/zoneinfo目录下的时区文件 - 都未找到,默认使用 GMT 时区
参考:Java读取系统默认时区
三、解决方案
3.1 挂载时区文件
将宿主机的/etc/localtime路径挂载到容器,可以保持容器与宿主机时间同步,避免由于时间同步引起的应用层的问题。
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
labels:
app: my-pod
spec:
containers:
- name: my-pod
image: nginx
volumeMounts:
- name: host-time
mountPath: /etc/localtime
readOnly: true
volumes:
- name: host-time
hostPath:
path: /etc/localtime
**作用:**将宿主机的 /etc/localtime 路径挂载到容器,保持容器与宿主机时间同步。
3.2 设置环境变量 TZ
即使挂载了时区文件,如果没有设置 TZ 环境变量,Java 应用可能仍然使用容器的默认时区。
apiVersion: v1
kind: Pod
metadata:
name: pod-env-tz
spec:
containers:
- name: ngx-time
image: nginx:latest
env:
- name: TZ
value: Asia/Shanghai
**作用:**设置 TZ 环境变量,确保 Java 应用能获取正确的时区。
3.3 完整配置示例
推荐的容器时区配置方案(同时配置环境变量和挂载时区文件):
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: my-app:latest
env:
- name: TZ
value: Asia/Shanghai
volumeMounts:
- name: host-time
mountPath: /etc/localtime
readOnly: true
volumes:
- name: host-time
hostPath:
path: /etc/localtime
四、验证方法
# 进入容器
kubectl exec -it <pod-name> -- /bin/bash
# 检查容器时区
date
date -R
# 检查 TZ 环境变量
echo $TZ
# 检查 Java 应用获取的时区(在应用代码中)
TimeZone.getDefault()
五、注意事项
- 双重配置:建议同时配置
TZ环境变量和挂载/etc/localtime,确保时区一致 - 数据库连接:JDBC 连接串也可以配置时区,如
serverTimezone=Asia/Shanghai - 镜像构建:如果在 Dockerfile 中设置时区,可以避免部署时配置
- 时区文件路径:不同的 Linux 发行版时区文件路径可能不同,注意适配
六、参考文章
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 逐光の博客!
评论




