在M1芯片的Docker上构建时遇到exec格式错误问题
在M1芯片的Docker上构建时遇到exec格式错误问题 大家好。
有点卡住了……我正在调用下面的 makefile,同时也包含我的 Dockerfile。 我遇到了以下错误:
docker run -it --network devlab georgelza/goprod-avro:1.0.0 runs_avro.sh
exec /app/runs_avro.sh: exec format error
Dockerfile
FROM bitnami/golang:1.22 AS base_arm64
LABEL Author="George Leonard (georgelza@gmail.com)"
ENV GOPROXY=https://proxy.golang.org,direct
ENV GOSUMDB=sum.golang.org
WORKDIR /app
# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod ./
COPY go.sum ./
RUN go mod tidy
# RUN go get github.com/TylerBrock/colorjson
# RUN go get github.com/brianvoe/gofakeit
# RUN go get github.com/confluentinc/confluent-kafka-go/v2/kafka
# RUN go get github.com/confluentinc/confluent-kafka-go/v2/schemaregistry
# RUN go get github.com/confluentinc/confluent-kafka-go/v2/schemaregistry/serde
# RUN go get github.com/confluentinc/confluent-kafka-go/v2/schemaregistry/serde/avrov2
# RUN go get github.com/google/uuid
# RUN go get github.com/tkanos/gonfig
# RUN go get go.mongodb.org/mongo-driver/bson/bsonrw
# RUN go get go.mongodb.org/mongo-driver/mongo
# RUN go get go.mongodb.org/mongo-driver/mongo/options
# RUN go get go.mongodb.org/mongo-driver/mongo/readpref
# RUN go get google.golang.org/grpc/grpclog
###########START NEW IMAGE###################
FROM base_arm64 AS client
WORKDIR /app
COPY . .
RUN go build -v -o /app/cmd/ /app/cmd/main.go
#RUN GOOS=linux GOARCH=arm64 go build -v -o /app/cmd/ /app/cmd/main.go
###########START NE W IMAGE###################
FROM bitnami/golang:1.22 AS prod
WORKDIR /app
COPY --from=client /app/cmd/main /app/cmd/
COPY runs_avro.sh /app
ENV PATH=/app:/app/cmd:$PATH
CMD ["runs_avro.sh"]
Makefile
sudo docker build --platform linux/arm64 --no-cache -t ${BINARY_NAME}:${VERSION} .
5 回复
这看起来像是 runs_avro.sh 脚本的bug。
我尝试了这两种调用应用程序的方式:
#CMD ["main", "avro"]
# or
CMD ["runs_avro.sh"]
这是 runs_avro.sh 的内容:
. ./.pwd
#go run -v cmd/main.go avro
/app/cmd/main avro
我还尝试了以下内容作为 Dockerfile:
FROM bitnami/golang:1.22 AS base_arm64
LABEL Author="George Leonard (georgelza@gmail.com)"
ENV GOPROXY=https://proxy.golang.org,direct
ENV GOSUMDB=sum.golang.org
WORKDIR /app
# 预复制/缓存 go.mod,以便预下载依赖项,并且仅在后续构建中依赖项发生变化时才重新下载
COPY go.mod ./
COPY go.sum ./
RUN go mod tidy
###########开始新镜像###################
FROM base_arm64 AS client
WORKDIR /app
COPY . .
RUN GOOS=linux GOARCH=arm64 go build -v -o /app/cmd/ /app/cmd/main.go
###########开始新镜像###################
FROM bitnami/golang:1.22 AS prod
WORKDIR /app
COPY --from=client /app/cmd/main /app/cmd/
COPY runs_avro.sh /app
ENV PATH=/app:/app/cmd:$PATH
CMD ["main", "avro"]
这是一个典型的架构不匹配问题。你在M1芯片(ARM64架构)上构建了ARM64的Docker镜像,但runs_avro.sh脚本可能是在x86_64系统上创建的,或者脚本本身包含了不兼容的格式。
问题分析:
runs_avro.sh脚本可能包含Windows换行符(CRLF)而不是Linux换行符(LF)- 脚本可能没有正确的shebang(#!/bin/bash)
- 脚本文件权限不正确
- 脚本本身可能是为不同架构编译的二进制文件
解决方案:
1. 首先修复Dockerfile中的脚本处理:
FROM bitnami/golang:1.22 AS base_arm64
LABEL Author="George Leonard (georgelza@gmail.com)"
ENV GOPROXY=https://proxy.golang.org,direct
ENV GOSUMDB=sum.golang.org
WORKDIR /app
# 复制并修复脚本的换行符
COPY runs_avro.sh /app/
RUN sed -i 's/\r$//' /app/runs_avro.sh && \
chmod +x /app/runs_avro.sh
# pre-copy/cache go.mod for pre-downloading dependencies
COPY go.mod go.sum ./
RUN go mod tidy
###########START NEW IMAGE###################
FROM base_arm64 AS client
WORKDIR /app
COPY . .
# 明确指定ARM64架构构建
RUN GOOS=linux GOARCH=arm64 go build -v -o /app/cmd/main /app/cmd/main.go
###########START NEW IMAGE###################
FROM bitnami/golang:1.22 AS prod
WORKDIR /app
# 确保脚本有正确的权限和格式
COPY --from=client /app/runs_avro.sh /app/
RUN chmod +x /app/runs_avro.sh && \
sed -i 's/\r$//' /app/runs_avro.sh
COPY --from=client /app/cmd/main /app/cmd/
ENV PATH=/app:/app/cmd:$PATH
# 使用exec格式执行
CMD ["/app/runs_avro.sh"]
2. 或者,如果脚本很简单,直接在Dockerfile中创建:
# 在prod阶段创建脚本
FROM bitnami/golang:1.22 AS prod
WORKDIR /app
# 直接创建脚本,避免换行符问题
RUN echo '#!/bin/bash' > /app/runs_avro.sh && \
echo 'cd /app' >> /app/runs_avro.sh && \
echo './cmd/main' >> /app/runs_avro.sh && \
chmod +x /app/runs_avro.sh
COPY --from=client /app/cmd/main /app/cmd/
ENV PATH=/app:/app/cmd:$PATH
CMD ["/app/runs_avro.sh"]
3. 检查并修复本地脚本文件:
在构建之前,先修复本地的runs_avro.sh文件:
# 转换换行符
sed -i 's/\r$//' runs_avro.sh
# 确保有正确的shebang
if ! head -1 runs_avro.sh | grep -q "^#!"; then
echo '#!/bin/bash' | cat - runs_avro.sh > temp && mv temp runs_avro.sh
fi
# 设置执行权限
chmod +x runs_avro.sh
# 验证脚本格式
file runs_avro.sh
4. 使用更简单的CMD格式:
# 改为使用shell格式,让/bin/bash处理脚本
CMD /app/runs_avro.sh
关键修改:
- 添加了
sed -i 's/\r$//'来移除可能的Windows换行符 - 明确添加了
chmod +x设置执行权限 - 在CMD中使用绝对路径
/app/runs_avro.sh - 确保构建时明确指定
GOARCH=arm64
构建命令保持不变:
sudo docker build --platform linux/arm64 --no-cache -t ${BINARY_NAME}:${VERSION} .


