构建多架构Docker镜像并分开推送到Dockerhub
前提
我平时使用的PostgreSQL和Caddy的Docker镜像都是自己构建的,因为会用到一些额外的插件。 我使用的服务器多数是x86架构,也有一些是ARM架构的,所以需要构建多架构的镜像,如果直接分开构建、push,Dockerhub上只会保留最后一次的push,使用的错误的架构,程序是无法启动的。
调查
其实Docker支持使用docker buildx build --platform=linux/arm64,linux/amd64
的方式同时构建多架构镜像,但是异构镜像是使用qemu这样的虚拟机技术实现的,效率可想而知,特别是在性能有限的vps上,构建很慢,而且有时候还会报错。
最好的办法是分开构建,在ARM机器和x86机器上分开构建,这样效率最高。
经过研究发现Docker提供了docker manifest 这个命令用于解决这个问题。
使用
使用很简单,分开构建并推送,然后创建manifest并推送,如果你原来的镜像是lerrybin/pg16:latest
,那么,
1. 在x86机器上构建一个名为lerrybin/pg16-amd64:latest
的镜像并推送到Dockerhub,镜像名称相比原来的名称多了一个架构后缀用于区分。
2. 在ARM机器上构建一个名为lerrybin/pg16-arm64:latest
的镜像,同样推送到Dockerhub。
3. 创建manifest docker manifest create lerrybin/pg16:latest lerrybin/pg16-amd64:latest lerrybin/pg16-arm64:latest
4. push manifest docker manifest push lerrybin/pg16:latest
此时拉去镜像就会自动获取相应架构的镜像,需要注意的是,推送manifest之前要确保对应的镜像已经推送到Dockerhub,不然会报错。
Makefile分享
另外附上我在用的一个Makefile,以供参考
REPOSITORY := lerrybin
NAME := caddy-with-cloudflare
TAG := latest
CURRENT_ARCH := $(shell uname -m)
ifeq ($(CURRENT_ARCH),x86_64)
BUILD_PLATFORM := linux/amd64
SURFIX := amd64
else
BUILD_PLATFORM := linux/arm64
SURFIX := arm64
endif
# Pull the base caddy image
update:
@echo "Pulling the base caddy image..."
@docker pull caddy:2-builder
# Build the Docker image
build: update
@echo "Building the $(NAME) image..."
@docker build --platform=$(BUILD_PLATFORM) -t $(REPOSITORY)/$(NAME)-${SURFIX}:$(TAG) . --push
@docker manifest create -a $(REPOSITORY)/$(NAME):$(TAG) $(REPOSITORY)/$(NAME)-amd64:$(TAG) $(REPOSITORY)/$(NAME)-arm64:$(TAG)
@docker manifest push $(REPOSITORY)/$(NAME):$(TAG)
all: update build
.PHONY: update build
.DEFAULT_GOAL := all
使用过程中遇到问题,可以查看文档 https://docs.docker.com/reference/cli/docker/manifest/#manifest-create