LoginSignup
2
0

More than 3 years have passed since last update.

何もしてないのにtimezoneが壊れまして候

Posted at

久しぶりにdocker buildした

FROM golang:1.11.9-alpine as build

WORKDIR /go/app

RUN apk add --no-cache musl-dev git gcc

COPY . .

RUN go build -o app

FROM alpine:latest

RUN apk add --no-cache musl-dev git gcc tzdata curl

WORKDIR /app

COPY --from=build /go/app/app .

RUN apk --no-cache add tzdata ca-certificates \
  && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && addgroup go \
  && adduser -D -G go go \
  && chown -R go:go /app/app

EXPOSE 8080

CMD ["./app"]

goでmysqlに接続するアプリをdockerで動作させていました。以下のようなデータが混ざったJSONを返すAPI Serverだと思ってください

image.png

特に問題も無くコードの変更もしてないのですが、ちょっとした変更がしたくて久しぶりにdocker buildを走らせた結果いきなりUTCに変わりました。

image.png

接続情報等の確認

  • mysqlへ接続していたので
  • https://github.com/go-sql-driver/mysql
  • 接続情報になにか変更が入ってしまったのかと思い確認にいきましたが
  • ちゃんとAsia/Tokyoになっています
parseTime=True&loc=Asia%2FTokyo
  • 段々意味が分からなくなってきたので
  • いったんtimezone周りの状況を整理しました

goのlocalどんな感じに決まってるのか

  • 文字列が出力されるときに呼び出される
  • initLocalという関数の中で決まる
  • TZ環境変数
    • 無い場合
      • /etc/localtimeを参照してこちらの情報を元にtimezoneを決定する
    • 有る場合
      • TZ環境変数の中身とtime.zoneSourcesにあるディレクトリのリストを順に調査
      • 該当した場合はその情報を元にtimezoneを決める
 21 var zoneSources = []string{
 22     "/usr/share/zoneinfo/",
 23     "/usr/share/lib/zoneinfo/",
 24     "/usr/lib/locale/TZ/",
 25     runtime.GOROOT() + "/lib/time/zoneinfo.zip",
 26 }
  • なのでTZ環境変数をしていなくても
  • tzdataをinstallさえして
  • /etc/localtimeへリンクをはるなりしておけば期待するtimezoneになります

mysql driverの場合

  • mysql driverでlocを設定した場合
  • どうなるのか。
  • dsn.goで
  • time.LoadLocationへlocに設定した値が渡されて
  • configに設定されます
450         // Time Location
451         case "loc":
452             if value, err = url.QueryUnescape(value); err != nil {
453                 return
454             }
455             cfg.Loc, err = time.LoadLocation(value)
456             if err != nil {
457                 return
458             }
  • ZONEINFO環境変数などが設定されていない場合に関しては
  • locに設定した値を元に
  • loadLocationが呼び出される
656     if z, err := loadLocation(name, zoneSources); err == nil {
657         return z, nil
658     } else if firstErr == nil {
659         firstErr = err
660     }
661     return nil, firstErr
  • この場合もzoneSourcesのどこかに期待するtimezoneの情報があれば
  • 正常に動作します

この時点で分かっていること

  • mysqlの取得する部分でtimezoneがおかしい問題がおきている
  • alpineでtzdataをinstallしていること
  • tzdata以外に参照するデータは無いこと

とても怪しいところ

image.png

  • 勘の良い方なら早々に気づいていたかと思いますが
  • 気づかないうちにalpineのバージョンが上がっていたようです
  • alpine:3.12.1にその時点で上がっていました

alpine3.12.1でtzdataに何が起きたのか

diff --git a/main/tzdata/APKBUILD b/main/tzdata/APKBUILD
index 9725639106..f70b03cab1 100644
--- a/main/tzdata/APKBUILD
 b/main/tzdata/APKBUILD
@@ -2,8 ,8 @@
 # Contributor: Natanael Copa <ncopa@alpinelinux.org>
 # Maintainer: Natanael Copa <ncopa@alpinelinux.org>
 pkgname=tzdata
-pkgver=2020a
-_tzcodever=2020a
pkgver=2020c
_tzcodever=2020c

tzdata2020a-2020cでは何が起きたのか

どう解決したのか

  • その時点でalpineのバージョンを有るところまで戻して固定する
  • もしくはTZを指定してtzdataを入れず zoneinfoを自前で入れた場合以下を見ます
  • runtime.GOROOT() + "/lib/time/zoneinfo.zip",
  • こちらへfat版を貰ってきます
  • 後者の方法をとることにしました

goの lib/time/zoneinfo.zipを確認する

export GOROOT=/usr/local/go
export TZ=Asia/Tokyo
curl -Lso/usr/local/go/lib/time/zoneinfo.zip https://github.com/golang/go/blob/5c9a8c0761ae643828a4526db764ac7a50a1a24d/lib/time/zoneinfo.zip?raw=true

確認

  • 無事指定のtimezoneになりました
package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Printf("%v\n", now)
}
2020-12-17 18:20:51.857490357 +0900 JST m=+0.000876904

まとめ

  • 何もしてないのに壊れたになるので
  • latestでの運用はやめましょう
  • goのversionもあげておかないとdebugger使えなかったりして大変なのであげましょう

追記(重要)

この問題は現在おきていません

FROM golang:1.11.9-alpine as build

WORKDIR /go/app

RUN apk add --no-cache musl-dev git gcc

COPY . .

RUN go build -o app

FROM alpine:3.12.1

WORKDIR /app

COPY --from=build /go/app/app .

RUN apk --no-cache add tzdata ca-certificates \
   && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  • こちらで実行するとJSTになります
2020-12-17 18:31:55.460003303 +0900 JST m=+0.003871447

goのslim対応はmasterに入っている

2
0
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
2
0