Docker多阶段构建中FROM scratch无法复制二进制文件求助
问题描述
Docker多阶段构建时,builder阶段已成功生成/bin/tracking二进制文件,但使用FROM scratch作为第二阶段基础镜像时,执行容器提示exec /bin/tracking: no such file or directory;替换为FROM golang:alpine则可正常运行。尝试过相对路径、绝对路径、设置WORKDIR等方法均未解决,需保留FROM scratch配置。
相关Dockerfile代码:
# golang:1.24.0-alpine3.21 using manifest digest (linux/amd64) FROM --platform=linux/amd64 golang:1.24.0-alpine3.21@sha256:2d40d4fc278dad38be0777d5e2a88a2c6dee51b0b29c97a764fc6c6a11ca893c AS builder WORKDIR /app ARG GITHUB_TOKEN ARG REVISION ARG TAG ARG BUILDINFO=github.com/private-digital/foe-tracking/internal/version # Create appuser. ENV USER=appuser ENV UID=1000 RUN adduser \ --disabled-password \ --gecos "" \ --home "/nonexistent" \ --shell "/sbin/nologin" \ --no-create-home \ --uid "${UID}" \ "${USER}" ENV PATH=$PATH:/usr/local/go/bin RUN go env -w GOPRIVATE="github.com/private-digital/*" RUN pwd && ls -al USER root # Install git and certificates # Git is required for fetching the dependencies. RUN apk update && apk add --no-cache gcc musl-dev git ca-certificates wget gcompat openssl # Prepare access to private repos RUN git config --global url."https://${GITHUB_TOKEN}@github.com/private-digital/".insteadOf "https://github.com/private-digital/" # Copy files COPY . . RUN go mod download RUN go mod verify RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -x -v -ldflags="-w -s -X '${BUILDINFO}.Version=${TAG}' -X '${BUILDINFO}.Commit=${REVISION}'" -o /bin/tracking ./cmd/tracking/main.go RUN pwd && ls -al /bin RUN ls -al /app && [ -f /bin/tracking ] && echo "Binary exists" || echo "Binary does not exist" # Binary exists FROM scratch USER appuser:appuser # Define arguments ARG CREATED ARG REVISION ARG TAG # Add Maintainer Info LABEL org.opencontainers.image.authors="FOE-Tracking" LABEL org.opencontainers.image.created="${CREATED}" LABEL org.opencontainers.image.revision="${REVISION}" LABEL org.opencontainers.image.tag="${TAG}" # Import the user, group and certificate files from the builder. COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=0 /etc/passwd /etc/passwd COPY --from=0 /etc/group /etc/group # copy executable COPY --from=0 /bin/tracking /bin/tracking # Run the binary - exec /bin/tracking: no such file or directory ENTRYPOINT ["/bin/tracking"]
解决方案
核心问题是启用了CGO(CGO_ENABLED=1)编译,生成的是动态链接二进制文件,而scratch镜像不含任何系统依赖库(如musl libc),导致系统无法找到二进制依赖的运行时组件,最终误报“文件不存在”。
修复步骤:
修改编译命令为静态编译:
将builder阶段的go build命令中CGO_ENABLED=1改为CGO_ENABLED=0,同时添加-tags netgo确保网络相关依赖也静态编译:RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -x -v -tags netgo -ldflags="-w -s -X '${BUILDINFO}.Version=${TAG}' -X '${BUILDINFO}.Commit=${REVISION}'" -o /bin/tracking ./cmd/tracking/main.go(若代码必须依赖CGO无法禁用,需手动将依赖的系统库从builder镜像复制到scratch镜像中,但静态编译是适配scratch的最优方案)
验证静态编译结果:
在builder阶段添加以下命令,确认二进制为静态链接:RUN ldd /bin/tracking || echo "Static binary"输出
Static binary即表示编译正确,无动态依赖。确保执行权限:
可在builder阶段编译后显式添加执行权限(默认已有,但显式设置更稳妥):RUN chmod +x /bin/tracking
内容的提问来源于stack exchange,提问作者Ravi Parekh
相关产品推荐
相关产品推荐

