5
3

More than 3 years have passed since last update.

Go1.15改訂版、Go言語アプリのDockerイメージをscratchから作る

Posted at

こんばんは、ねじねじおです。

Go言語アプリの Docker イメージを scratch からつくるとき、builder ステージから /usr/share/zoneinfo ディレクトリをコピーしていますか?
それとも、 /usr/local/go/lib/time/zoneinfo.zip ファイルをコピーしていますか?
あなたはどちら派ですか?

もう、そんなことで争う必要はないのです。Go 1.15 がリリースされたから。

Go 1.14 まで

Go 1.14 までは、タイムゾーンを解決するためにbuilderステージからタイムゾーンデータベースをコピーする必要がありました。
下記の最後の行です。

Dockerfile
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 のバージョンも出力するようにしました。

server.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 オプションを付ける

Dockerfile
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。
ねじねじおでした。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3