Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
List binary dependencies to build a minimal docker image from scratch
unless ARGV.size > 0
puts " Missing executable file argument"
puts " Usage (in a Dockerfile)"
puts " RUN crystal run ./path/to/list-deps.cr -- ./bin/executable"
exit 1
end
executable = File.expand_path(ARGV[0])
unless File.exists?(executable)
puts " Unable to find #{executable}"
exit 1
end
puts " Extracting libraries for #{executable} ..."
deps = [] of String
output = `ldd #{executable}`.scan(/(\/.*)\s\(/) do |m|
library = m[1]
deps << library
real_lib = File.real_path(library)
deps << real_lib if real_lib != library
end
puts " Generating Dockerfile"
puts
puts "=" * 30
puts "FROM scratch"
deps.each do |dep|
puts "COPY --from=0 #{dep} #{dep}"
end
puts "COPY --from=0 #{executable} /#{File.basename(executable)}"
puts "ENTRYPOINT [\"/#{File.basename(executable)}\"]"
puts "=" * 30
@martinandert

This comment has been minimized.

Copy link

martinandert commented Apr 29, 2017

Nice article! You actually don't need this support script and paste its output into the Docker file. Just change the original Dockerfile to

FROM crystallang/crystal:latest
ADD . /src
WORKDIR /src
RUN shards build --production
RUN ldd bin/miniserver | tr -s '[:blank:]' '\n' | grep '^/' | \
    xargs -I % sh -c 'mkdir -p $(dirname deps%); cp % deps%;'

FROM scratch
COPY --from=0 /src/deps /
COPY --from=0 /src/bin/miniserver /miniserver

ENV WWW=/www
EXPOSE 80

ENTRYPOINT ["/miniserver"]
@timkendall

This comment has been minimized.

Copy link

timkendall commented Nov 18, 2017

I ran into a weird issue when trying either of the above approaches - image built and booted fine but could no longer connect to my Postgres instance. Haven't resolved it yet.

@timkendall

This comment has been minimized.

Copy link

timkendall commented Nov 18, 2017

Looks like the lower level error from crystal-pg is No address found for localhost:5432

@dishcandanty

This comment has been minimized.

Copy link

dishcandanty commented Jan 18, 2018

@timkendall did you ever end up figuring out the resolution issues?

@plainas

This comment has been minimized.

Copy link

plainas commented Feb 22, 2018

@timkendall and @discandanty Those are off topic, but I would guess somewhere you are mapping ports for the container from the first stage. From the the "FROM scratch" line on, it's another dockerfile, so to speak. If this is confusing check the documentation for docker multi stage build https://docs.docker.com/v17.09/engine/userguide/eng-image/multistage-build/

More on the topic... @martinandert , I took that approach, fetched all the dependencies with ldd and copy them to the container and works like a charm. A question though: are there any pitfalls of just building statically?

Say:

FROM crystallang/crystal:latest
ADD . /src
WORKDIR /src
RUN crystal build src/miniserver.cr --static

FROM scratch
COPY --from=0 /src/bin/miniserver /miniserver

ENV WWW=/www
EXPOSE 80

ENTRYPOINT ["/miniserver"]
@charlie-hadden

This comment has been minimized.

Copy link

charlie-hadden commented May 3, 2018

@timkendall @dishcandanty I'm late to the party on this but I ran into the same issue. Ultimately I ended up using the ldd approach, and adding the following lines to my Dockerfile:

COPY --from=0 /lib/x86_64-linux-gnu/libnss_dns.so.2 /lib/x86_64-linux-gnu/libnss_dns.so.2
COPY --from=0 /lib/x86_64-linux-gnu/libresolv.so.2 /lib/x86_64-linux-gnu/libresolv.so.2

This was enough to fix the issue for me.

@liuyang1204

This comment has been minimized.

Copy link

liuyang1204 commented May 17, 2018

@charlie-hadden

I don't know how do you figure out those 2 files. I tried another approach and it works:

RUN shards build --production --static
FROM busybox:glibc

That's it, static build + busybox:glibc

See also: crystal-lang/crystal#6099

@liuyang1204

This comment has been minimized.

Copy link

liuyang1204 commented May 17, 2018

@plainas FYI, the issue I met in the above link is exactly a problem of static build.

@ababich

This comment has been minimized.

Copy link

ababich commented Jun 14, 2018

busybox:glibc makes no sense as we try to make scratch images

@fusillicode

This comment has been minimized.

Copy link

fusillicode commented Sep 29, 2018

I'm trying @martinandert suggestion but after successfully build the image I end up with the following error when I try to run it:

docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown.

Is there anyone encountering the same problem? 🤔
Btw I'm using the Docker Community Edition Version 2.0.0.0-beta1-mac75 (27117), Channel: edge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.