无法使用Rust可执行文件运行Docker镜像

Vic*_*voy 11 rust docker dockerfile

我试图用我的二进制文件(用Rust编写)创建一个图像,但我得到了不同的错误.这是我的Dockerfile:

FROM scratch
COPY binary /
COPY .env /
COPY cert.pem /etc/ssl/
ENV RUST_BACKTRACE 1
CMD /binary
Run Code Online (Sandbox Code Playgroud)

建筑完成很好但是当我尝试运行它时我得到了这个:

$ docker run binary
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.
ERRO[0000] error waiting for container: context canceled 
Run Code Online (Sandbox Code Playgroud)

还有这个:

$ docker run binary /binary
standard_init_linux.go:195: exec user process caused "no such file or directory"
Run Code Online (Sandbox Code Playgroud)

我不知道该怎么做.错误消息对我来说很奇怪.根据官方Docker文档,它必须工作.

系统信息:最新的Arch Linux和Docker:

Docker version 18.02.0-ce, build fc4de447b5
Run Code Online (Sandbox Code Playgroud)

我用C++程序测试过,它的工作正常,包括clang和gcc.

它不工作scratch,alpine,busybox,或 bash基于图像,但它一起工作postgresql,ubuntudebian图像.确切的问题是与Rust和轻量级docker图像有关的东西 - 否则一切正常.

Vic*_*voy 10

正如@Oleg Sklyar指出的那样,问题是Rust二进制文件是动态链接的.

这可能有点令人困惑,因为许多听说过Rust的人也听说过Rust二进制文件是静态链接的,但这是指条件箱中的Rust代码:crate是静态链接的,因为它们在编译时都是已知的.这并不是指程序可能链接到的现有C动态库,例如libc和其他必备库.通常,这些库也可以构建为静态链接的工件(请参阅本文末尾).要检查您的程序或库是否是动态链接的,您可以使用ldd实用程序:

$ ldd target/release/t
    linux-vdso.so.1 (0x00007ffe43797000)
    libdl.so.2 => /usr/lib/libdl.so.2 (0x00007fa78482d000)
    librt.so.1 => /usr/lib/librt.so.1 (0x00007fa784625000)
    libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fa784407000)
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fa7841f0000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007fa783e39000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fa784ca2000)
Run Code Online (Sandbox Code Playgroud)

您需要在Docker镜像中使用这些库.你还需要翻译; 获取它的路径你可以使用objdump实用程序:

$ LANG=en objdump -s -j .interp target/release/t

target/release/t:     file format elf64-x86-64

Contents of section .interp:
 0270 2f6c6962 36342f6c 642d6c69 6e75782d  /lib64/ld-linux-
 0280 7838362d 36342e73 6f2e3200           x86-64.so.2.  
Run Code Online (Sandbox Code Playgroud)

将文件复制到预期的目录中,一切正常.

还有第二个选项是使用rust-musl-builder泊坞窗图像.有一些问题postgresqldiesel但对于大多数的项目也将是一件好事.它的工作原理是生成一个静态链接的可执行文件,您可以复制和使用它.如果要提供较小的docker镜像并且没有所有无用的额外数据(如解释器,未使用的库等),则此选项比使用解释器和动态库更受欢迎.

  • 我不会*只是将库(特别是*不是*解释器)从编译系统复制到Docker镜像.您应该使用分发包管理器在Docker映像中安装库,然后在容器内构建Rust程序,自动链接到相应的库.您还可以选择使用MUSL构建静态二进制文件. (3认同)
  • 像那样?https://docs.docker.com/develop/develop-images/multistage-build/#before-multi-stage-builds如果是这样,会有什么区别?翻译有什么特别之处? (2认同)
  • 是的,多级构建是适合的工具; 你不想在最终图像中运送Rust编译器.我从来没有听说过有人在机器之间复制解释器,所以感觉超级可疑.Rust playground是一个静态二进制文件,所以你可以使用静态链接,但是你在某些方面它变得正确复杂.有像[rust-musl-builder](https://github.com/emk/rust-musl-builder)这样的图像可以让它更容易. (2认同)