こんばんは、ねじねじおです。
Go言語アプリの Docker イメージを scratch からつくるとき、builder ステージから /usr/share/zoneinfo
ディレクトリをコピーしていますか?
それとも、 /usr/local/go/lib/time/zoneinfo.zip
ファイルをコピーしていますか?
あなたはどちら派ですか?
もう、そんなことで争う必要はないのです。Go 1.15 がリリースされたから。
Go 1.14 まで
Go 1.14 までは、タイムゾーンを解決するためにbuilderステージからタイムゾーンデータベースをコピーする必要がありました。
下記の最後の行です。
FROM golang:1.14.7 AS builder
WORKDIR /go/src/app
COPY ./ ./
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./server ./server.go
FROM scratch AS production
WORKDIR /go/bin
COPY --from=builder /go/src/app/server ./
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
環境依存でなんだか無粋ですね。
Go 1.15 では
Go 1.15 では、タイムゾーンデータベースをコンパイル後のバイナリの中に組み込むことができるようになりました。
Go 1.15 Release Notes / New embedded tzdata package
方法は2つあります。検証してみましょう。
準備
以前の記事で使った echo の小さな WebAPI を使います。
Go言語アプリのDockerイメージをscratchで軽量化してみた
結果がわかりやすいように、プログラムを変更して Go のバージョンも出力するようにしました。
e.GET("/", func(c echo.Context) error {
return c.JSON(http.StatusOK, []string{
"Hello, World!",
time.Now().Format(time.RFC3339),
runtime.Version(),
})
})
では、Dockerfileから
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
を削除して、ビルドして実行してみます。
$ docker build ./ -t example
$ docker run -e TZ=Asia/Tokyo -p 1323:1323 example ./server
$ curl http://localhost:1323/
["Hello, World!","2020-08-14T15:28:16Z","go1.15"]
予想どおり、タイムゾーンが効いていないです。
方法① ビルド時に -tags timetzdata オプションを付ける
FROM golang:1.15.0 AS builder
WORKDIR /go/src/app
COPY ./ ./
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -tags timetzdata -o ./server ./server.go
FROM scratch AS production
WORKDIR /go/bin
COPY --from=builder /go/src/app/server ./
ビルドして実行してみます。
$ docker build ./ -t example
$ docker run -e TZ=Asia/Tokyo -p 1323:1323 example ./server
$ curl http://localhost:1323/
["Hello, World!","2020-08-15T00:37:14+09:00","go1.15"]
タイムゾーンが反映されています!
方法② プログラム内で、time/tzdata パッケージをインポートする
先ほどのDockerfileの go build コマンドから -tags timetzdata
を削除します。
# RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
# go build -tags timetzdata -o ./server ./server.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -o ./server ./server.go
代わりに、プログラム内に import _ "time/tzdata"
を追加します。
ビルドして実行してみます。
$ docker build ./ -t example
$ docker run -e TZ=Asia/Tokyo -p 1323:1323 example ./server
$ curl http://localhost:1323/
["Hello, World!","2020-08-15T00:49:39+09:00","go1.15"]
OK !
タイムゾーンが反映されています。
そして、新たな火種が
OK。
と終わりたいところですが、 選択肢が2つ増えたことで論争の火種が増えてしまってますよね。
ねじおは、プログラム側は実行環境を知り得ないというスタンスで「ビルド時に -tags timetzdata
オプションを付ける」を選択します。
OK。
ねじねじおでした。