Docker容器时间同步,宿主机时间同步chrony配置
Docker容器时间不同步是运维中很常见的问题。
容器默认继承宿主机的内核时间,但时区可能不一致,而宿主机自身时间如果漂移,容器也会跟着出错。
解决思路分两层:先让宿主机通过 chrony 与上游时间源保持同步,再让容器使用正确的时区和时间。
本文面向零基础读者,按命令直接复制执行即可,完成后可自行验证效果。
为什么要单独处理 Docker 容器的时间
Docker 容器不是一个完整的操作系统,它共享宿主机的 Linux 内核,所以 date 看到的时间其实是宿主机内核时间加容器内设置的时区偏移。
常见现象有:
- 容器日志时间比当前时间早 8 小时或晚 8 小时,多是时区未设置。
- 容器内执行的定时任务(如
cron)时间不准,影响业务调度。 - 宿主机时间漂移,所有容器时间整体偏移。
因此先确保宿主机时间准确,再统一容器时区,是解决 Docker 时间同步的正确顺序。
第一步:给宿主机安装并配置 chrony
chrony 是常用的时间同步服务,比 ntpdate 更适合现代服务器。
先检查是否已安装:
rpm -qa | grep chrony
dpkg -l | grep chrony
CentOS、Rocky、Alibaba Cloud Linux 可直接执行:
yum install -y chrony
Ubuntu、Debian 执行:
apt install -y chrony
安装后编辑主配置文件 /etc/chrony.conf,把默认的 NTP 服务器改成国内可达的上游源,例如:
server ntp.aliyun.com iburst
server ntp.tencent.com iburst
server cn.pool.ntp.org iburst
iburst 参数表示首次同步时快速发送多个请求,缩短校准时间。
修改后重启并设置开机自启:
systemctl restart chronyd
systemctl enable chronyd
部分 CentOS 7 版本服务名是 chronyd,Ubuntu 18.04 及以下可能是 chrony,使用 systemctl status chronyd 查看实际服务名。
第二步:验证宿主机时间同步状态
使用 chronyc 命令查看同步情况:
chronyc sources -v
输出中 ^* 表示当前已选中的时间源,^+ 表示可用的备用源。
再执行:
chronyc tracking
重点看 Leap status 是否为 Normal,Stratum 数值越小代表越接近权威时间源。
如果出现 System clock wrong by ... 属于正常校准提示,等待几分钟后再次检查。
宿主机时间确认无误后,执行 date 查看当前系统时间:
date
如果时区不对,先修正系统时区:
timedatectl set-timezone Asia/Shanghai
再执行 date 确认输出符合预期。
第三步:让 Docker 容器时间与宿主机保持一致
宿主机时间准确后,需要处理容器内部时区。
最推荐的方式是在启动容器时通过 -e TZ 环境变量指定时区:
docker run -d --name myapp -e TZ=Asia/Shanghai nginx:alpine
对于已经创建的容器,可以通过挂载宿主机时区文件的方式修正:
docker run -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro --name myapp2 nginx:alpine
/etc/localtime 是二进制时区数据,/etc/timezone 是文本时区标识,两者一起挂载可避免部分镜像内时区设置残留问题。
如果容器已经运行且不方便重建,可进入容器手动同步:
docker exec -it myapp cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
注意,这个命令只对容器内有时区数据文件的镜像有效,某些精简镜像可能缺少 /usr/share/zoneinfo。
此时建议直接重建容器,使用环境变量方式最省心。
对于 docker-compose 部署,可在服务定义中加入环境变量:
services:
app:
image: your-image
environment:
- TZ=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
第四步:检查容器时间是否真正一致
执行以下命令对比宿主机和容器时间:
date
docker exec myapp date
两个输出应在秒级保持一致。
再验证时区是否生效:
docker exec myapp cat /etc/timezone
如果输出 Asia/Shanghai,说明时区设置成功。
对于使用 TZ 环境变量的容器,可以查看进程环境变量:
docker exec myapp env | grep TZ
常见坑:镜像精简、时区文件缺失、容器内改时间无效
很多人进入容器执行 date -s 想直接改时间,发现权限不足或改完又变回去。
这是因为容器默认共享宿主机的时钟源,普通容器不具备修改系统时间的权限,即使加上 --privileged 也不推荐,这会带来安全风险。
正确做法永远是调整宿主机的 chrony 同步和容器的时区映射。
另一个容易踩的坑是安装完 chrony 后忘记放行 UDP 123 端口。
如果宿主机开启了 firewalld,需要执行:
firewall-cmd --permanent --add-service=ntp
firewall-cmd --reload
否则 chronyd 虽然启动,但无法正常与外网时间源通信,chronyc sources 会一直看到 ^? 状态。
还有一点,
部分云服务器默认带硬件时钟(RTC),
如果宿主机重启后时间回退,
需要检查是否开启了 NTP 服务并且 BIOS 时钟设置是否正确,
可使用 timedatectl 查看 RTC 时间:
timedatectl
建议将 RTC in local TZ 设置为 no,统一使用 UTC 标准,避免时区叠加错误。
最后的验证清单
完成以上配置后,按下面顺序做最终检查:
# 1. 宿主机时间源状态
chronyc sources -v
# 2. 宿主机当前时间
date
# 3. 容器内当前时间
docker exec myapp date
# 4. 容器时区
docker exec myapp cat /etc/timezone
如果时间同步还算稳定,但容器日志时间仍差 8 小时,多半是应用读取了 Java 或 Python 自己的默认时区,需要在应用配置里也指定 Asia/Shanghai。
这类问题不属于系统时间同步,可从应用运行时参数再排查。
如果你刚接触 Docker,建议先在测试容器上完整操作一遍,再推广到生产环境。
宿主机时间同步用 chrony,容器时区用 TZ 环境变量,这两步做好,绝大部分时间不一致问题都能解决。
遇到异常时优先回看第四步的检查项,确认是宿主机漂移还是容器时区映射失效。