前言
拉取使用别人镜像时发现在不同CPU架构下都可以使用,查找后发现虽然是同一个镜像但是分不同的架构版本,拉取镜像时会拉取当前CPU架构下的镜像,所以可以全平台通用一个命令。
比如golang:1.24.1
docker pull golang:1.24.1
可以看到官方镜像是分为好多架构的
Buildx
1、Buildx 简介
Docker Buildx 是 Docker的CLI插件,来自于Moby BuildKit 。自从Docker 18.06 开始这个插件直接集成到了Docker build 中。
Buildx 是一个构建工具, 它可以帮助用户快速、高效地构建 Docker 镜像, 并支持多种平台的构建。使用 buildx, 用户可以在单个命令中构建多种架构的镜像, 例如 x86 和 ARM 架构, 而无需手动操作多个构建命令。此外, buildx 还支持 Dockerfile 的多阶段构建和缓存, 这可以大大提高镜像构建的效率和速度。
2、Buildx 安装
注意: 在Debian和Ubuntu中不要使用apt install docker.io
命令安装docker,因为docker.io不是官方docker,没有内置buildx,所以安装后无法使用buildx,应该使用官方镜像安装docker才内置buildx。
debian/ubuntu官方教程:https://docs.docker.com/engine/install/debian/
添加密钥
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
安装docker-ce和插件
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
检查版本
docker version
docker buildx version
# github.com/docker/buildx v0.16.1 34c1952
如果已经安装了docker.io,并且有正在运行的镜像且无法停机时,有两种方式可以为docker.io添加Buildx插件
1.手动下载Buildx插件
# 创建文件夹
mkdir -p ~/.docker/cli-plugins/
# 下载到指定目录 ~/.docker/cli-plugins/docker-buildx
# 注意 这是amd架构的
curl -Lo ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/v0.11.2/buildx-v0.11.2.linux-amd64
# arm64:curl -Lo ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/v0.16.2/buildx-v0.16.2.linux-arm64
# 赋予权限
chmod +x ~/.docker/cli-plugins/docker-buildx
# 验证
docker buildx version
开启支持,Docker Buildx属于实验性功能,默认并没有开启
# 编辑配置文件
vi /etc/docker/daemon.json
{
"experimental": true
}
# 重启
systemctl restart docker
2.docker套docker
# 启动一个docker容器
docker run --privileged -d --name docker docker
# 进入docker容器
docker exec -it docker sh
# 1.为qemu安装所有架构
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# 2.取最新的 tonistiigi/binfmt 镜像
docker run --privileged --rm tonistiigi/binfmt --install all
# 查看buildx版本
docker buildx version
# 登录docker账号
docker login -u javaow
# 剩下就是和普通的一样, 先创建Dockerfile.build编译即可
3、构建器管理
要构建多平台镜像就需要使用构建器构建,虽然builder有一个名为default的默认构建器,但是default的驱动器为docker而不是docker-container,所以默认的default构建器不能构建跨多平台容器,需要手动创建构建器并且指定为默认构建器才可以
查看 builder 列表
# 查看 builder 列表
docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
multiarch* docker-container
\_ multiarch0 \_ unix:///var/run/docker.sock running v0.15.1 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
default docker
\_ default \_ default running v0.15.0 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
# 一个默认的default和一个我们自己创建的名为multiarch的根据器
# 其中名称后面带*的是当前正在使用的,也是默认的构建器 当我们运行 docker build 命令时就是在使用此 builder 构建镜像。
创建启动构建器 因为使用 docker 驱动程序的默认 builder 不支持使用单条命令(默认 builder 的 –platform 参数只接受单个值)构建跨平台镜像,所以我们需要使用 docker-container 驱动创建一个新的 builder
# 创建 buildx 构建器 名称为multiarch 驱动器为docker-container
# --use 指定为默认构建器
docker buildx create --name multiarch --driver docker-container --use
启动构建器
#一般默认创建了就会直接启动,如果创建了没有启动就需要手动启动构建器
# 查看构建器列表
docker buildx ls
# 如果发现构建器的STATUS为inactive,那就是还未启用
# 手动启用名为multiarch的构建器,再次ls查看状态为running就是已经启用
docker buildx inspect --bootstrap multiarch
4、架构安装
为构建器安装支持架构
# 1.为qemu安装所有架构
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# 2.使用最新的 tonistiigi/binfmt 镜像
docker run --privileged --rm tonistiigi/binfmt --install all
5、构建
构建并推送
# --platform要构建的平台列表 --no-cache不使用缓存
# -f指定Dockerfile.build 文件位置
# -t指定构建的镜像名称和版本 这里没有指定版本所以是最新镜像
# .说明Dockerfile.build 在当前目录
# --push 构建好后直接push提交到远程仓库
docker buildx build \
--platform linux/amd64,linux/arm64 --no-cache \
-f Dockerfile \
-t javaow/go-buildx . --push
6、实战
注意: 因为go本身支持跨平台编译,所以这里的第一阶段构建使用的是宿主机CPU架构,如果语言不支持或者必须使用不同平台镜像编译 那么需要把$BUILDPLATFOR换成$TARGETPLATFORM
dockerfile
# ================= 第一阶段 =====================
# 使用官方 Go 镜像进行编译
# 镜像的架构平台取自$BUILDPLATFORM变量
# $BUILDPLATFORM变量标识宿主机的架构,因为go支持跨平台编译,所以这里统一使用一个架构镜像编译即可 在go层面使用跨平台编译
# 如果语言不支持或者必须使用不同平台镜像编译 那么需要把$BUILDPLATFOR换成$TARGETPLATFORM
# 别名为builder
FROM --platform=$BUILDPLATFORM golang:1.20 AS builder
# 设置工作目录(创建一个目录并cd过去)
WORKDIR /demo
# 将源代码复制到容器中
COPY main.go .
# 设置 Go 环境变量 切换模块源为中国Go模块代理服务器
RUN go env -w GOPROXY=https://goproxy.cn,direct
# 在当前目录初始化创建main模块并自动解析下载依赖(构建完整模块 tidy完善go.mod)
RUN go mod init main && go mod tidy
# RUN 命令想要使用变量必须提前用 ARG 进行声明,并且多个阶段中要多次声明
ARG TARGETOS
ARG TARGETARCH
# 编译go二进制文件 go层面的跨平台编译(如果是其他语言那么基础镜像就得使用不同平台镜像)
# GOARCH平台从 $TARGETARCH 变量获取
# GOOS从$TARGETOS变量获取
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /demo/main .
# ================= 第二阶段 =====================
# 使用轻量级的 Alpine 镜像
# 架构为$TARGETPLATFORM,$TARGETPLATFORM代表目标架构,由--platform指定
FROM --platform=$TARGETPLATFORM alpine:3.18
# 设置工作目录(创建一个目录并cd过去)
WORKDIR /apps
# 将第一阶段编译好的二进制文件从第一阶段复制到 Alpine 镜像中
# 复制builder阶段中的/demo/main文件到当前阶段的.目录中 .代表当前目录也就是上面WORKDIR的目录
# --from指定阶段FROM的AS别名
COPY --from=builder /demo/main .
# 设置时区为上海,并且创建全局访问的软链接
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' > /etc/timezone \
&& ln -s /apps/main /usr/bin/main
# 设置编码
ENV LANG C.UTF-8
# RUN 命令想要使用变量必须提前用 ARG 进行声明,并且多个阶段中要多次声明
ARG TARGETPLATFORM
# 根据平台不同安装不同的软件包
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
# 创建软链接 解决二进制无法执行问题 只限制amd架构
mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2; \
elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
echo "arm平台"; \
fi
# 设置容器启动命令
CMD main
# 如果有-c等命令就使用ENTRYPOINT,会拼接,CMD只会覆盖
# ENTRYPOINT ["/usr/bin/main"]
编译并提交到远程,这里编译4个架构
# --platform就是Dockerfile.build 文件中的变量,指定不同的基础镜像
# -f指定Dockerfile.build 文件位置
# -t指定构建的镜像名称 这里没有指定版本所以是最新镜像
# .说明Dockerfile.build 在当前目录
# --push 构建好后直接push提交到远程仓库
docker buildx build \
--platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 --no-cache \
-f Dockerfile.build \
-t javaow/go-buildx . --push