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

FROM scratch
COPY binary /
COPY .env /
COPY cert.pem /etc/ssl/
ENV RUST_BACKTRACE 1
CMD /binary

建筑完成得很好,但当我试着运行它时,我发现:

$ 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 

这是:

$ docker run binary /binary
standard_init_linux.go:195: exec user process caused "no such file or directory"

我不知道该怎么办.这个错误消息在我看来很奇怪.根据official Docker documentation条规则,它必须有效.

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

Docker version 18.02.0-ce, build fc4de447b5

我用C++程序测试,它工作良好,既有CLAN,又有GCC.

它不能处理基于scratchalpinebusyboxbash的图像,但可以处理postgresqlubuntudebian个图像.确切的问题与Rust 和轻量级docker图像有关——否则一切正常.

推荐答案

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

这可能有点令人困惑,因为许多听过Rust的人也听说过Rust二进制文件是静态链接的,但这指的是 crate 中的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)

在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.  

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

还有第二个选项是使用rust-musl-builder docker图像.postgresqldiesel有一些问题,但对于大多数项目来说都是好的.它的工作原理是生成一个静态链接的可执行文件,您可以复制并使用它.如果你想提供一个小尺寸的docker镜像,并且不需要所有无用的额外数据,比如解释器、未使用的库等等,那么这个选项比使用解释器和动态库要好得多.

Rust相关问答推荐

通用池类型xsx

如何最好地并行化修改同一Rust向量的多个切片的代码?

返回的future 不是`发送`

限制未使用的泛型导致编译错误

MPSC频道在接收器处阻塞

这是不是在不造成嵌套的情况下从枚举中取出想要的变体的惯用方法?

你是如何在铁 rust 一侧的金牛座获得应用程序版本的?

如何使用盒装枚举进行模式匹配?

无法定义名为&new&的关联函数,该函数的第一个参数不是self

可以为rust构建脚本编写单元测试吗?

在Rust中判断编译时是否无法访问

如何将单个 struct 实例与插入器一起传递到Rust中的映射

将一个泛型类型转换为另一个泛型类型

零拷贝按步骤引用一段字节

你能在Rust中弃用一个属性吗?

将原始可变指针传递给 C FFI 后出现意外值

n 个范围的笛卡尔积

Rust 中 `Option` 的内存开销不是常量

`use std::error::Error` 声明中断编译

为什么 Rust 标准库同时为 Thing 和 &Thing 实现特征?