一、x86机器上直接运行docker buildx报错

xwl@DESKTOP-RL3B3I2:~/proj/cloud-clipboard-master$ docker buildx build --platform linux/arm64 -t web-clip:1.0-arm .
[+] Building 54.9s (8/12)                                    docker:default
 => [internal] load build definition from Dockerfile                   0.0s
 => => transferring dockerfile: 410B                                   0.0s
 => [internal] load metadata for docker.io/library/node:22.12-alpine3  4.8s
 => [internal] load .dockerignore                                      0.0s
 => => transferring context: 58B                                       0.0s
 => [builder 1/5] FROM docker.io/library/node:22.12-alpine3.21@sha25  49.3s
 => => resolve docker.io/library/node:22.12-alpine3.21@sha256:51eff88  0.0s
 => => sha256:51eff88af6dff26f59316b6e356188ffa2c422b 6.41kB / 6.41kB  0.0s
 => => sha256:be269eaee91460596ce0f9b805cc56455c97315 1.72kB / 1.72kB  0.0s
 => => sha256:48b99dcc508e2c6654d8ac7b0f3ccf28ecd6668 6.20kB / 6.20kB  0.0s
 => => sha256:707c94c90c597447ce10a36c9b56355c1cc67d0 3.98MB / 3.98MB  5.8s
 => => sha256:c5d4869abc5d49c134efbd24c4e61ae5793e 49.48MB / 49.48MB  48.0s
 => => sha256:fe958d7b1773a5ba0872e9bace36e06f7d7dc32 1.26MB / 1.26MB  4.9s
 => => sha256:55d61a2387043410c2bcbd8c1e5d05e91f184e54c42 445B / 445B  5.9s
 => => extracting sha256:707c94c90c597447ce10a36c9b56355c1cc67d0cf593  0.1s
 => => extracting sha256:c5d4869abc5d49c134efbd24c4e61ae5793e16a4b7ad  0.9s
 => => extracting sha256:fe958d7b1773a5ba0872e9bace36e06f7d7dc325f964  0.0s
 => => extracting sha256:55d61a2387043410c2bcbd8c1e5d05e91f184e54c42f  0.0s
 => [internal] load build context                                      0.2s
 => => transferring context: 81.28MB                                   0.2s
 => [builder 2/5] COPY . /app                                          0.2s
 => [builder 3/5] WORKDIR /app/client                                  0.1s
 => ERROR [builder 4/5] RUN npm install                                0.3s
------                                                                      
 > [builder 4/5] RUN npm install:
0.253 exec /bin/sh: exec format error
------
Dockerfile:5
--------------------
   3 |     COPY . /app
   4 |     WORKDIR /app/client
   5 | >>> RUN npm install
   6 |     RUN npm run build
   7 |     
--------------------
ERROR: failed to build: failed to solve: process "/bin/sh -c npm install" did not complete successfully: exit code: 255 

从错误信息来看,你遇到了一个典型的"exec format error"错误,这通常发生在尝试在一种架构的系统上运行另一种架构的二进制文件时。

错误原因分析

  • 错误信息:exec /bin/sh: exec format error
  • 发生在:RUN npm install 步骤
  • 退出码:255

这个错误说明Docker尝试在构建过程中运行的命令与当前环境的架构不兼容。

解决方案

你需要先安装QEMU模拟支持,使Docker能够在x86系统上模拟arm64架构:

  1. 首先运行以下命令安装QEMU支持:
docker run --privileged --rm tonistiigi/binfmt --install all
  1. 然后创建一个buildx构建器:
docker buildx create --name mybuilder --use
  1. 现在重新尝试构建arm64镜像:
docker buildx build --platform linux/arm64 -t web-clip:1.0-arm .

技术解释

当你尝试在x86系统上构建arm64架构的镜像时,Docker需要通过QEMU来模拟arm64架构。如果没有正确安装QEMU支持,就会出现"exec format error"错误,因为系统无法执行arm64架构的二进制文件。

安装binfmt支持后,Docker就能够正确地在构建过程中模拟arm64架构,从而成功执行npm install等命令。

