Goのタイムゾーンの変更をalpineのDockerコンテナ内で行なう

はじめに

Goのtimeパッケージにはいくつかタイムゾーンを指定するための関数が生えていますが、それらはすべて、 the IANA Time Zone databaseと呼ばれる世界各地の標準時間を集めたDatabaseを利用してタイムゾーンの情報を取得します。これはubuntuの環境などで動かす場合は特に問題ないのですが、alpine Linuxを用いたコンテナ内では少し注意必要で、先日少し戸惑ったのでメモとして残しておきます。

Goのタイムゾーン操作について

Goのtimeは例えば、以下のようにタイムゾーンを指定することができます。

   const location = "Asia/Tokyo"
    loc, err := time.LoadLocation(location)
    if err != nil{
        panic(err)
    }
    nowWithLocation := time.Now().In(loc)
    log.Printf("time = %s", nowWithLocation.String())
    log.Printf("location = %s", location)

これをubuntuなどの環境で動かすと普通に動きます。

# 動作環境はこんな感じ
$ uname -srvmpio
Linux 5.3.0-46-generic #38~18.04.1-Ubuntu SMP Tue Mar 31 04:17:56 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

$ go build -o ./go-location-sample
$ ./go-location-sample
2020/04/12 19:32:40 time = 2020-04-12 19:32:40.986375152 +0900 JST
2020/04/12 19:32:40 location = Asia/Tokyo

alpineやscrach Linuxでイメージを作成した際の問題点

先程のコードを以下のようにDockerイメージを作成し動かそうとするとエラーになります。

FROM golang:1.10.1-alpine3.7 as builder
COPY ./main.go ./
RUN go build -o /go-location-sample ./main.go

FROM alpine:3.7
COPY --from=builder /go-location-sample .
ENTRYPOINT ["./go-location-sample"]

ビルドして実行します。

$ docker -v
Docker version 19.03.8, build afacb8b7f0

$ docker build -t go-location-sample:1.0 .
$ docker images -a | grep go-location-sample
go-location-sample                                          1.0                 b762fd786613        About a minute ago   6.32MB
$ docker run b762fd786613
panic: open /usr/local/go/lib/time/zoneinfo.zip: no such file or directory

goroutine 1 [running]:
main.main()
    /go/main.go:12 +0x182

ログにエラーの内容が出ていますが、これはTime Zone Databaseの実態であるzoneinfo.zipがalpineなどに用意されていないことが問題で起こります。
(ちなみに、同様のことがscratchやbusyboxなどでも起こるみたいです。)

なので、実行イメージの方にzoneinfo.zip追加してやるようにすれば動くようになります。

FROM golang:1.10.1-alpine3.7 as builder
COPY ./main.go ./
RUN go build -o /go-location-sample ./main.go

FROM alpine:3.7
COPY --from=builder /go-location-sample .
# time zone databaseを取ってくる
ADD https://github.com/golang/go/raw/master/lib/time/zoneinfo.zip /usr/local/go/lib/time/zoneinfo.zip
ENTRYPOINT ["./go-location-sample"]
$ sudo docker build -t go-location-sample:1.0 .
$ sudo docker images -a | grep go-location-sample
go-location-sample                                          1.0                 9fb7055e3f0b        About a minute ago   7.1MB
$ docker run 9fb7055e3f0b
2020/04/12 11:41:43 time = 2020-04-12 20:41:43.000606042 +0900 JST
2020/04/12 11:41:43 location = Asia/Tokyo

これで問題なく動くようになりました。

感想

仕事で若干ハマったので、メモとして残しておこうと思って書きました。
なんとなくもう少しいいやり方もあるように感じたので、もしご存知の方がいらっしゃったらコメント等で教えてほしいです。