protomaps / go-pmtiles

Single-file executable tool for working with PMTiles archives
BSD 3-Clause "New" or "Revised" License
350 stars 48 forks source link

Docker image cannot `convert` #170

Closed zstadler closed 2 months ago

zstadler commented 2 months ago

When running convert using the Docker image, it fails with an error like

2024/06/08 20:18:17 main.go:177: Failed to create temp file, open /tmp/pmtiles3706954202: no such file or directory

This is probably because there is no /tmp directory in the Docker image.

To reproduce:

Assuming there is an output.mbtiles file in the current directory:

docker run --rm -v .:/data protomaps/go-pmtiles convert /data/output.mbtiles /data/output.pmtiles

The following can be used to produce such an output.mbtiles:

wget https://raw.githubusercontent.com/onthegomap/planetiler/main/planetiler-custommap/src/main/resources/samples/power.yml
docker run -v .:/data ghcr.io/onthegomap/planetiler:latest generate-custom --download --schema=/data/power.yml
daniel-j-h commented 2 months ago

I can reproduce this and I'm running into the same issue for a while now - the workaround I found is setting the TMPDIR env var so that the convert program uses a directory I'm mounting into the container, as in

docker run -it --rm --pull always -e TMPDIR=/data -v $(pwd):/data ghcr.io/protomaps/go-pmtiles:main convert /data/monaco-latest.mbtiles /data/monaco-latest.pmtiles

an alternative could be mounting a proper tmpfs as in https://docs.docker.com/reference/cli/docker/container/run/#tmpfs but that seems a bit more involved.

The issue seems to come from the bare bones scratch base image we're using which doesn't allow writing to /tmp by default

https://github.com/protomaps/go-pmtiles/blob/5a7f686cc7bb7eab560f5270a71d95a81a08cdba/Dockerfile#L6-L8

zstadler commented 2 months ago

BTW, my workaround is to mount the host's /tmp directory:

docker run --rm -v .:/data -v /tmp:/tmp protomaps/go-pmtiles convert /data/output.mbtiles /data/output.pmtiles
bdon commented 2 months ago

If the TMPDIR=/data -v $(pwd):/data workaround is good enough then do we need #171 ?

zstadler commented 2 months ago

Yes, I think #171 is needed. It also has no down-side.

The point of a using temporary directory is that it is different than the current working directory. TMPDIR=/data -v $(pwd):/data is equivalent to -v $(pwd):/data -v $(pwd):/tmp IMHO, -v $(pwd):/data -v /tmp:/tmp is much better, but it is also just a workaround for an incomplete Docker image.

go-pmtiles convert expects a writable /tmp directory and the docker image does not supply it.

bdon commented 2 months ago

Thanks, released in 1.20.0.

In the long term maybe we need a different base image to make these things easier? Are there good minimal alternatives beyond golang:1.21.8-alpine3.19?

zstadler commented 2 months ago

@bdon wrote:

In the long term maybe we need a different base image to make these things easier? Are there good minimal alternatives beyond golang:1.21.8-alpine3.19?

gcr.io/distroless/static seems like a good alternative:

Statically compiled applications (Go) that do not require libc can use the gcr.io/distroless/static image, which contains:

  • ca-certificates
  • A /etc/passwd entry for a root user
  • A /tmp directory
  • tzdata

It only adds a few MB to the scratch-base image

bdon commented 2 months ago

@zstadler looks good if distroless is smaller than alpine, what changes to https://github.com/protomaps/go-pmtiles/blob/main/Dockerfile need to be made to make the switch?