二、启用QEMU模拟的原理是什么,为什么buildx之前docker run --privileged --rm tonistiigi/binfmt --install all运行这个就可以了?

QEMU模拟和binfmt_misc的工作原理是这样的:

核心原理

  1. QEMU(Quick Emulator) 是一个硬件模拟器,能够模拟不同架构的CPU指令集,比如在x86系统上模拟ARM、ARM64等架构。

  2. binfmt_misc 是Linux内核的一个功能,允许系统识别并处理不同格式的可执行文件。它可以配置为当遇到特定架构的可执行文件时,自动使用相应的模拟器来执行。

  3. tonistiigi/binfmt 镜像的作用是在主机系统中注册各种架构的二进制格式处理程序,将不同架构的可执行文件与对应的QEMU模拟器关联起来。

命令解析

当你运行 docker run --privileged --rm tonistiigi/binfmt --install all 时:

  • --privileged 权限:允许容器修改主机的binfmt_misc配置
  • tonistiigi/binfmt 镜像:包含QEMU模拟器和注册脚本
  • --install all:注册所有支持的架构(包括arm64)

工作流程

  1. 容器启动后,会在主机的 /proc/sys/fs/binfmt_misc/ 目录中创建相应的配置文件
  2. 这些配置文件告诉内核:当遇到特定架构的可执行文件时,使用哪个QEMU模拟器来执行
  3. 当Docker buildx构建arm64镜像时,容器内的命令会通过binfmt_misc自动路由到QEMU模拟器
  4. QEMU模拟器执行arm64架构的指令,让x86主机能够正确处理arm64的构建过程

为什么这样就能工作

在没有binfmt_misc支持的情况下,x86系统无法识别和执行arm64架构的二进制文件,因此会出现"exec format error"。通过注册binfmt_misc配置,系统能够自动检测可执行文件的架构并使用相应的模拟器,从而实现跨架构的构建能力。

这就是为什么在使用buildx进行跨架构构建前,需要先运行这个命令来启用QEMU模拟支持。

三、运行一次以后,每次都无需再次运行qemu了嘛

是的,通常情况下运行一次docker run --privileged --rm tonistiigi/binfmt --install all后,QEMU模拟支持会持续生效,不需要每次构建都重新运行。

持久化原理

  • binfmt_misc配置是存储在Linux内核中的,一旦注册就会保持有效
  • 这些配置会在系统重启后丢失,因此重启后需要重新运行该命令
  • 对于Docker Desktop用户,由于底层虚拟机的特性,可能需要在每次重启Docker Desktop后重新运行

验证方法

你可以通过查看binfmt_misc目录来确认配置是否存在:

ls -la /proc/sys/fs/binfmt_misc/

如果看到类似qemu-aarch64的条目,说明arm64架构的支持已经注册成功。

xwl@DESKTOP-RL3B3I2:~/proj/cloud$ ls -la /proc/sys/fs/binfmt_misc/
total 0
drwxr-xr-x 2 root root 0 Mar  3 00:32 .
dr-xr-xr-x 1 root root 0 Mar  3 00:22 ..
-rw-r--r-- 1 root root 0 Mar  3 00:22 WSLInterop
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-aarch64
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-arm
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-loongarch64
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-mips64
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-mips64el
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-ppc64le
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-riscv64
-rw-r--r-- 1 root root 0 Mar  3 00:32 qemu-s390x
--w------- 1 root root 0 Mar  3 00:22 register
-rw-r--r-- 1 root root 0 Mar  3 00:22 status

注意事项

  • 在某些容器化环境或云环境中,权限可能受限,可能需要特殊处理
  • 如果你使用的是Docker Desktop for Windows或macOS,由于运行在虚拟机中,可能需要在每次重启Docker Desktop后重新注册
  • 对于生产环境,建议将此命令添加到系统启动脚本中,确保每次系统启动后自动配置

总结来说,运行一次后通常可以持续使用,直到系统重启。重启后需要重新运行该命令来重新注册binfmt_misc配置。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