【发布时间】:2019-02-28 13:21:18
【问题描述】:
我正在使用 Docker 创建一个容器应用程序,然后将其部署到 kubernetes engine,但是当应用程序初始化时,我收到此错误:
err: open C:\Go/lib/time/zoneinfo.zip: no such file or directory
【问题讨论】:
标签: go kubernetes containers google-kubernetes-engine
我正在使用 Docker 创建一个容器应用程序,然后将其部署到 kubernetes engine,但是当应用程序初始化时,我收到此错误:
err: open C:\Go/lib/time/zoneinfo.zip: no such file or directory
【问题讨论】:
标签: go kubernetes containers google-kubernetes-engine
您可以考虑构建您的 Go 应用程序 with Go 1.15(2020 年 8 月,两年后)
新的嵌入式 tzdata 包
Go 1.15 包含一个新包
time/tzdata,它允许将时区数据库嵌入到程序中。
- 导入此包(如
import _ "time/tzdata")允许程序查找时区信息,即使本地系统上没有时区数据库。- 您还可以通过使用
-tags timetzdata构建来嵌入时区数据库。任何一种方法都会使程序的大小增加大约 800 KB。
这样,一旦作为 Docker 映像部署到 Kubernetes 引擎,它就不必尝试加载任何时区信息,因为所述信息已嵌入其程序中。
此解决方案的缺点是时区信息版本与您用于构建的 Go 版本相关联。
如果您继续为您的项目使用固定版本的 Go,您将保留该版本的时区。
能够独立于 Go 版本更新时区信息(每次重建 Docker 映像以进行部署时更新)可能是更好的选择。
作为插图,请参阅 dolmen 的answer。
【讨论】:
当使用 Go 的 time 包,特别是 LoadLocation 方法时,它会在各个位置查找time zone database 信息。这在 https://golang.org/src/time/zoneinfo.go 源代码中 LoadLocation 的 cmets 中进行了解释。具体来说,它会在这些地方查看:
当您在 Windows 机器上编程时,Go 很可能默认使用第三个选项。但是,当您使用二进制文件时,没有 $GOROOT,因此它在您的容器中不起作用。在大多数版本的 Linux 上,第二个选项可以正常工作,因为它们具有必要的时区数据库文件。但是,我强烈怀疑您引用的优化容器没有。这为您留下了选项 1,它基本上包括将您自己的时区数据库文件放在容器上,然后使用 ZONEINFO 环境变量引用它们的位置。这既是一种痛苦,我还发现当您请求一个不存在的时区文件时,它会默默地失败。
在我自己解决这个问题时,我最终创建了一个使用 LoadLocationFromTZData 方法的包,并尝试简化提供和使用您自己的时区数据库副本的过程。你可以在这里看到我自己的堆栈溢出问题:Detect if ZONEINFO fails in Go。您可以在此处查看我的时区包的存储库:https://github.com/slotheroo/knozone
【讨论】:
使用 Dockerfile 构建 zoneinfo.zip 以及构建您的应用程序。
FROM golang:1.17.1-alpine3.14 AS builder
...
WORKDIR /src
...
RUN GOOS=linux GO111MODULE=on go build -trimpath -o my_app
....
FROM alpine:latest as alpine
# Update timezone info and TLS certificates
RUN apk --no-cache add tzdata zip ca-certificates
WORKDIR /usr/share/zoneinfo
# -0 means no compression. Needed because go's
# tz loader doesn't handle compressed data.
RUN zip -r -0 /zoneinfo.zip .
# Final image.
FROM scratch
# Timezone data
ENV ZONEINFO /zoneinfo.zip
COPY --from=alpine /zoneinfo.zip /
# TLS certificates
COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /src/my_app
您可能还对Google Distroless base Docker images 感兴趣。
【讨论】:
我一周前遇到了同样的问题,最后在 Dockerfile 上解决了这个问题。
首先,您需要找到zoneinfo.zip 文件。例如,在通过 brew 安装 Go 的 MacOS 上可能会变得很棘手。
tztest$ go env GOROOT
/usr/local/Cellar/go/1.12.7/libexec
tztest$ ls -l /usr/local/Cellar/go/1.12.7/libexec/lib/time/zoneinfo.zip
-rwxr-xr-x 1 mau staff 365447 Jul 8 16:29 /usr/local/Cellar/go/1.12.7/libexec/lib/time/zoneinfo.zip
所以解决方法是复制 zoneinfo.zip 并包含在 Dockerfile 的同一目录中。从那里开始,只需将文件添加到 docker 构建过程并覆盖环境变量
ADD zoneinfo.zip /zoneinfo.zip
ENV ZONEINFO /zoneinfo.zip
【讨论】: