Vấn đề về time.LoadLocation của Go với Docker
TIL
720
White

Theodore Nguyen viết ngày 06/06/2019

Vấn đề về time.LoadLocation của Go với Docker

Vừa qua, khi phải build 1 service bằng Go và chạy trên Docker thì mình đã gặp 1 vấn đề khá thú vị. Mình sẽ giải thích bằng một ví dụ đơn giản bên dưới.

Vấn đề

Mình có đoạn code như sau

package main

import (
 "fmt"
 "time"
)

func main() {
 // 2019-06-05T18:07:29+07:00
 timestamp := int64(1559732849)
 tz := "Asia/Ho_Chi_Minh"

 loc, _ := time.LoadLocation(tz)
 t := time.Unix(timestamp, 10).In(loc)
 fmt.Printf("Corresponding timestring for timestamp %v in tz '%v': %v\n", timestamp, tz, t.Format(time.RFC3339))
}

Như các bạn có thể thấy, đoạn code không có gì phức tạp. Mình sử dụng 1 timestamp có sẵn và dùng function LoadLocation của package time để chọn timezone hiển thị cho timestamp. Khi chạy trực tiếp bằng command line trên máy mình thì mình ra output:

Corresponding timestring for timestamp 1559732849 in tz 'Asia/Ho_Chi_Minh': 2019-06-05T18:07:29+07:00

Bây giờ mình sẽ chạy đoạn code này trên Docker với Dockerfile như sau

# Dockerfile
FROM golang:1.12.5 as builder

# copy source
WORKDIR /go/src/go-docker-timezone
COPY . .

# build the binary
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o gotz

FROM scratch
COPY --from=builder /go/src/go-docker-timezone/gotz /gotz
ENTRYPOINT ["/gotz"]

Như các bạn có thể thấy, mình dùng 1 image gốc là golang:1.12.5 để làm builder, build source của Go trên builder này rồi copy sang 1 image khác với image gốc là scratch. Entrypoint được set là file binary đã build ở step bên trên. Thử build và chạy Dockerfile này xem chuyện gì xảy ra.

Build


$ docker build -t gotz .
Sending build context to Docker daemon  55.81kB
Step 1/7 : FROM golang:1.12.5 as builder
 ---> 7ced090ee82e
...
Step 7/7 : ENTRYPOINT ["/gotz"]
 ---> Running in 4cf461f342dd
Removing intermediate container 4cf461f342dd
 ---> 8eef414b48ae
Successfully built 8eef414b48ae
Successfully tagged gotz:latest

Run

Văng lỗi rực rỡ

$ docker run gotz
panic: time: missing Location in call to Time.In

goroutine 1 [running]:
time.Time.In(...)
        /usr/local/go/src/time/time.go:1120
main.main()
        /go/src/go-docker-timezone/main.go:14 +0x21a

Nguyên nhân

Đi lòng vòng search trên mạng một hồi thì ra nguyên do là:

  • Go chạy đi mò các file của hệ thống để load thông tin của các timezone (hàm LoadLocation)

  • Image scratch mà mình dùng để chạy file binary của Go không có các file timezone.

  • Trong Linux thì nó nằm ở /usr/share/zoneinfo.

Cách giải quyết

Với nguyên nhân như trên thì cách giải quyết là mình sẽ tìm cách bợ mớ timezone ở đâu đó bỏ vào cái container của image scratch, dùng để chạy file binary. May mắn thay, image builder có sẵn mớ đó nên mình bợ luôn. Thêm dòng này vào Dockerfile, ngay chỗ mình bợ file binary được build ra của Go.

# Dockerfile
...
FROM scratch
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /go/src/go-docker-timezone/gotz /gotz
...

Sau khi build image và chạy lại thì mình được kết quả như mong muốn.

$ docker run gotz
Corresponding timestring for timestamp 1559732849 in tz 'Asia/Ho_Chi_Minh': 2019-06-05T18:07:29+07:00

Source code ví dụ bên trên mình để trên Github: https://github.com/ngdangdat/go-docker-timezone

ngdangdat 07-06-2019

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Theodore Nguyen

2 bài viết.
1 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
1 5
Chào cộng đồng kipalog, Giới thiệu Mình là Đạt, một selftaught programmer, chỉ người tự học lập trình. Mình có kinh nghiệm về web development: ...
Theodore Nguyen viết hơn 1 năm trước
1 5
Bài viết liên quan
White
0 4
fCC: Technical Documentation Page note So I have finished the HTML part of this exercise and I want to come here to lament about the lengthy HTML ...
HungHayHo viết 1 năm trước
0 4
White
2 0
I used Spring boot, Hibernate few times back then at University, I'v started using it again recently. In this (Link), I want to check how Spring J...
Rey viết 7 tháng trước
2 0
White
22 1
Toán tử XOR có tính chất: + A XOR A = 0 + 0 XOR A = A Với tính chất này, có thể cài đặt bài toán sau với độ phức tạp O(N) về runtime, và với O(1)...
kiennt viết gần 3 năm trước
22 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
2 bài viết.
1 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!