Docker 与 Windows 时间不同步的问题及解决办法

最近突然发现 Windows 上的 Docker Container 时间滞后于 Windows 系统时间,这有时候会对 Container 造成不可预测的影响。因此在做了一番调研,解决方法记录如下。

出现原因

目前我的 Docker 容器内的时间为 Sun Jun 6 21:54:29 UTC 2021,但是 Windows 系统时间为 2021年6月7日 15:05:10,Docker Container 滞后了大约 9 个小时。这个问题出现的原因,简而言之就是使用了 Windows 系统的睡眠功能。当 Windows 从睡眠中醒来时,时间没有得到同步,于是 Docker Container 就滞后了睡眠所消耗的时间。

因此,要解决这个问题,我们就要让两边的时间同步。

解决方案

以下假设你的 Windows 系统装载了 PowerShell。强烈建议直接装 Windows Terminal 一步到位,在官方应用商店可以下载到。如果需要查看你的 Docker 引擎,可以进入 Docker Desktop 的设置页,看一下 Use the WSL 2 based engine 是否被勾选。

运行在 WSL2 之上的 Docker[1]

运行 WSL2 上的 Docker 很容易可以解决这个问题。关于该 bug 的讨论可以参考 GitHub[2]。解决该问题的方法非常简单,只需在 PowerShell 里运行:

1
wsl --shutdown

此时 Docker Desktop 会提示你 WSL2 后端已经被关闭,并问你是否需要重启。点击 restart 并等待一段时间即可修复问题。

运行在 Hyper-V 之上的 Docker[3]

这个版本的解决方案没有经过我的亲自实验(因为我的 Docker 基于 WSL2),仅供参考。

首先我们准备如下的.ps1 脚本:

1
2
3
4
5
$vm = Get-VM -Name DockerDesktopVM
$feature = "Time Synchronization"

Disable-VMIntegrationService -vm $vm -Name $feature
Enable-VMIntegrationService -vm $vm -Name $feature

保存该文件为 docker-time-sync.ps1(或者你喜欢的其他名字)。通过管理员身份启动 PowerShell,定位到该文件的位置并运行它。

如果显示以下错误信息:

1
无法将“Get-VM”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。……

则需要你修改一下权限。首先运行 Get-ExecutionPolicy -List 查看一下当前的作用域,并通过 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 进行修改。修改完毕后再次尝试运行以上脚本。

根据 GitHub[4] 上的讨论,你也可以打开 Hyper-V 管理器程序,关闭并重新开启以下功能(未经翻译)即可解决:

1
MobyLinuxVM > Settings > Integration Services > Time synchronization

  1. https://www.thegrussalo.com/2021/01/docker-container-time-drift-using-wsl2.html ↩︎

  2. https://github.com/microsoft/WSL/issues/4149 ↩︎

  3. https://www.thorsten-hans.com/docker-on-windows-fix-time-synchronization-issue ↩︎

  4. https://hub.fastgit.org/docker/for-win/issues/72 ↩︎