概要
以前以下の記事でscratch imageの作成方法を紹介しました。
しかしGoのコードによっては以下のpanicが起きることがあります。
panic: time: missing Location in call to Time.In
今回はその対応方法です。
環境
- golang 1.8.3
- docker 17.06.0-ce
原因
scratch imageにはzoneinfo
が無いためです。
通常は/usr/share/zoneinfo
にあり、golangのプログラムもそこを参照しようとしますが存在しない場合は
tz, err := time.LoadLocation("Asia/Tokyo")
といったコードのときにエラーが発生します。もしここでエラーハンドルしない場合はpanicになります。
対処方法
サンプルコード
今回以下のようなコードを用意しました。time.LoadLocation("Asia/Tokyo")
でエラーハンドルしていないコードです。
package main import ( "fmt" "net/http" "time" ) func main() { now := time.Now() tz, _ := time.LoadLocation("Asia/Tokyo") fmt.Println("Local time: ", now) fmt.Println("Tokyo time: ", now.In(tz)) _, err := http.Get("https://golang.org/") if err == nil { fmt.Println("GoLang website is UP") } else { fmt.Printf("GoLang website is DOWN\nErr: %s\n", err.Error()) } }
ローカルのMacで実行すると以下のようになります。
$ go run main.go Local time: 2017-08-13 19:57:21.032806177 +0900 JST Tokyo time: 2017-08-13 19:57:21.032806177 +0900 JST GoLang website is UP
golangのビルド
以前と同様にビルドしておきます。
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o main main.go
バイナリ情報は以下です。scratch imageで実行できるバイナリですね。
$ file main main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
zoneinfoの用意
Macや一般的なLinuxディストリビューションには/usr/share/zoneinfo
にあるので、そちらを利用します。tar.gz
で保持しておきます。tar.gz
にする理由はDockerfileのADD
で自動で展開してくれるからです。
$ tar -cvzf zoneinfo.tar.gz -C / usr/share/zoneinfo
フォルダ構造
以下のようなファイル配置になります。
ca-certificates.crt
は以前と同じように用意しておきます。
. ├── Dockerfile ├── ca-certificates.crt ├── main ├── main.go └── zoneinfo.tar.gz
Dockerfileの用意
FROM scratch ADD ca-certificates.crt /etc/ssl/certs/ ADD zoneinfo.tar.gz / ADD main / CMD ["/main"]
ポイントはADD zoneinfo.tar.gz /
です。先に述べたようにADD
はtar.gz
を展開してくれるので、これによって/usr/share/zoneinfo
にzoneinfoが展開されます。
動作検証
dockerをビルドします。
$ docker build -t example-scratch .
実行します。
$ docker run -it example-scratch Local time: 2017-08-13 10:58:20.286529522 +0000 UTC Tokyo time: 2017-08-13 19:58:20.286529522 +0900 JST GoLang website is UP
エラーハンドルしていないですが、panicにならずちゃんとJST
の時間が出力されました。
ローカルのMac上で実行したのと違ってLocal timeはUTCですね。
ファイルサイズはどれくらい増えるのか?
goのバイナリ入れず、ca-certificates.crt
とzoneinfo
だけの場合でどれくらいのimageサイズなるか測ってみました。
zoneinfoなし
$ docker images example-scratch
REPOSITORY TAG IMAGE ID CREATED SIZE
example-scratch latest 695004c086e6 3 weeks ago 274kB
zoneinfoあり
$ docker images example-scratch REPOSITORY TAG IMAGE ID CREATED SIZE example-scratch latest 1adbb2b490f9 About an hour ago 466kB
200kB
弱ほど増えました。goバイナリを考えると誤差レベルなので、zoneinfo
が有ったほうが扱いやすいimageになりそうです。