Docker で "no such file or directory" が出たときの対処法


適当なプログラムをコンパイルして

$ docker run -it --rm -v $PWD:/go/src/github.com/bgpat/helloworld-server golang bash
root@7dedc18b6923:/go# cd src/github.com/bgpat/helloworld-server/
root@7dedc18b6923:/go/src/github.com/bgpat/helloworld-server# go build -o bin/helloworld
root@7dedc18b6923:/go/src/github.com/bgpat/helloworld-server# exit

実行すると "no such file or directory" が出るけど

$ docker run -it --rm -v $PWD/bin:/usr/local/bin alpine helloworld
standard_init_linux.go:190: exec user process caused "no such file or directory"

ファイルはある

$ docker run -it --rm -v $PWD/bin:/usr/local/bin alpine which helloworld
/usr/local/bin/helloworld
$ docker run -it --rm -v $PWD/bin:/usr/local/bin alpine ls -al /usr/local/bin/helloworld
-rwxr-xr-x    1 root     root       6617238 Jul 11 16:39 /usr/local/bin/helloworld

というときの対処法。

原因

dynamic link されたライブラリが見つからないのが原因。

Docker では Alpine Linux などの軽いイメージが用いることが多いが、
イメージサイズを削るために一般的なライブラリが入っていなかったり、
互換ライブラリ使っていたりするのでこのようなエラーが出る。

対処法1

static link すれば実行時に必要なライブラリがないので動く。

$ docker run -it --rm -v $PWD:/go/src/github.com/bgpat/helloworld-server golang bash
root@5e7fa9b09bfa:/go# cd src/github.com/bgpat/helloworld-server/
root@5e7fa9b09bfa:/go/src/github.com/bgpat/helloworld-server# go build --ldflags '-linkmode external -extldflags -static' -tags netgo -o bin/helloworld

対処法2

すでにビルドされたバイナリを使いたい場合はライブラリを揃えるしかない。
readelf コマンドを使うと必要なライブラリが見れる。

/ # readelf -l /usr/local/bin/helloworld 

Elf file type is EXEC (Executable file)
Entry point 0x456fe0
There are 10 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000000230 0x0000000000000230  R      0x1000
  INTERP         0x0000000000000fe4 0x0000000000400fe4 0x0000000000400fe4
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  NOTE           0x0000000000000f80 0x0000000000400f80 0x0000000000400f80
                 0x0000000000000064 0x0000000000000064  R      0x4
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000020c9b0 0x000000000020c9b0  R E    0x1000
  LOAD           0x000000000020d000 0x000000000060d000 0x000000000060d000
                 0x00000000001c5207 0x00000000001c5207  R      0x1000
  LOAD           0x00000000003d3000 0x00000000007d3000 0x00000000007d3000
                 0x0000000000035720 0x00000000000575b8  RW     0x1000
  DYNAMIC        0x00000000003d3120 0x00000000007d3120 0x00000000007d3120
                 0x0000000000000130 0x0000000000000130  RW     0x8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000008  R      0x8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x8
  LOOS+0x5041580 0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .note.go.buildid 
   03     .text .plt .interp .note.go.buildid 
   04     .rodata .rela .rela.plt .gnu.version .gnu.version_r .hash .dynstr .dynsym .typelink .itablink .gosymtab .gopclntab 
   05     .got.plt .dynamic .got .noptrdata .data .bss .noptrbss 
   06     .dynamic 
   07     .tbss 
   08     
   09     

/lib64/ld-linux-x86-64.so.2 が必要らしい。

パッケージを検索して

https://pkgs.alpinelinux.org/contents?file=ld-linux-x86-64.so.2&path=&name=&branch=edge

libc6-compat を入れればいいことがわかった。

/ # apk add -U libc6-compat
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
(1/1) Installing libc6-compat (1.1.19-r10)
OK: 15 MiB in 15 packages
/ # helloworld

無事起動できた!!