如何从 Dockerfile 有条件地为 M1 Mac Silicon 或 AMD 构建 docker 映像?

问题描述 投票:0回答:3

一些背景:
-我是

Docker
新手(从 1 天开始),
-我有一台小型
VM
正在运行
linux/AMD
,并且我拥有一台 M1 Mac (
ARM
),
-我还想使用 Container for Dev(而不是虚拟环境)。

为了在 M1 Mac 上构建

prod
的容器,我有以下
Dockerfile

请参阅
--platform=linux/amd64
中的
FROM
arg,它可以工作(= 我能够部署)。

FROM --platform=linux/amd64 python:3.10-slim-bullseye
WORKDIR /usr/src/app
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
ENV FLASK_ENV=development 
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"]

但是,我怎么能在我的

Dockerfile
中说不使用
--platform=linux/amd64
if 我想为本地开发构建?
我在
dockerfile
中看到了一些关于 SO 的帖子,但仅限于 RUN
 命令。
有什么想法或最佳实践吗?
谢谢。

docker build dockerfile
3个回答
8
投票
我相信您可以使用

docker buildx build

docker build 上的 --platform 参数来设置平台来构建将在 FROM
 内的任何 
Dockerfile
 调用中使用的映像(如果没有其他的话)已指定(请参阅
Dockerfile FROM),如文档中所述。

然后,您可以在

Dockerfile 中使用 TARGETPLATFORM

 变量来获取它正在构建的平台(如果需要)。如果您想更改构建的默认平台,可以设置 
DOCKER_DEFAULT_PLATFORM 环境变量。


1
投票
我也愿意

    不在 Dockerfile 中指定平台,并使用适用于 M1 mac 的以下命令以特定于平台的方式在本地构建它(或通过在 CI 中指定构建步骤进行生产):
  • docker buildx build --platform=linux/arm64 -t myTag .
    ,或
  • 有两个独立的 Dockerfile(例如
  • Dockerfile.intel
    Dockerfile
    ),其中定义了各自的平台。这样,任何构建管道都会选择 
    Dockerfile
     作为默认值,但对于本地构建,您可以指定要使用哪一个,如下所示:
    docker build -f Dockerfile.intel .
    
    
要将图像作为开发容器运行,请在

devcontainer.json

 中指定图像,然后通过在 VSCode 的命令面板中键入 
Reopen in Container
 来启动和附加。


0
投票
我自己花了很多时间研究这个问题 - 非常沮丧的是在我的 Mac 上构建花了这么长时间。

    您不应该
  • 有两个 Dockerfile - 而应该有一个支持多架构的 Dockerfile。 如果您想要快速构建时间并且没有特定于架构的设置,请在多阶段构建中使用
  • tonistiigi/xx
  • 我使用 Golang 项目作为示例,但它将适用于任何 Dockerfile。
  • 方法 1 - 使用
buildx

QEMU
如果您有一个“常规”Dockerfile - 即您没有 

--platform

语句或任何特定于架构的内容,您可能可以这样做:

docker buildx build -f Dockerfile --platform linux/amd64 --tag my-container:latest --load .

这将使用 QEMU - 但它

并且有时会中断(编译器开关等)。这是因为构建本身是在模拟器中运行的(在本例中是模拟 amd64

方法 2:滚动您自己的多架构镜像:

如果您有这样的 Dockerfile:

FROM golang:1.20 ADD app /app ENV CGO_ENABLED=0 RUN cd /app && go build -o app . WORKDIR /app ENTRYPOINT [ "/app/app" ]

做成这样:

FROM --platform=$BUILDPLATFORM golang:1.20 AS build # get gcc cross toolchain RUN DEBIAN_FRONTEND=noninteractive apt-get update RUN DEBIAN_FRONTEND=noninteractive apt-get -y install g++-x86-64-linux-gnu libc6-dev-amd64-cross RUN DEBIAN_FRONTEND=noninteractive apt-get -y clean ADD app /app ARG TARGETOS TARGETARCH ENV CGO_ENABLED=1 WORKDIR /app # RUN gcc -dumpmachine with --progress=plain here to see what gcc is used by default RUN CC=x86_64-linux-gnu-gcc GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o app . ENTRYPOINT [ "/app/app" ]

注意,我们必须为我们需要的架构安装特定的交叉工具链。这并不理想 - 因为它使我们的 Dockerfile 架构变得特定:/

方法三:使用

tonistiigi/xx工具

Docker层 我们可以使用这个

tonistiigi/xx

包作为基础层。它提供的工具使交叉构建变得更容易并且仍然在本机运行。

FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM golang:1.20

RUN DEBIAN_FRONTEND=noninteractive apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential
RUN DEBIAN_FRONTEND=noninteractive apt-get -y clean

COPY --from=xx / /
ADD app /app
ARG TARGETPLATFORM
RUN xx-apt install -y libc6-dev gcc
ENV CGO_ENABLED=1
WORKDIR /app
RUN xx-go --wrap
RUN go build -o app . && xx-verify app
ENTRYPOINT [ "/app/app" ]

xx-

工具提供了了解 Docker 多平台变量的包装器,然后使用正确的跨工具链构建正确的

TARGETARCH
架构包。
这是最好的方法 - 无论您在哪里运行 

docker build buildx

命令,它都会产生快速的本机交叉构建。它也应该适用于 Docker Desktop 或安装在 Linux 上的 docker -

aarch64
amd64
类似。
相同的构建命令:

docker buildx build -f Dockerfile --platform linux/amd64 --tag my-container:latest --load .

 用于所有三种方法。

对于 OP - 这意味着他们可以在 Docker 桌面(MacOS 端)上运行命令或使用安装在 Linux 虚拟机中的 docker。

查看我的博客文章:

https://www.izumanetworks.com/blog/build-docker-on-apple-m/

了解更多详情。

© www.soinside.com 2019 - 2024. All rights reserved.