はじめに
検証環境や閉環境などのインターネットもNTPもない環境で仮想マシンを作成すると、ゲストOS(Linux)の時刻が9時間進んた時刻になってしまいます。
dateコマンドを使って現実世界の時計を見ながら設定したり、スクリプトを使って-9時間した時刻を設定している方もいるのではないでしょうか。
しかし、ホストOSの時刻とゲストOSの時刻はなぜずれてしまうのでしょうか。
本記事では、時刻がずれてしまう原因の簡単な解説を行い、dateコマンドを使わず、現実世界の時計も見ず、
ホストOS(Windows)の時刻(JST)を基準として時刻合わせを行う方法を紹介します。
環境
- ホストOS: Windows10
- VMware Workstation 16
- ゲストOS:Ubuntu 20.04
状況と原因
VMware Workstation で仮想マシンを作成したとき、インターネット接続もなく、ntp環境もない場合はゲストOSの時刻はいつまでもおかしな時刻を指します。
「おかしな」というのは、ホストOSであるWindowsの時刻は現実世界に一致しているのに、ゲストOSであるLinuxは、ホストOSのローカルタイム(日本時刻JST)をUTCとして扱ってしまっていることです。
下記に示すように、現実世界とWindowsが11:00 JST のとき、ゲストOSの表示時刻(JST)は9時間進んだ時刻 20:00 JST を示してしまいます。
測定場所 | 時刻 |
---|---|
現実世界(日本時刻) | 11:00 JST |
ホストOS Windows表示時刻 | 11:00 JST |
ゲストOS Linux表示時刻(UTC) | 11:00 UTC (おかしい) |
ゲストOS Linux表示時刻(JST) | 20:00 JST |
原因の解説は 仮想化雑記帳: 仮想マシンとハードウェアクロック を読んでいただくとして、簡単に解説すると、
- 仮想マシンが初回に起動するときは、VMware WorkstationがホストOS(Windows)のローカルタイム(日本時刻)を仮想マシンのリアルタイムクロック(RTC)に書き込む
- RTCにタイムゾーンの概念はない
- 仮想マシン上のゲストOS(Linux)は、RTCの時刻をUTCとして扱う
- なので、Linuxが表示するローカルタイム(日本時刻)はUTCから9時間進んだ時刻になる
3コマンドで合わせる方法
結論
何も考えずに次の3コマンドを実行すればOKです。Linuxインストール時に設定したタイムゾーンには依存しません。
sudo timedatectl set-timezone Asia/Tokyo # ホストOSのタイムゾーンに合わせる
sudo hwclock --hctosys --localtime # ハードウェアクロック(hc)の時刻をローカルタイムとみなして、システムクロック(sys)に適用する
sudo hwclock --systohc --utc # システムクロック(sys)の時刻を、ハードウェアクロック(hc)に適用する。その際、hcはUTCを表示させるべきものとして扱います
解説
各コマンドの実行結果を、timedatectl の結果を確認しながら進めます。
なお、作業時点でのWindowsの表示時刻は 「10:00 JST」頃となっています。
まずは、timedatectl
コマンドで現在の状況を確認します。
RTC timeが10:00となってしまっています。
RTC timeはUTC時刻を表示していてほしいので、ここをなんとか01:00(日本時刻の9時間前)にするのが目標です。
$ timedatectl
Local time: Wed 2021-12-15 10:00:38 UTC
Universal time: Wed 2021-12-15 10:00:38 UTC
RTC time: Wed 2021-12-15 10:00:37 # ここを01:00:37と表示されるようにしたい
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
まずは、timedatectl set-timezone
コマンドで、LinuxのローカルタイムゾーンをJSTにします。
ここでJSTを選んだ理由は、ホストOSのタイムゾーンがJSTであることと、以降のコマンドで、RTC timeの時刻をJSTとして扱いためです。
ホストOSの時刻がESTの方は、LinuxのローカルタイムゾーンをESTにしてください。
(作業後は好きなタイムゾーンに変更できます)
$ sudo timedatectl set-timezone Asia/Tokyo
$ timedatectl
Local time: Wed 2021-12-15 19:04:08 JST # ローカルタイムゾーンがJSTになった
Universal time: Wed 2021-12-15 10:04:08 UTC
RTC time: Wed 2021-12-15 10:04:07
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
次に、hwclock --hctosys
コマンドで、hc(ハードウェアクロック、RTC)時刻をsys(システムクロック、Linuxの時計)に適用します。
この際、--localtime
オプションを付与することで、hcがローカルタイム(JST時刻)を表示しているものとして扱います。
$ sudo hwclock --hctosys --localtime
$ timedatectl
Local time: Wed 2021-12-15 10:04:34 JST # RTC time の時刻(JST扱い)がLocal timeに適用された
Universal time: Wed 2021-12-15 01:04:34 UTC
RTC time: Wed 2021-12-15 10:04:34
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
最後に、hwclock --systohc
コマンドで、sys(システムクロック、Linuxの時計)を、hc(ハードウェアクロック、RTC)に適用します。
この際、--utc
オプションを付与することで、hcはUTCを表示させるべきものとして扱います。
つまり、timedatectl
コマンドの「Universal time」がRTCに適用されます。
$ sudo hwclock --systohc --utc
$ timedatectl
Local time: Wed 2021-12-15 10:04:48 JST
Universal time: Wed 2021-12-15 01:04:48 UTC
RTC time: Wed 2021-12-15 01:04:48 # Universal time が Local timeに適用された
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
NTP service: active
RTC in local TZ: no
これで仮想マシンのRTCが、期待する状態になりました。
仮想マシンを再起動しても、電源OFF/ONしても、クローンしても時刻は期待する状態を維持します。
ただし、仮想マシンをエクスポートしてova,ovf形式にし、その後インポートした場合にはまた時刻がおかしくなります。
RTCの時刻はovaファイルに保存されないためです。
(この表現は正確ではないので、解説は仮想化雑記帳: 仮想マシンとハードウェアクロック を参照ください)
まとめ
- 仮想マシンの初回起動時はOSのローカルタイムをUTCとして扱ってしまう
- dateコマンドで時刻を修正することもできるが、RTCを正しい値に修正することで正しい状態にすることができる
- コマンドは、何も考えずに3行実行するだけでよい