Ubuntu 16.04(xenial)のDockerコンテナのタイムゾーンを日本(JST)にする(Dockerfileで)

## Ubuntu の Docker コンテナでタイムゾーンを変更したい

Docker で Ubuntu を特に何もせず立てたときはタイムゾーンが UTC になりますが、日本に住んでいて日本時間で日常生活を送っている私にとっては、やはりコンテナ上のタイムゾーンも JST のほうがログとかの取り回しがしやすいので、 JST にする方法をいろいろ試していたのですが試行錯誤したログです。

ちなみに普通に立ち上げた時はやはり UTC でした。

```shell-session
% docker run --rm -i -t ubuntu:xenial
root@b4eb0482f2cb:/# date
Wed Jun  7 04:25:42 UTC 2017
```

著名な方法の1つとして、 [`/etc/localtime` をマウントするといった方法](http://qiita.com/HommaHomma/items/c6dbb554afb51f1b95d5) があり、この方法だと Docker Hub から落としてきたイメージをそのままつかうことができるので、ビルドの必要もありません。

しかしながら手元の環境[^1]だとなぜかマウントしても変わらなかったことと、タイムゾーンを変更したいコンテナがオリジナルのコンテナだったこともあり、 Dockerfile 内でコンテナビルド中に変更することにしました。

[^1]: OS X Yosemite && Docker 17.03.1-ce-mac12 (17661)

## Ubuntu 14.04 だとわりと簡単にできていた

コンテナで立ち上げる Ubuntu が 14.04(trusty) の場合だと以下の Dockerfile で変更できていました。

```docker:Dockerfile.ubuntu_trusty
FROM ubuntu:trusty

ENV TZ Asia/Tokyo
RUN echo "${TZ}" > /etc/timezone \
   && dpkg-reconfigure -f noninteractive tzdata
```

```shell-session
% docker build --tag ubuntu-jst:trusty -f Dockerfile.ubuntu_trusty .
  :
% docker run --rm -i -t ubuntu-jst:trusty
root@4fbcbb5f70c4:/# date
Wed Jun  7 21:10:54 JST 2017
```

しかしながら、同じ方法で ubuntu:xenial をベースにするとコケてしまいます。

```shell-session
% docker build --tag ubuntu-jst:xenial -f Dockerfile.ubuntu_xenial .
Sending build context to Docker daemon  5.12 kB
Step 1/3 : FROM ubuntu:xenial
 ---> 7b9b13f7b9c0
Step 2/3 : ENV TZ Asia/Tokyo
 ---> Running in 1d3359c286c7
 ---> cfb72b2e99e6
Removing intermediate container 1d3359c286c7
Step 3/3 : RUN echo "${TZ}" > /etc/timezone   && dpkg-reconfigure -f nonintractive tzdata
 ---> Running in 1d964b6a380c
debconf: unable to initialize frontend: Nonintractive
debconf: (Can't locate Debconf/FrontEnd/Nonintractive.pm in @INC (you may need to install the Debconf::FrontEnd::Nonintractive module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 /usr/local/share/perl/5.22.1 /usr/lib/x86_64-linux-gnu/perl5/5.22 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.22 /usr/share/perl/5.22 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base .) at (eval 19) line 2.)
debconf: falling back to frontend: Noninteractive
dpkg-query: package 'tzdata' is not installed and no information is available
Use dpkg --info (= dpkg-deb --info) to examine archive files,
and dpkg --contents (= dpkg-deb --contents) to list their contents.
/usr/sbin/dpkg-reconfigure: tzdata is not installed
```

## 何が原因なのか

エラーメッセージに書いてあるとおり、 Docker Hub 上にある Ubuntu のイメージに `tzdata` コマンド自体がそもそも入っていないことが原因です。そもそも Ubuntu は 16.04 から systemd になっている影響で、本来であれば `timedatectl` でタイムゾーンを設定するべきなので、そのせいもありデフォルトで入ってないのかもしれません[^2]。

がんばれば Docker で systemd を扱う方法もないことはないので、これによって `timezonectl` を使うことができるのかもしれませんが、タイムゾーンの変更のためだけに systemd を導入するのは、お菓子を袋をあけるために日本刀を用意するようなものです。

[^2]: 14.04 だと `locale-gen` をつかって言語も変えられていたのだがこれもできなくなっています。もしかしたらコンテナの容量を下げるための対策に巻き込まれたのかもしれません。

少々話がそれたましたが、一応 `tzdata` は、まだ `apt-get` で入れることができるようなのでありがたくパッケージ管理システムによって得た堕落を享受することにします。

```docker:Dockerfile
FROM ubuntu:xenial

# パッケージ取得先のミラーをjaistに変更する
RUN sed -i.bak -e "s%http://archive.ubuntu.com/ubuntu/%http://ftp.jaist.ac.jp/pub/Linux/ubuntu/%g" /etc/apt/sources.list

ENV TZ Asia/Tokyo
RUN apt-get update \
  && apt-get install -y tzdata \
  && rm -rf /var/lib/apt/lists/* \
  && echo "${TZ}" > /etc/timezone \
  && rm /etc/localtime \
  && ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && dpkg-reconfigure -f noninteractive tzdata
```

これで JST の Ubuntu コンテナを用意することができました。

```shell-session
% docker build --tag ubuntu-jst:xenial -f Dockerfile.ubuntu_xenial .
:
% docker run --rm -i -t ubuntu-jst:xenial
root@2646f266e8d1:/# date
Wed Jun  7 21:41:08 JST 2017
```

:v: