适用场景:手头有 x86 的 VPS/电脑 + ARM 的树莓派/N100 盒子/NAS,同一个镜像要在不同架构上跑;不想每次 docker build 都要换机器,想自动化出 multi-arch;还想自建私有仓库 + 安全扫描 + 签名
核心栈:Docker Buildx + QEMU + GitHub Actions / Drone + Harbor(或 GHCR/ZOT)+ Trivy + Cosign
达成目标:Git Push → 自动构建 linux/amd64 + linux/arm64 + linux/arm/v7 + linux/riscv64 → 推私有仓库 → 扫描 CVE → 签名 → 各节点 docker pull 直接跑
—
0. 架构与流程总览
+----------+ +---------------+ +------------------------+
| Git Push | ----> | CI (Actions/ | ----> | buildx (QEMU 模拟) |
| | | Drone/Woodpecker) | 构建多架构镜像 |
+----------+ +---------------+ +-----------+------------+
|
v
+-------------------------------+
| Harbor / GHCR / ZOT 私有仓库 |
| - 多架构 manifest list |
| - Trivy CVE 扫描 |
| - Cosign 签名验证 |
+----------------+--------------+
|
+----------------------------+-------------+
| | |
x86_64 节点 arm64 节点 riscv64 节点
docker pull docker pull docker pull
自动选架构 自动选架构 自动选架构
关键认知:多架构镜像的本质是 manifest list(清单)——一个 tag 下挂多个架构的 image manifest,客户端 docker pull 时自动按本机架构选层。
—
1. buildx 本地多架构构建(零 CI 起步)
1.1 安装 & 启用
# Docker 新版自带 buildx 插件
docker buildx version
# 创建构建器,启用 QEMU 跨架构模拟
docker run --rm --privileged tonistiigi/binfmt --install all
docker buildx create --name multiarch --driver docker-container --use
docker buildx inspect --bootstrap
# 验证支持的架构
docker buildx ls
# 应看到: linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6, linux/riscv64, linux/ppc64le, linux/s390x...
1.2 构建并推送多架构镜像
# 单条命令出多架构(以你自己项目为例)
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
--tag registry.example.com/myapp:latest \
--tag registry.example.com/myapp:v1.2.3 \
--push \
.
1.3 只看不推(本地调试)
# 构建到本地 buildx 缓存(不推远程)
docker buildx build --platform linux/arm64 --load -t myapp:arm64 .
# 注意: --load 只能单架构;多架构必须 --push 到仓库
—
2. Dockerfile 多架构最佳实践
2.1 用 TARGETARCH 构建参数自动切架构
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY . .
# 交叉编译:在 x86 上出 arm64 二进制(快!无需 QEMU 完整模拟运行)
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags="-s -w" -o /app .
FROM --platform=$TARGETPLATFORM alpine:3.20
COPY --from=builder /app /usr/local/bin/app
EXPOSE 8080
ENTRYPOINT ["/usr/local/bin/app"]
--platform=$BUILDPLATFORM(构建阶段跑在构建机架构)+ $TARGETOS/$TARGETARCH(交叉编译到目标架构),比 QEMU 完整模拟运行快 10-100 倍。
2.2 原生编译 vs QEMU 模拟(选型)
| 语言/场景 | 推荐方式 | 说明 |
| Go / Rust / C(静态编译) | 交叉编译(GOARCH / --target) | 快、无 QEMU 依赖 |
| Python / Node / Java(解释/JIT) | QEMU 模拟(默认) | 用官方多架构 base 镜像即可 |
| 需要原生依赖(C 库、系统包) | 官方多架构 base(debian/alpine/ubuntu 全架构) | 拉取对应架构层 |
| C/C++ 大项目(Qt/OpenCV) | 各架构原生 Runner(真实 arm64 机器跑) | 最稳,配 GitHub 新 arm64 runner |
2.3 避免的错误
# ❌ 硬编码架构
FROM amd64/alpine:3.20 # 只出 x86
# ❌ 用未声明多架构的 base
FROM some/tiny-image:latest # 可能只有 amd64
# ✅ 用官方或明确多架构的镜像
FROM alpine:3.20 # 官方 manifest list 含 amd64/arm64/arm/v7...
—
3. GitHub Actions 自动化多架构构建
# .github/workflows/build-multiarch.yml
name: Build Multi-Arch
on:
push:
tags: ['v*'] # 打 tag 才构建
workflow_dispatch: # 手动触发
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
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 GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
缓存加速:cache-from/to: type=gha 用 GitHub Action 缓存层,重复构建秒级;mode=max 缓存所有阶段。
—
4. 私有仓库落地:Harbor(企业级首选)
4.1 Docker Compose 部署 Harbor
# harbor.yml(下载官方安装包自带模板,改关键项)
version: "3.8"
services:
nginx:
image: goharbor/nginx-photon:v2.11.0
container_name: nginx
restart: always
ports:
- "80:80"
- "443:443"
- "4443:4443" # Notary
volumes:
- ./common/config/nginx:/etc/nginx:z
- /data/harbor:/harbor
depends_on:
- portal
- core
- registry
networks:
- harbor
core:
image: goharbor/harbor-core:v2.11.0
container_name: harbor-core
restart: always
env_file: ./common/config/core/env
volumes:
- /data/harbor/data:/data:z
- /data/harbor/secret:/etc/harbor:z
networks:
- harbor
registry:
image: goharbor/registry-photon:v2.11.0
container_name: registry
restart: always
volumes:
- /data/harbor/registry:/storage:z
- ./common/config/registry:/etc/registry:z
networks:
- harbor
# ... (portal, jobservice, log, redis, database, trivy-adapter, chartmuseum 等)
networks:
harbor:
external: false
# 官方一键安装
wget https://github.com/goharbor/harbor/releases/download/v2.11.0/harbor-online-installer-v2.11.0.tgz
tar xzvf harbor-online-installer-v2.11.0.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
vim harbor.yml # 改 hostname、密码、数据目录、https 证书
sudo ./install.sh --with-trivy --with-notary --with-chartmuseum
4.2 Harbor 核心功能(企业级 vs GHCR)
| 功能 | Harbor | GHCR | Docker Hub |
| 镜像存储 | ✅ 私有/内网 | ✅ 私有/公开 | ⚠️ 免费版私有仓库受限 |
| CVE 扫描 | ✅ Trivy 内置,可阻断漏洞镜像 | ✅ Dependabot 关联 | ⚠️ Docker Scout 收费 |
| 签名验证 | ✅ Notary/Cosign 集成 | ✅ Sigstore(beta) | ⚠️ 有限 |
| GC 清理策略 | ✅ 按 tag/保留策略自动清理 | ❌ 手动 | ❌ 手动 |
| 项目/权限隔离 | ✅ 项目级 RBAC、配额 | ⚠️ 组织级 | ⚠️ 组织级 |
| 复制/同步 | ✅ 规则引擎(推/拉、过滤) | ❌ | ❌ |
| Helm Chart 托管 | ✅ ChartMuseum/Oci | ✅ OCI | ❌ |
| 审计日志 | ✅ 完整审计 | ✅ 基础 | ⚠️ 基础 |
| 部署形态 | 私有/内网/离线 | SaaS | SaaS |
4.3 Trivy 扫描 + 签名验证(在 Harbor 里配置)
# 1. 扫描:创建项目时勾选「自动扫描」,或用 CLI 手动
trivy image --scanners vuln,misconfig,secret,license \
--severity HIGH,CRITICAL \
registry.example.com/myapp:v1.2.3
# 2. 签名:Harbor 支持 Cosign,构建时签名
cosign sign --key cosign.key registry.example.com/myapp:v1.2.3
# 3. Harbor 策略:阻止「高危漏洞」或「未签名」镜像被拉取
# 项目 → 配置 → 漏洞级别策略 → 高危阻断 pull
4.4 客户端配置(各节点)
# 登录(内网/自签证书)
docker login registry.example.com
# 自签证书需加到各节点信任
mkdir -p /etc/docker/certs.d/registry.example.com
cp ca.crt /etc/docker/certs.d/registry.example.com/ca.crt
systemctl restart docker
# 拉取(自动选本机架构)
docker pull registry.example.com/myapp:latest
—
5. 轻量替代方案(看团队规模)
| 工具 | 定位 | 特点 | 适用 |
| ZOT | 极简 OCI 仓库(Go 单二进制) | 无依赖、OCI 原生、Helm Chart、签名、webhook | 个人/小团队、边缘 |
| Registry:2 + UI | Docker 官方仓库 | 最小可用,无扫描/配额 | 最简内网 |
| Nexus / Artifactory | 全功能制品库 | Maven/npm/PyPI/Docker 全支持 | 大型企业、多语言 |
| GitLab Registry | 随 GitLab 自带 | 零额外部署、CI 集成深 | 已用 GitLab 的团队 |
| Gitea + GHCR | Gitea Actions + 包仓库 | 轻量、Git+CI+包一体 | 已用 Gitea 的个人/团队 |
—
6. 从 Docker Compose 迁移到 manifest list(GHCR 示例)
# 1. 构建多架构并推 GHCR
docker buildx build --platform linux/amd64,linux/arm64 \
-t ghcr.io/username/myapp:latest --push .
# 2. 本机拉取验证
docker pull ghcr.io/username/myapp:latest
docker image inspect ghcr.io/username/myapp:latest --format '{{.Architecture}}'
# 3. 看 manifest list
docker buildx imagetools inspect ghcr.io/username/myapp:latest
# 输出:
# Manifest List:
# Platform: linux/amd64
# Platform: linux/arm64
—
7. 常见坑 & 避坑指南
| 现象 | 原因 | 修正 |
构建 arm64 时 exec format error | QEMU 未注册 / 缺 binfmt | docker run --privileged tonistiigi/binfmt --install all |
--load 多架构失败 | --load 只支持单架构到本地 docker | 多架构必须 --push 到仓库,或 --output type=oci,dest=x.tar |
| 交叉编译 Go 出错 | 缺 CGO_ENABLED=0、静态链接 | Go 加 CGO_ENABLED=0;Rust 用 --target + cross-rs |
| Node/Python arm64 构建慢 | QEMU 模拟运行 | 用官方多架构 base,或 arm64 真实 Runner |
| GHCR 拉取慢 | 默认 docker.io 源被墙/慢 | 配镜像加速 ghcr.io 或改 registry-mirrors |
| Harbor 自签证书不信任 | 各节点无 CA | 分发 CA 到 /etc/docker/certs.d/ |
| 推上去了但拉下来是错架构 | 客户端缓存 / manifest 混 | docker buildx imagetools inspect 检查 manifest list |
| 镜像太大 | 构建层冗余 | 多阶段构建、--platform=$BUILDPLATFORM 构建阶段只跑编译工具 |
—
8. 一键部署脚本(构建 + 推 + 扫 + 签)
#!/usr/bin/env bash
# build-release.sh —— 本地一键出多架构 + 推 GHCR + 扫描 + 签名
set -euo pipefail
IMAGE="ghcr.io/yourname/myapp"
VERSION="${1:-$(date +%Y%m%d%H%M)}"
PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7"
echo ">>> 构建多架构镜像 $IMAGE:$VERSION"
docker buildx build \
--platform "$PLATFORMS" \
--tag "$IMAGE:$VERSION" \
--tag "$IMAGE:latest" \
--push .
echo ">>> CVE 扫描"
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --severity HIGH,CRITICAL "$IMAGE:$VERSION"
echo ">>> 签名"
cosign sign --key cosign.key "$IMAGE:$VERSION"
echo ">>> 验证清单"
docker buildx imagetools inspect "$IMAGE:$VERSION"
echo "✅ 完成!各节点执行: docker pull $IMAGE:latest"
—
(完)