6

I'm using Docker to create a container application and then deploy it to kubernetes engine but when the application is been initialized I get this error:

err: open C:\Go/lib/time/zoneinfo.zip: no such file or directory

enter image description here

enter image description here

John Balvin Arias
  • 2,632
  • 3
  • 26
  • 41

4 Answers4

11

You might consider building your Go application with Go 1.15 (August 2020, two years later)

New embedded tzdata package

Go 1.15 includes a new package, time/tzdata, that permits embedding the timezone database into a program.

  • Importing this package (as import _ "time/tzdata") permits the program to find timezone information even if the timezone database is not available on the local system.
  • You can also embed the timezone database by building with -tags timetzdata.

Either approach increases the size of the program by about 800 KB.

That way, once deployed to a Kubernetes engine as a Docker image, it won't have to try and load any timezone information, since said information is embedded in its program.

Caveat: as commented by dolmen:

This solution has the drawback that the timezone information version is linked to the version of Go you use for building.

If you keep using a fixed version of Go for your project, you will keep timezones from that version.

Being able to update the timezone information independently from the Go version (update every time you rebuild the Docker image for deploy) might be a better choice.

As an illustration, see dolmen's answer.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    This solution has the drawback that the timezone information version is linked to the version of Go you use for building. If you keep using a fixed version of Go for your project, you will keep timezones from that version. Being able to update the timezone information independently from the Go version (update every time you rebuild the Docker image for deploy) might be a better choice. – dolmen Sep 24 '21 at 09:13
3

When using Go's time package, specifically the LoadLocation method, it looks for time zone database information in various locations. This is explained in the comments for LoadLocation in the source code at https://golang.org/src/time/zoneinfo.go. Specifically it looks in these places:

  1. A location specified by a ZONEINFO environment variable
  2. Known locations where time zone database files are kept on Unix operating systems
  3. The zoneinfo.zip file in your $GOROOT

When you're programming on a Windows machine, Go is most likely defaulting to the 3rd option. However, there is no $GOROOT when you're working with a binary, so that won't work in your container. On most versions of Linux the 2nd option would work fine as they would have the necessary time zone database files. However, I have a strong suspicion that the optimized container you reference does not. This leaves you with option 1, which essentially consists of putting your own time zone database files on the container and then referencing their location with the ZONEINFO environment variable. This is both kind of a pain in the ass and I've also found that it fails silently when you request a time zone file that doesn't exist.

In my own addressing of this problem I ended up creating a package that utilizes the LoadLocationFromTZData method and tries to simplify the process of providing and working with your own copy of the time zone database. You can see my own stack overflow question here: Detect if ZONEINFO fails in Go. And you can see the repository for my time zone package here: https://github.com/slotheroo/knozone

Slotheroo
  • 925
  • 2
  • 9
  • 17
  • yes, I actually did that, luckly for me, I only need one time zone, that is my time zone(at least for now), hope this get fixed soon, 357B is the size of zoneinfo.zip,it won't hurt anybody just to add it to the binary – John Balvin Arias Sep 26 '18 at 05:21
3

Use the Dockerfile to build the zoneinfo.zip as well as build your app.

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

You might also be interested in Google Distroless base Docker images.

dolmen
  • 8,126
  • 5
  • 40
  • 42
0

I faced that same problem a week ago and ended up resolving like this on the Dockerfile.

First, you need to locate the zoneinfo.zip file. For instance on a MacOS having Go installed via brew can get tricky.

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

So the workaround is copying zoneinfo.zip and include in the same directory of the Dockerfile. From there, is just a matter of ADD the file to the docker build process and override the environment variable

ADD zoneinfo.zip /zoneinfo.zip
ENV ZONEINFO /zoneinfo.zip
coffekid
  • 621
  • 2
  • 10
  • 25