Create the smallest Crystal-lang docker image based on scratch


Official Crystal-lang docker image is Ubuntu-based and relatively big, but production-ready image could be tiny, if we will use docker multi-stage builds. The smallest image could be created using scratch image, but if it’s needed to do some processing before actual code starts, busybox or alpine is recommended.

Dockerfile

Well, just compile app using crystal image and copy resulting binary to the scratch, like below:

# vim:set ft=dockerfile:
FROM crystallang/crystal:0.31.1 as builder

LABEL maintainer="Andrius Kairiukstis <****>"

WORKDIR /src
COPY . .

RUN shards build --production --progress --verbose --warnings=all
RUN ldd ./bin/app | tr -s '[:blank:]' '\n' | grep '^/' | \
    xargs -I % sh -c 'mkdir -p $(dirname deps%); cp % deps%;'
# RUN find ./deps/

################################################################################
FROM scratch

LABEL maintainer="Andrius Kairiukstis <****>"

# Dependences. That will fix DNS resolve issue in docker
COPY --from=builder /src/deps /
COPY --from=builder /lib/x86_64-linux-gnu/libnss_dns.so.* /lib/x86_64-linux-gnu/
COPY --from=builder /lib/x86_64-linux-gnu/libresolv.so.*  /lib/x86_64-linux-gnu/

# app
COPY --from=builder /src/bin/app /app

ENTRYPOINT ["/app"]

Crystal-lang notes

There is issues with DNS – see this https://github.com/crystal-lang/crystal/issues/2426 and https://github.com/crystal-lang/crystal/issues/6099. The best way to resolve I’ve found is to copy libnss and libresolv files.

I’ve also tried to compile with --static option, copying (and not) the DNS libraries (libnss_dns.so and libresolv.so), but did not get DNS working – that image is good only for listening services.

Result

Resulting image is tiny, only 10MB (and the smallest one is 6.25MB only, but DNS won’t working)

$ docker image list dial_demo

# REPOSITORY             TAG                    IMAGE ID      CREATED         SIZE
# smallest-docker-image  scratch-ldd            d819bf2a43f3  21 minutes ago  10MB
# smallest-docker-image  scratch-static-no-dns  595afcfad6f0  13 minutes ago  6.25MB

Can I download this?

Sure. I’ve pushed stuff to my sandbox repository. There is three Dockerfiles, for scratch – 10MB, busybox – 11.2MB and alpine linux – 15.6MB.