Help us understand the problem. What is going on with this article?

Docker で /etc/localtime をホストに volume マウントしてハマった話

More than 1 year has passed since last update.

/etc/localtime は迂闊に volume マウントしてはいけない。

「タイムゾーンをホストと合わせるために /etc/localtime をホストに volume マウントしましょう (-v /etc/localtime:/etc/localtime:ro)」 という記事があちこちで見られます。
私もそれに従って volume マウントしていたのですが、そのためにハマった話です。

under the hood で何が起きていたのか

Linux の特定のディストリビューションの特定のバージョンでは、/etc/localtime/usr/share/zoneinfo/Etc/UTC (UTC の zoneinfo の実体) に symlink (シンボリックリンク) されています。そんな /etc/localtime をホストに volume マウントするとどうなるか? symlink である /etc/localtime がホストの /etc/localtime に置き換わると思いきや、実はリンク先のファイルが置き換わる、つまり、UTC の zoneinfo の中身が JST のそれに置き換わってしまうのです。
少しだけ詳しいことをこっちに書きました。
「Docker で symlink をホストに volume マウントしたら...」

# cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# docker run --rm -it -v /etc/localtime:/etc/localtime:ro ubuntu:xenial-20190610 bash
root@ec52ace0eced:/# ls -l /etc/localtime
lrwxrwxrwx 1 root root 27 Jun 11 05:40 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
root@ec52ace0eced:/# cat /etc/localtime
TZiォ?ン
         シ
          ~~JDTJSTTZif2
                                e?p・ロォ??シ
                                                                              LMTJDTJST
JST-9
root@ec52ace0eced:/# cat /usr/share/zoneinfo/Etc/UTC
TZiォ?ン
         シ
          ~~JDTJSTTZif2
                                e?p・ロォ??シ
                                                                              LMTJDTJST
JST-9

そしてどうなったか

使っていた PostgreSQL のコンテナイメージ(非オフィシャル) は、9.6 のときのベースイメージが Ubuntu 14.04 (Trusty) でした。Trusty の /etc/localtime は UTC の zoneinfo の実体のコピーだったので、中身が JST である ホストの /etc/localtime を volume マウントしても問題ありませんでした。
その状態のまま PostgreSQL のイメージを 10 にバージョンアップしたら問題が起きました。ベースイメージが Ubuntu Xenial に上がっていたのです。
(後で調べてわかったわけですが) その結果上述のように UTC の zoneinfo の中身が JST のそれに置き換わってしまい、セッションの timezone が UTC なのに now()timestamp with timezone なフィールドの値が JST で返ってくるようになりました。
PostgreSQL を呼んでいたアプリ(某OSS) では、表示のタイムスタンプが9時間前になる、認可トークンのタイムスタンプが9時間前になって発行時点で既に期限が切れている、といった現象が発生しました。1

ディストリビューションによる相違

いろいろなディストリビューションの /etc/localtime がどうなっているか、ざっと調べてみました。
下記で 判定 に × を付けたディストリビューション/バージョンは上記の問題が発生します。

distribution version /etc/localtime /usr/share/zoneinfo/Etc/UTC 判定
ubuntu cosmic なし なし
ubuntu bionic なし なし
ubuntu xenial /usr/share/zoneinfo/Etc/UTCへのsymlink なし ×
ubuntu trusty UTCの実体 あり
debian stretch /usr/share/zoneinfo/Etc/UTCへのsymlink あり ×
debian jessie UTCの実体 あり
debian wheezy UTCの実体 あり
alpine 3.1 - 3.5 UTCの実体 なし
alpine 3.6 - 3.9 なし なし
centos 7.4.1708 ../usr/share/zoneinfo/UTCへのsymlink あり ×
centos 7.2.1511 ../usr/share/zoneinfo/UTCへのsymlink あり ×

詳しく調べてはいないのですが、ディストリビューションにバンドルされている tzdata パッケージの版数によるようです。

どうするのがよいのか

結論を先に言うと、いろいろググってみても諸説あって決定的な正解がみつかっていません。ディストリビューション毎に推奨の方法が異なっているようにも見えます。
上で問題になった ubuntu:xenial で -e TZ=Asia/Tokyo を付けて docker run してみましたが効果がありませんでした。というわけで、どのような方法にせよ、Dockerfile に細工して build する必要だけはありそうです。
究極の正解は UTC のまま使うことなんですが、ログのタイムスタンプを読み替えるのがめんどい....


  1. PostgreSQL 側の現象とアプリ側の現象が矛盾しているというか、時差のプラスマイナスが逆な気がします。そこの辻褄はアプリ(OSS) 側のロジックをもう少し分析しないとわかりませんが、現時点ではそこまでやれていません。 

jeffi7
fujitsu
富士通グループのソフトウェア技術者有志により運営しているコミュニティです。
http://www.fujitsu.com/jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away