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.