Skip to content

Instantly share code, notes, and snippets.

@bcardiff
Last active May 29, 2024 17:37
Show Gist options
  • Save bcardiff/85ae47e66ff0df35a78697508fcb49af to your computer and use it in GitHub Desktop.
Save bcardiff/85ae47e66ff0df35a78697508fcb49af to your computer and use it in GitHub Desktop.
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
@LeonLiuY
Copy link

LeonLiuY commented May 17, 2018

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

@ababich
Copy link

ababich commented Jun 14, 2018

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

@fusillicode
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

@kalinon
Copy link

kalinon commented Sep 27, 2019

Had issues with scratch using 0.31.0. I think its because it cant find uname:

Unhandled exception: execvp (/bin/sh "-c" "uname \"${@}\"" "--"): No such file or directory: No such file or directory (Errno)
  from usr/share/crystal/src/process.cr:296:52 in 'initialize:shell:input:output:error'
  from usr/share/crystal/src/process.cr:251:3 in 'new:shell:input:output:error'
  from usr/share/crystal/src/process.cr:583:3 in '`'
  from usr/share/crystal/src/openssl/bio.cr:81:7 in '~Pinger::OS:init'
  from usr/share/crystal/src/crystal/once.cr:255:3 in 'once'
  from usr/share/crystal/src/crystal/once.cr:48:3 in '__crystal_once'
  from src/lib/pinger/src/pinger.cr:15:3 in '__crystal_main'
  from usr/share/crystal/src/crystal/main.cr:97:5 in 'main_user_code'
  from usr/share/crystal/src/crystal/main.cr:86:7 in 'main'
  from usr/share/crystal/src/crystal/main.cr:106:3 in 'main'
  from __libc_start_main
  from _start
  from ???

However, changing it alpine worked.

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 alpine
COPY --from=0 /src/deps /
COPY --from=0 /src/bin/miniserver /miniserver

ENTRYPOINT ["/miniserver"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment