You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust Rocket构建小体积Docker镜像运行报exit code 126

错误原因

docker exec 退出码126 不是二进制没复制——二进制不存在会返回127。126的本质是:系统找到了对应路径的文件,但无法执行,常见触发原因只有三类:

  • 文件没有可执行权限
  • 文件格式/依赖和运行环境不兼容(架构不匹配、动态链接库缺失、不是合法可执行文件)
  • 路径指向了非可执行文件

你两个构建方案分别踩了不同的坑:

多阶段构建+distroless方案问题

  1. 依赖缺失:官方rust基础镜像是Debian系,默认编译出的二进制动态链接glibc,虽然gcr.io/distroless/cc带了基础glibc,但Rocket如果开启TLS、依赖OpenSSL,distroless/cc默认不带OpenSSL库和CA证书,会导致二进制加载失败。
  2. 权限隐患:COPY默认继承源文件权限,如果构建阶段二进制的可执行位丢失,复制后就无法运行。
  3. 路径不严谨:运行阶段没有显式设置WORKDIR,用相对路径./arb_data容易出现路径偏差。

musl静态编译+scratch方案核心错误

这个方案的问题非常明确:你定义的默认二进制名是arbdata(无下划线),但项目Cargo.toml配置的项目名是arb_data(中间带下划线),cargo build生成的二进制名和项目名一致,也就是说你构建阶段复制文件、运行阶段执行的文件名从一开始就写错了。
除此之外你还漏了CA证书复制、没有显式给二进制加执行权限,就算文件名写对也可能碰到执行失败的问题。


修复方案

二选一即可,都能把镜像体积从原来的1GB+压缩到50MB以内,静态编译方案可以做到5MB左右。

方案1:修正版distroless构建(兼容性最好)

不需要处理静态编译的C库兼容问题,适合快速上线:

# 构建阶段
FROM rust:1.75-slim-bookworm as builder
WORKDIR /app
# 安装编译依赖
RUN apt update && apt install -y --no-install-recommends libssl-dev pkg-config ca-certificates
# 依赖缓存层:先复制依赖文件编译空项目,避免每次改代码都重编依赖
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main(){}" > src/main.rs
RUN cargo build --release
# 复制真实源码编译
COPY src ./src
RUN touch src/main.rs && cargo build --release

# 运行阶段
FROM gcr.io/distroless/cc-debian12:nonroot
# 复制CA证书,需要调用外部HTTPS接口时必须加
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
# 显式加可执行权限复制二进制
COPY --from=builder --chmod=755 /app/target/release/arb_data /app/arb_data
USER nonroot
EXPOSE 8000
CMD ["/app/arb_data"]

方案2:修正版musl静态编译+scratch(体积极致小)

完全空的基础镜像,体积最小,适合对镜像大小有严格要求的场景:

# 二进制名和项目实际输出保持一致,带下划线
ARG BINARY_NAME_DEFAULT=arb_data

FROM clux/muslrust:stable as builder
RUN groupadd -g 10001 -r dockergrp && useradd -r -g dockergrp -u 10001 dockeruser
ARG BINARY_NAME_DEFAULT
ENV BINARY_NAME=$BINARY_NAME_DEFAULT

# 依赖缓存层
COPY Cargo.lock Cargo.toml ./
RUN mkdir src && echo "fn main() {print!(\"Dummy main\");}" > src/main.rs
RUN cargo build --target x86_64-unknown-linux-musl --release
# 清理dummy main的编译缓存,匹配正确的二进制名
RUN rm -f target/x86_64-unknown-linux-musl/release/deps/arb_data*

# 编译真实二进制
COPY src ./src
RUN touch src/main.rs && cargo build --target x86_64-unknown-linux-musl --release
RUN mkdir -p /build-out
RUN cp target/x86_64-unknown-linux-musl/release/$BINARY_NAME /build-out/

# 运行阶段
FROM scratch
COPY --from=builder /etc/passwd /etc/passwd
# 复制CA证书
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
USER dockeruser

ARG BINARY_NAME_DEFAULT
ENV BINARY_NAME=$BINARY_NAME_DEFAULT
ENV RUST_LOG="error,$BINARY_NAME=info"
# 显式加可执行权限
COPY --from=builder --chmod=755 /build-out/$BINARY_NAME /$BINARY_NAME

EXPOSE 8000
CMD ["/arb_data"]

前置配置与排查方法
  1. 构建前必须在项目根目录新建.dockerignore文件,写入以下内容,避免把本地不同架构的编译产物、冗余文件复制进构建上下文:
target/
.git/
.gitignore
Dockerfile
  1. 如果改完仍报错,可以在构建后执行以下命令验证二进制状态:
    • 对distroless镜像:docker run --rm --entrypoint ls <你的镜像名> -l /app,看二进制是否存在、权限位是否包含x(可执行标识)
    • 本地验证编译产物:在构建阶段容器里执行ldd /app/target/release/arb_data,动态编译的话会列出所有依赖库,静态编译会提示not a dynamic executable,如果有库找不到就是依赖缺失
  2. 不要依赖COPY的默认权限继承,复制可执行文件时始终加--chmod=755显式赋予执行权限,避免不同构建环境的权限配置差异导致问题。

内容的提问来源于stack exchange,提问作者streetRAT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:18:22