Docker多阶段构建Go二进制文件无法执行的修复方案
问题描述
我尝试构建Go应用,main.go文件位于cmd/app/main.go路径下。执行docker build --no-cache .构建镜像,再通过docker run <container_id>运行容器时,出现报错exec ./bin/app: no such file or directory。
本地测试正常:执行go build -o ./bin/app ./cmd/app后,运行./bin/app可正常启动应用。
我的Dockerfile内容:
# Build phase FROM golang:1.20 AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download && go mod verify COPY . . RUN go build -o ./bin/app ./cmd/app # Production phase FROM alpine:3.14 WORKDIR /app COPY --from=builder /app/bin/app ./bin/app ENTRYPOINT [ "./bin/app" ]
进入容器查看文件情况(执行docker run -it fyno/server/multi /bin/sh):
/app # cd bin /app/bin # ls -la total 11636 drwxr-xr-x 2 root root 4096 Apr 12 05:04 . drwxr-xr-x 1 root root 4096 Apr 12 05:04 .. -rwxr-xr-x 1 root root 11904381 Apr 12 05:04 app /app/bin # ./app /bin/sh: ./app: not found /app/bin #
请问该如何修复这个问题?
解决方案
这个问题的核心是Go默认构建的动态链接二进制文件依赖glibc,但Alpine Linux使用的是musl libc,二者不兼容,导致系统找不到二进制文件依赖的库,从而提示"not found"(即使文件实际存在)。
有两种靠谱的修复方式:
方式一:构建静态链接的二进制文件
修改Dockerfile中builder阶段的go build命令,添加环境变量强制生成静态可执行文件:
# 替换原有的RUN go build命令 RUN CGO_ENABLED=0 GOOS=linux go build -o ./bin/app ./cmd/app
CGO_ENABLED=0:禁用CGO,强制Go生成静态链接的二进制,不依赖系统动态库GOOS=linux:明确指定目标操作系统为Linux,避免跨平台构建的问题
修改后的完整Dockerfile:
# Build phase FROM golang:1.20 AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download && go mod verify COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o ./bin/app ./cmd/app # Production phase FROM alpine:3.14 WORKDIR /app COPY --from=builder /app/bin/app ./bin/app ENTRYPOINT [ "./bin/app" ]
方式二:改用基于glibc的基础镜像
如果不想构建静态二进制,可以把生产阶段的Alpine镜像替换为使用glibc的镜像,比如debian:stable-slim:
# 替换原有的FROM alpine:3.14 FROM debian:stable-slim WORKDIR /app COPY --from=builder /app/bin/app ./bin/app ENTRYPOINT [ "./bin/app" ]
Debian默认使用glibc,和Go默认构建的动态链接二进制兼容,无需修改构建命令。
内容的提问来源于stack exchange,提问作者vvv
相关产品推荐
相关产品推荐

