15 - Docker 中的 QEMU
15 - Docker 中的 QEMU
掌握在 Docker 中使用 QEMU 实现多架构构建,包括 Buildx 配置与 QEMU 用户模式集成。
15.1 Docker 与 QEMU 的结合
Docker 与 QEMU 的结合主要体现在多架构容器镜像构建上。通过 QEMU 的用户模式仿真,可以在 x86_64 主机上构建和运行 ARM64、RISC-V 等架构的容器镜像。
多架构构建架构:
┌─────────────────────────────────────────────────────┐
│ x86_64 主机 │
│ ┌──────────────────────────────────────────────┐ │
│ │ Docker Buildx │ │
│ │ ┌────────────────┐ ┌────────────────┐ │ │
│ │ │ amd64 builder │ │ arm64 builder │ │ │
│ │ │ (原生) │ │ (QEMU 仿真) │ │ │
│ │ └────────┬───────┘ └────────┬───────┘ │ │
│ └───────────┼───────────────────┼──────────────┘ │
│ │ │ │
│ ┌───────────┴───────────────────┴──────────────┐ │
│ │ Docker Engine │ │
│ │ ┌──────────────┐ ┌──────────────────────┐ │ │
│ │ │ amd64 容器 │ │ arm64 容器 (QEMU) │ │ │
│ │ └──────────────┘ └──────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
15.2 安装 QEMU 用户模式支持
使用 Docker 官方推荐方式
# 使用 tonistiigi/binfmt 设置多架构支持
docker run --privileged --rm tonistiigi/binfmt --install all
# 验证安装
ls /proc/sys/fs/binfmt_misc/qemu-*
# qemu-aarch64 qemu-arm qemu-mips64el qemu-ppc64le qemu-riscv64 qemu-s390x ...
手动安装
# Debian/Ubuntu
sudo apt install -y qemu-user-static
# 注册 binfmt
sudo update-binfmts --enable qemu-aarch64
sudo update-binfmts --enable qemu-arm
# 验证
docker run --rm --platform linux/arm64 arm64v8/ubuntu:22.04 uname -m
# aarch64
15.3 Docker Buildx 配置
安装 Buildx
# Docker Desktop 已包含 Buildx
# 单独安装:
# 1. 下载 buildx 二进制
mkdir -p ~/.docker/cli-plugins/
wget -O ~/.docker/cli-plugins/docker-buildx \
https://github.com/docker/buildx/releases/download/v0.12.1/buildx-v0.12.1.linux-amd64
chmod +x ~/.docker/cli-plugins/docker-buildx
# 2. 创建新的 buildx builder(支持多架构)
docker buildx create --name multiarch --driver docker-container --use
docker buildx inspect --bootstrap
创建多架构 Builder
# 查看当前 builder
docker buildx ls
# 创建支持多架构的 builder
docker buildx create --name mybuilder --driver docker-container --use
# 启动 builder
docker buildx inspect mybuilder --bootstrap
# 查看支持的平台
docker buildx inspect mybuilder | grep Platforms
# Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, ...
15.4 多架构镜像构建
基本多架构构建
# 构建并推送到 Docker Hub
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
-t username/myapp:latest \
--push .
# 仅构建(不推送)
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp:latest \
--load .
# 注意: --load 只支持单架构
# 导出为本地 tar 文件
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp:latest \
--output type=local,dest=./output .
Dockerfile 多架构优化
# 多架构 Dockerfile 示例
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -o /app/server .
FROM --platform=$TARGETPLATFORM alpine:3.19
RUN apk --no-cache add ca-certificates tzdata
COPY --from=builder /app/server /usr/local/bin/server
EXPOSE 8080
CMD ["server"]
使用 ARG 处理架构差异
# 处理不同架构的依赖差异
FROM ubuntu:22.04
ARG TARGETARCH
# 根据架构安装不同包
RUN case "${TARGETARCH}" in \
"amd64") \
apt-get update && apt-get install -y intel-microcode ;; \
"arm64") \
apt-get update && apt-get install -y linux-firmware ;; \
esac && \
rm -rf /var/lib/apt/lists/*
# 架构特定的下载链接
ARG NODE_VERSION=20
RUN ARCH=$(dpkg --print-architecture) && \
wget "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" && \
tar -xf "node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" -C /usr/local --strip-components=1
15.5 实战:构建多架构 Go 应用
# 项目结构
myapp/
├── Dockerfile
├── go.mod
├── go.sum
└── main.go
// main.go
package main
import (
"fmt"
"net/http"
"runtime"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from %s/%s!\n", runtime.GOOS, runtime.GOARCH)
})
fmt.Printf("Server running on %s/%s\n", runtime.GOOS, runtime.GOARCH)
http.ListenAndServe(":8080", nil)
}
# Dockerfile
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -ldflags="-s -w" -o /server .
FROM scratch
COPY --from=builder /server /server
EXPOSE 8080
CMD ["/server"]
# 构建多架构镜像
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x \
-t username/myapp:latest \
--push .
15.6 实战:构建多架构 Python 应用
# Python 多架构 Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
# 构建
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t username/python-app:latest \
--push .
15.7 多架构镜像管理
查看多架构镜像 manifest
# 查看镜像支持的架构
docker buildx imagetools inspect username/myapp:latest
# 输出示例:
# Name: docker.io/username/myapp:latest
# MediaType: application/vnd.oci.image.index.v1+json
# Digest: sha256:...
# Manifests:
# Name: docker.io/username/myapp:latest@sha256:...
# MediaType: application/vnd.oci.image.manifest.v1+json
# Platform: linux/amd64
#
# Name: docker.io/username/myapp:latest@sha256:...
# MediaType: application/vnd.oci.image.manifest.v1+json
# Platform: linux/arm64
手动创建 manifest 列表
# 分别构建各架构
docker buildx build --platform linux/amd64 -t username/myapp:amd64 --push .
docker buildx build --platform linux/arm64 -t username/myapp:arm64 --push .
# 创建 manifest 列表
docker manifest create username/myapp:latest \
username/myapp:amd64 \
username/myapp:arm64
# 推送 manifest
docker manifest push username/myapp:latest
15.8 QEMU 全系统模式在 Docker 中
某些场景下需要在 Docker 中运行完整的虚拟机:
# 在 Docker 中运行 QEMU 全系统仿真
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
qemu-system-x86 \
qemu-utils \
&& rm -rf /var/lib/lib/lists/*
COPY vm-disk.qcow2 /images/vm.qcow2
# 注意: 需要 --privileged 或 KVM 设备
CMD ["qemu-system-x86_64", \
"-m", "2G", \
"-drive", "file=/images/vm.qcow2,format=qcow2", \
"-nographic", \
"-net", "user,hostfwd=tcp::2222-:22"]
# 运行(需要特权模式)
docker run --privileged -d -p 2222:2222 qemu-vm
# 或者使用 KVM 加速
docker run --device=/dev/kvm -d -p 2222:2222 qemu-vm
15.9 CI/CD 多架构构建
GitHub Actions
name: Build Multi-Arch Image
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
username/myapp:${{ github.ref_name }}
username/myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
GitLab CI
build-multi-arch:
stage: build
image: docker:24
services:
- docker:24-dind
before_script:
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker buildx create --use
script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
- docker buildx build
--platform linux/amd64,linux/arm64
-t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
--push .
15.10 性能优化
构建缓存
# 使用 registry 缓存
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myapp:latest \
--cache-from type=registry,ref=myapp:buildcache \
--cache-to type=registry,ref=myapp:buildcache,mode=max \
--push .
减少 QEMU 仿真开销
# 1. 使用多阶段构建,只在最后阶段使用目标架构
# 2. 在 BUILDPLATFORM 上编译,避免 QEMU 编译
# 3. 使用缓存,减少重复构建
# 示例: Go 应用只在最后 COPY 二进制
FROM scratch
COPY --from=builder /app/server /server
要点回顾
| 要点 | 核心内容 |
|---|---|
| binfmt_misc | 通过 tonistiigi/binfmt 安装多架构支持 |
| Buildx | Docker 多架构构建的标准工具 |
| 多平台构建 | --platform linux/amd64,linux/arm64 |
| 最佳实践 | 在 BUILDPLATFORM 编译,避免 QEMU 编译开销 |
| CI/CD | docker/setup-qemu-action + docker/setup-buildx-action |
注意事项
构建速度: QEMU 仿真构建比原生构建慢 5-20 倍。建议在 BUILDPLATFORM 上进行编译,仅在最后阶段使用目标架构。
测试: 多架构镜像应进行跨架构测试,确保各架构都能正常运行。
基础镜像: 确保基础镜像支持目标架构。可以使用
docker manifest inspect查看镜像支持的架构。
扩展阅读
- Docker Buildx 文档
- docker/setup-qemu-action
- docker/setup-buildx-action
- tonistiigi/binfmt
- 多架构 Docker 镜像最佳实践
下一步
→ 16 - 最佳实践:学习 QEMU 性能调优、安全加固与生产部署的最佳实践。