Rust musl Docker 图片找不到 Cargo
Rust musl Docker image cannot find Cargo
我正试图在 Docker 中获取 Rust 运行ning 以将其用于 32 位 musl 构建。自从我更新它以使用新的 URL 来拉锈,当 运行 使用 bash:
交互式地连接容器时,我遇到了这个问题
root@2c3549fe3169:/sample# cargo
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
奇怪的是,我可以看到可执行文件
root@2c3549fe3169:/sample# ls -l /root/.cargo/bin/
total 101440
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 cargo
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 cargo-clippy
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 cargo-fmt
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rls
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rust-gdb
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rust-lldb
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustc
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustdoc
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustfmt
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustup
root@2c3549fe3169:/sample# date
Sun Feb 17 21:34:21 UTC 2019
root@2c3549fe3169:/sample# file /root/.cargo/bin/cargo
/root/.cargo/bin/cargo: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.9, with debug_info, not stripped
root@2c3549fe3169:/sample# cargo
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
通过以下方式安装:
RUN curl https://sh.rustup.rs -sSf | sh -s -- \
--default-toolchain 1.32.0 \
-y && \
~/.cargo/bin/rustup target add i686-unknown-linux-musl && \
echo "[build]\ntarget = \"i686-unknown-linux-musl\"" > ~/.cargo/config
我可以看到该文件,但我似乎无法 运行 它,即使我切换到该目录也是如此:
root@2c3549fe3169:~/.cargo/bin# ./cargo
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
这是我在 运行ning ldd
:
时看到的
root@4e21c8d37266:/volume# ldd /root/.cargo/bin/cargo
linux-gate.so.1 (0xf7f41000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xf774c000)
librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xf7742000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xf7723000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf7705000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7529000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xf7427000)
/lib/ld-linux.so.2 (0xf7f43000)
这是我完整的Docker文件
FROM i386/ubuntu
RUN apt-get update && apt-get install -y \
cmake \
curl \
file \
git \
g++ \
python \
make \
nano \
ca-certificates \
xz-utils \
musl-tools \
pkg-config \
apt-file \
xutils-dev \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
RUN curl https://sh.rustup.rs -sSf | sh -s -- \
--default-toolchain 1.32.0 \
-y && \
~/.cargo/bin/rustup target add i686-unknown-linux-musl && \
echo "[build]\ntarget = \"i686-unknown-linux-musl\"" > ~/.cargo/config
# Compile C libraries with musl-gcc
ENV SSL_VER=1.0.2j \
CURL_VER=7.52.1 \
CC=musl-gcc \
PREFIX=/usr/local \
PATH=/usr/local/bin:$PATH \
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
RUN curl -sL http://www.openssl.org/source/openssl-$SSL_VER.tar.gz | tar xz && \
cd openssl-$SSL_VER && \
./Configure no-shared --prefix=$PREFIX --openssldir=$PREFIX/ssl no-zlib -m32 linux-elf -fPIC -fno-stack-protector && \
make depend 2> /dev/null && make -j$(nproc) && make install && \
cd .. && rm -rf openssl-$SSL_VER
RUN curl https://curl.haxx.se/download/curl-$CURL_VER.tar.gz | tar xz && \
cd curl-$CURL_VER && \
./configure --enable-shared=no --enable-static=ssl --enable-optimize --prefix=$PREFIX --host=i686-pc-linux-gnu CFLAGS=-m32 \
--with-ca-path=/etc/ssl/certs/ --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt --without-ca-fallback && \
make -j$(nproc) && make install && \
cd .. && rm -rf curl-$CURL_VER
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
SSL_CERT_DIR=/etc/ssl/certs \
OPENSSL_LIB_DIR=$PREFIX/lib \
OPENSSL_INCLUDE_DIR=$PREFIX/include \
OPENSSL_DIR=$PREFIX \
OPENSSL_STATIC=1 \
PATH=/usr/local/bin:/root/.cargo/bin:$PATH
RUN echo $PATH
并根据评论跟踪 cargo
二进制文件:
root@156da6108ff8:~/.cargo/bin# strace -f -e trace=execve cargo
execve("/root/.cargo/bin/cargo", ["cargo"], 0xfffdd8fc /* 20 vars */) = 0
execve("/root/.rustup/toolchains/1.32.0-x86_64-unknown-linux-gnu/bin/cargo", ["/root/.rustup/toolchains/1.32.0-"...], 0x57d95620 /* 25 vars */) = -1 ENOENT (No such file or directory)
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
+++ exited with 1 +++
所以,这是我们调查的总结。
用于构建的基础映像是 i386/ubuntu
,内部有 32 位环境,但是,该映像没有适当地掩盖 uname(2)
调用的结果(通过 setarch linux32
作为入口点),因此,当 运行ning 在 64 位系统(你的情况)上时,构建容器内调用 uname(2)
或 uname(1)
的任何进程都会看到 x86_64
i686
。这就是问题的根源。
当您安装 cargo
时,您下载并 运行 安装脚本,它会检测 运行 所在的平台并下载 rustup-init
的适当版本。此脚本中的平台检测正确识别它 运行 在 32 位环境中但在 64 位内核上,因此脚本下载 rustup-init
的 32 位版本。但是,rustup-init
决定在 x86_64
上 运行(可能它看到 uname(2)
返回的 x86_64
,但不执行“32 位”检查64 位内核环境”的情况,就像安装程序脚本一样)。不用-y
:
安装的时候可以看到
Current installation options:
default host triple: x86_64-unknown-linux-gnu
default toolchain: stable
modify PATH variable: yes
所以,rustup
安装 64 位工具链,当调用 cargo
导致 运行ning 64 位二进制在 32 -位环境,所以你看到错误。
我仍然觉得这里有某种不一致的行为,因为安装脚本和 rustup-init
都是 parts of the same project 而且我真的不明白为什么他们应该检测平台 [=51] =]在相同的环境下(为什么rustup-init
不能像安装脚本一样聪明?)。
正如@Shepmaster 所注意到的,这是一个已知问题 (Rustup installs 64bit compiler on a 32bit Docker instance)。有两种可能的解决方法:
- 通过将
--default-host i686-unknown-linux-gnu
传递给安装程序强制默认工具链的平台;
- 通过运行在
setarch linux32
下安装它来欺骗安装程序,这样它对 uname(2)
的调用将看到 i686
而不是 x86_64
.
就个人而言,我会选择第一个选项,因为它看起来不那么hacky。
我正试图在 Docker 中获取 Rust 运行ning 以将其用于 32 位 musl 构建。自从我更新它以使用新的 URL 来拉锈,当 运行 使用 bash:
交互式地连接容器时,我遇到了这个问题root@2c3549fe3169:/sample# cargo
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
奇怪的是,我可以看到可执行文件
root@2c3549fe3169:/sample# ls -l /root/.cargo/bin/
total 101440
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 cargo
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 cargo-clippy
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 cargo-fmt
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rls
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rust-gdb
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rust-lldb
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustc
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustdoc
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustfmt
-rwxr-xr-x 10 root root 10383380 Feb 17 21:34 rustup
root@2c3549fe3169:/sample# date
Sun Feb 17 21:34:21 UTC 2019
root@2c3549fe3169:/sample# file /root/.cargo/bin/cargo
/root/.cargo/bin/cargo: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.9, with debug_info, not stripped
root@2c3549fe3169:/sample# cargo
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
通过以下方式安装:
RUN curl https://sh.rustup.rs -sSf | sh -s -- \
--default-toolchain 1.32.0 \
-y && \
~/.cargo/bin/rustup target add i686-unknown-linux-musl && \
echo "[build]\ntarget = \"i686-unknown-linux-musl\"" > ~/.cargo/config
我可以看到该文件,但我似乎无法 运行 它,即使我切换到该目录也是如此:
root@2c3549fe3169:~/.cargo/bin# ./cargo
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
这是我在 运行ning ldd
:
root@4e21c8d37266:/volume# ldd /root/.cargo/bin/cargo
linux-gate.so.1 (0xf7f41000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xf774c000)
librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xf7742000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xf7723000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xf7705000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7529000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xf7427000)
/lib/ld-linux.so.2 (0xf7f43000)
这是我完整的Docker文件
FROM i386/ubuntu
RUN apt-get update && apt-get install -y \
cmake \
curl \
file \
git \
g++ \
python \
make \
nano \
ca-certificates \
xz-utils \
musl-tools \
pkg-config \
apt-file \
xutils-dev \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
RUN curl https://sh.rustup.rs -sSf | sh -s -- \
--default-toolchain 1.32.0 \
-y && \
~/.cargo/bin/rustup target add i686-unknown-linux-musl && \
echo "[build]\ntarget = \"i686-unknown-linux-musl\"" > ~/.cargo/config
# Compile C libraries with musl-gcc
ENV SSL_VER=1.0.2j \
CURL_VER=7.52.1 \
CC=musl-gcc \
PREFIX=/usr/local \
PATH=/usr/local/bin:$PATH \
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
RUN curl -sL http://www.openssl.org/source/openssl-$SSL_VER.tar.gz | tar xz && \
cd openssl-$SSL_VER && \
./Configure no-shared --prefix=$PREFIX --openssldir=$PREFIX/ssl no-zlib -m32 linux-elf -fPIC -fno-stack-protector && \
make depend 2> /dev/null && make -j$(nproc) && make install && \
cd .. && rm -rf openssl-$SSL_VER
RUN curl https://curl.haxx.se/download/curl-$CURL_VER.tar.gz | tar xz && \
cd curl-$CURL_VER && \
./configure --enable-shared=no --enable-static=ssl --enable-optimize --prefix=$PREFIX --host=i686-pc-linux-gnu CFLAGS=-m32 \
--with-ca-path=/etc/ssl/certs/ --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt --without-ca-fallback && \
make -j$(nproc) && make install && \
cd .. && rm -rf curl-$CURL_VER
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
SSL_CERT_DIR=/etc/ssl/certs \
OPENSSL_LIB_DIR=$PREFIX/lib \
OPENSSL_INCLUDE_DIR=$PREFIX/include \
OPENSSL_DIR=$PREFIX \
OPENSSL_STATIC=1 \
PATH=/usr/local/bin:/root/.cargo/bin:$PATH
RUN echo $PATH
并根据评论跟踪 cargo
二进制文件:
root@156da6108ff8:~/.cargo/bin# strace -f -e trace=execve cargo
execve("/root/.cargo/bin/cargo", ["cargo"], 0xfffdd8fc /* 20 vars */) = 0
execve("/root/.rustup/toolchains/1.32.0-x86_64-unknown-linux-gnu/bin/cargo", ["/root/.rustup/toolchains/1.32.0-"...], 0x57d95620 /* 25 vars */) = -1 ENOENT (No such file or directory)
error: command failed: 'cargo'
info: caused by: No such file or directory (os error 2)
+++ exited with 1 +++
所以,这是我们调查的总结。
用于构建的基础映像是 i386/ubuntu
,内部有 32 位环境,但是,该映像没有适当地掩盖 uname(2)
调用的结果(通过 setarch linux32
作为入口点),因此,当 运行ning 在 64 位系统(你的情况)上时,构建容器内调用 uname(2)
或 uname(1)
的任何进程都会看到 x86_64
i686
。这就是问题的根源。
当您安装 cargo
时,您下载并 运行 安装脚本,它会检测 运行 所在的平台并下载 rustup-init
的适当版本。此脚本中的平台检测正确识别它 运行 在 32 位环境中但在 64 位内核上,因此脚本下载 rustup-init
的 32 位版本。但是,rustup-init
决定在 x86_64
上 运行(可能它看到 uname(2)
返回的 x86_64
,但不执行“32 位”检查64 位内核环境”的情况,就像安装程序脚本一样)。不用-y
:
Current installation options:
default host triple: x86_64-unknown-linux-gnu
default toolchain: stable
modify PATH variable: yes
所以,rustup
安装 64 位工具链,当调用 cargo
导致 运行ning 64 位二进制在 32 -位环境,所以你看到错误。
我仍然觉得这里有某种不一致的行为,因为安装脚本和 rustup-init
都是 parts of the same project 而且我真的不明白为什么他们应该检测平台 [=51] =]在相同的环境下(为什么rustup-init
不能像安装脚本一样聪明?)。
正如@Shepmaster 所注意到的,这是一个已知问题 (Rustup installs 64bit compiler on a 32bit Docker instance)。有两种可能的解决方法:
- 通过将
--default-host i686-unknown-linux-gnu
传递给安装程序强制默认工具链的平台; - 通过运行在
setarch linux32
下安装它来欺骗安装程序,这样它对uname(2)
的调用将看到i686
而不是x86_64
.
就个人而言,我会选择第一个选项,因为它看起来不那么hacky。