不使用docker buildx,是否可以手动构建多架构的Docker镜像?

5

我有一个使用Golang编写的项目,已经构建并放入了scratch镜像中:

# Build binary
FROM golang:1.17-alpine AS build-env
ADD . /app
WORKDIR /app
RUN env CGO_ENABLED=0 go build -ldflags="-s -w" -o myapp ./cmd/myapp/main.go

# Create image
FROM scratch
COPY --from=build-env /app/myapp /
ENTRYPOINT ["/myapp"]

由于Golang允许跨多个架构进行交叉编译(而且比在模拟环境中构建要快得多),我想做类似于以下的操作:

# Build binary
FROM golang:1.17-alpine AS build-env
ADD . /app
WORKDIR /app
RUN env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags="-s -w" -o myapp_linux_i386 ./cmd/myapp/main.go             # Linux 32bit
RUN env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o myapp_linux_x86_64 ./cmd/myapp/main.go         # Linux 64bit
RUN env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags="-s -w" -o myapp_linux_arm ./cmd/myapp/main.go      # Linux armv5/armel/arm (it also works on armv6)
RUN env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags="-s -w" -o myapp_linux_armhf ./cmd/myapp/main.go    # Linux armv7/armhf
RUN env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o myapp_linux_aarch64 ./cmd/myapp/main.go        # Linux armv8/aarch64
RUN env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags="-s -w" -o myapp_freebsd_x86_64 ./cmd/myapp/main.go     # FreeBSD 64bit
RUN env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o myapp_darwin_x86_64 ./cmd/myapp/main.go       # Darwin 64bit
RUN env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o myapp_darwin_aarch64 ./cmd/myapp/main.go      # Darwin armv8/aarch64
RUN env CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-s -w" -o myapp_windows_i386.exe ./cmd/myapp/main.go     # Windows 32bit
RUN env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o myapp_windows_x86_64.exe ./cmd/myapp/main.go # Windows 64bit

那么我如何创建和推送多架构的Docker镜像呢?

# Create image
...

不使用buildx是必须的吗?Buildx支持交叉编译,看起来你想避免模拟。 - BMitch
这不是必须的,但是使用仿真构建需要更长时间。特别是对于ARMv6架构,如果不使用仿真可能只需要5秒钟,但使用仿真则需要5到8分钟。 - Erikas
1个回答

7

从问题描述来看,你好像不是想避免使用buildx,而是想避免在解释器下运行编译器,并且希望使用Go内置的交叉编译功能。这已经集成到buildx中:

# Build binary
FROM --platform=$BUILDPLATFORM golang:1.17-alpine AS build-env
ADD . /app
WORKDIR /app
ARG TARGETOS
ARG TARGETARCH
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
    go build -ldflags="-s -w" -o myapp ./cmd/myapp/main.go

# Create image
FROM scratch
COPY --from=build-env /app/myapp /
ENTRYPOINT ["/myapp"]

--platform参数在构建过程中运行第一阶段的平台。TARGETOS和TARGETARCH是buildkit内置的参数。你可以使用以下命令进行构建:

docker buildx build \
  --platform="linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x" \
  -t registry/image:tag \
  .

请注意,MacOS没有对docker的支持,它在该平台上运行于Linux虚拟机中。我不认为Windows/386也是有效的,我只看到过AMD64上运行docker,并可能支持ARM64。


除此之外,有多种方法来推送多平台manifest。Docker内置了docker manifest功能,或者您可以自己生成manifest并使用API调用将其推送到注册表(如果想了解更低级别的细节,请参阅OCI的image-spec和distribution-spec)。但是如果您有Docker,那么使用buildx就很容易。


这对我在dockerfile中有所帮助。我还需要在buildx命令中添加"--provenance false"。 docker buildx build
--provenance false
--platform linux/arm64/v8,linux/amd64 \
- undefined
什么问题需要禁用来源?我看到有人这样做是因为他们没有构建一个多平台的镜像,而是希望qemu来解释其他平台的二进制文件。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接