使用buildx实现Docker跨平台编译

使用buildx实现Docker跨平台编译

背景

传统CDN价格比较昂贵,PCDN资源使用节约成本的一种思路,而市面上的盒子资源往往使用的都是ARM32和ARM64的架构,部署方式往往都是使用Docker部署,我们需要打多个镜像来适配不同的架构。如果想要在自己的服务器上制作镜像,往往会出现千奇百怪的问题。

构建ARM镜像的方法主要为下面这几种

  • 在ARM设备上进行编译(最新的Mac都是ARM64架构)
  • 模拟ARM环境,可以使用QEMU实现(参考博客:https://blog.csdn.net/xiaofengxing1/article/details/105490843/)
  • 交叉编译,交叉编译器可以编译出另一个系统平台的可执行文件,可以参考Golang的编译,支持的特别友好。

构建多平台的Docker镜像

Docker 在19.03版本引入了新的插件buildx,可以实现构建多平台的Docker镜像。

开启buildx功能

使用19.X版本还需要进行一些配置才可以开启,在20.X版本Docker默认开启了buildx。下面说下19.x的开启方法

#开启环境变量
export DOCKER_CLI_EXPERIMENTAL=enabled
##验证:
docker buildx version
	github.com/docker/buildx v0.6.1-docker 260d07a9a19b03df969787496419a0808a27ac61
#启用binfmt_misc(Mac跳过)
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
#验证
ls  /proc/sys/fs/binfmt_misc/
	qemu-aarch64  qemu-arm  qemu-ppc64le  qemu-s390x  register  status
cat /proc/sys/fs/binfmt_misc/qemu-aarch64
  enabled
  interpreter /usr/bin/qemu-aarch64
  flags: OCF
  offset 0
  magic 7f454c460201010000000000000000000200b7
  mask ffffffffffffff00fffffffffffffffffeffff

创建并使用多平台构建器

#创建
docker buildx create --use --name mybuilder
#启动
docker buildx inspect mybuilder --bootstrap
+] Building 18.9s (1/1) FINISHED
 => [internal] booting buildkit                                           18.9s
 => => pulling image moby/buildkit:buildx-stable-1                        18.2s
 => => creating container buildx_buildkit_mybuilder0                       0.6s
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

构建多平台镜像

使用一个goalng代码进行测试

package main

import (
	"fmt"
	"log"
	"net/http"
)

func listenServer() {
	http.Handle("/", http.HandlerFunc(lServe))
	http.ListenAndServe(":8080", nil)
}

func lServe(w http.ResponseWriter, r *http.Request) {
	log.Println("response success")
	fmt.Fprintln(w, "hello world")
}
func main() {
	listenServer()
}

Dockerfile文件

FROM golang:alpine
MAINTAINER jiangfeng
WORKDIR $GOPATH/src/test
ADD . ./
ENV GO111MODULE=on
ENV GOPROXY="https://goproxy.io"
RUN go build -o test_docker .
EXPOSE 8080
ENTRYPOINT  ["./test_docker"]

使用Docker buildx进行构建

docker buildx build -t jiangfeng2010/buildx_test --platform=linux/arm/v7,linux/arm64,linux/amd64 . --push

过程如下:

如果只是想保留到本地,可以使用如下命令

docker buildx build -t jiangfeng2010/buildx_test --platform=linux/arm64 -o type=docker .

查看镜像digests:

docker buildx imagetools inspect jiangfeng2010/buildx_test
Name:      docker.io/jiangfeng2010/buildx_test:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:49ec85eb495d740b3fa9dae75fb22616c4f6484a019f97ad8e1c56eb9e888469

Manifests:
  Name:      docker.io/jiangfeng2010/buildx_test:latest@sha256:ee3d8adecd00615a14d25499344981c462c1da1d87e34f48f2215a9a628c502e
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7

  Name:      docker.io/jiangfeng2010/buildx_test:latest@sha256:c5600c69cc83ea4204b8717a58fc4cb107ebaab9cc42c480041f7f3bc68de11e
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      docker.io/jiangfeng2010/buildx_test:latest@sha256:8a27ba2ad897f7857dff83df617aac8c6ce2185d9d327f1342dc7d8a659c0642
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

问题与思考

1.针对不同的架构,我们往往使用的是不同的基础镜像,比如制作ARM32的设备,我们一般会使用arm32v7/debian,在arm64的设备上,我们使用的是arm64v8/debian:10,其实使用buildx的时候只是交叉编译的某一个架构的专属镜像,改如何解决这个问题,一键打包多平台的镜像。

2.传统的盒子资源内存都是十分宝贵的,虚盒资源也希望镜像越小越好,以上面做的测试为例,镜像达到了惊人的300M,这会导致部分盒子跑步起来的情况,如何能把镜像做到50M以内。

posted @ 2022-03-01 23:03  better_feng  阅读(3753)  评论(0编辑  收藏  举报