Docker 跨平台构建镜像

我在工作中使用AWS作为公有云平台,它在提供传统的X64 CPU计算资源的同时,也提供了基于ARM64 CPU的自研Graviton2计算资源,并宣称有更好性能和消费比优势。当前ARM架构的CPU大放异彩,逐渐扩展到数字世界的各个领域。我在使用ECS编排Spring Cloud集群的时候,突然想到能不能让我们的程序同时具备运行在X64和ARM64的能力?由于我的程序是容器化的,那么Docker镜像最好是同时提供X64和ARM64共2个版本.

现在docker hub大部分的热门镜像都支持X64和ARM64,例如openjdk:

image

那么我能不能也做到跨平台构建docker镜像呢,这里我面临一个问题: ARM64的正经电脑缺失,我需要为linux/amd64上同时构建linux/amd64和linux/arm64镜像. 好在docker早为我们想回到了,相关的资源为: Docker Buildx.

下面我做具体的验证

环境

操作系统 架构 备注
CentOS Stream 8 amd64 普通PC
Debain 11 arm64 实际为raspberry pi 4b运行64bit的raspberry pi os

Docker的版本至少需要19.03及以上的版本,我使用的是20.10.13

跨平台构建实战

安装buildx插件

我们需要先下载buildx插件并在docker中安装插件,以buildx v0.8.0为例

# 检查docker版本
[thinktik@thinkdev ~]$ docker --version
Docker version 20.10.13, build a224086
# 下载好的buildx放在linux上
[thinktik@thinkdev ~]$ ls
buildx-v0.8.0.linux-arm64  envs
# 创建文件夹,存放插件
[thinktik@thinkdev ~]$ mkdir -p ~/.docker/cli-plugins
# 复制到文件夹下
[thinktik@thinkdev ~]$ mv buildx-v0.8.0.linux-arm64 ~/.docker/cli-plugins/
# 赋予插件可执行权限
[thinktik@thinkdev ~]$ chmod +x ~/.docker/cli-plugins/buildx-v0.8.0.linux-arm64 
# 安装插件
[thinktik@thinkdev ~]$ docker buildx install
# 检查我们当前的buildx可以使用的全部的构建实例/构建节点,我们发现还是使用默认的,没有任何改变
[thinktik@thinkdev ~]$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
default * docker                  
  default default         running linux/amd64, linux/386
  
# 安装binfmt,它内置了QEMU能提供跨平台构建功能
[thinktik@thinkdev ~]$ docker run --privileged --rm tonistiigi/binfmt --install all
Unable to find image 'tonistiigi/binfmt:latest' locally
latest: Pulling from tonistiigi/binfmt
2b4d0e08bd75: Pull complete 
c331be51c382: Pull complete 
Digest: sha256:5bf63a53ad6222538112b5ced0f1afb8509132773ea6dd3991a197464962854e
Status: Downloaded newer image for tonistiigi/binfmt:latest
installing: s390x OK
installing: riscv64 OK
installing: mips64le OK
installing: mips64 OK
installing: arm64 OK
installing: arm OK
installing: ppc64le OK
{
  "supported": [
    "linux/amd64",
    "linux/arm64",
    "linux/riscv64",
    "linux/ppc64le",
    "linux/s390x",
    "linux/386",
    "linux/mips64le",
    "linux/mips64",
    "linux/arm/v7",
    "linux/arm/v6"
  ],
  "emulators": [
    "qemu-aarch64",
    "qemu-arm",
    "qemu-mips64",
    "qemu-mips64el",
    "qemu-ppc64le",
    "qemu-riscv64",
    "qemu-s390x"
  ]
}

# 创建一个buildx构建器
[thinktik@thinkdev ~]$ docker buildx create --name crossbuilder --driver docker-container
crossbuilder
# 使用新创建的构建器
[thinktik@thinkdev ~]$ docker buildx use crossbuilder
# 再次检查buildx可以使用的构建实例/构建节点,我们看到新加了一个crossbuilder,并且显示支持了一大批CPU架构
[thinktik@thinkdev ~]$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT             STATUS   PLATFORMS
crossbuilder *  docker-container                     
  crossbuilder0 unix:///var/run/docker.sock inactive 
default         docker                               
  default       default                     running  linux/amd64, linux/386, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/arm/v7, linux/arm/v6
复制代码

以一个Java项目为例构建跨平台镜像

gradle打包出jar

[thinktik@thinkdev ~]$ ls
envs  geo
# 进入java spring项目文件夹中
[thinktik@thinkdev ~]$ cd geo/
[thinktik@thinkdev geo]$ ls
Dockerfile    ecs_task_fargate_best_practice.json  gradle   gradlew.bat  settings.gradle
build.gradle  ecs_task_ec2_best_practice.json  gradlew  README.md    src
# gradle构建
[thinktik@thinkdev geo]$ sh ./gradlew build
...

BUILD SUCCESSFUL in 1m 32s
6 actionable tasks: 6 executed

复制代码

dokcer跨平台打包

# docker登录到docker hub
[thinktik@thinkdev geo]$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: thinktik
Password: 
WARNING! Your password will be stored unencrypted in /home/thinktik/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
# 使用buildx跨平台构建并上传到docker hub. 我们可以看到--platform linux/amd64,linux/arm64/v8表示构建amd64和arm64的linux镜像
[thinktik@thinkdev geo]$ docker buildx build --platform linux/amd64,linux/arm64/v8 -t thinktik/geo:v0.0.1 . --push
复制代码

最后的效果:

构建
image

docker hub中托管的镜像已经显示支持了amd64和arm64
image

验证

amd64验证

[thinktik@thinkdev geo]$ uname -a
Linux thinkdev 4.18.0-365.el8.x86_64 #1 SMP Thu Feb 10 16:11:23 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
[thinktik@thinkdev geo]$ cat /etc/redhat-release 
CentOS Stream release 8
[thinktik@thinkdev geo]$ docker images
REPOSITORY          TAG               IMAGE ID       CREATED      SIZE
moby/buildkit       buildx-stable-1   ab57028900a2   5 days ago   142MB
tonistiigi/binfmt   latest            71d103174212   7 days ago   35.8MB
[thinktik@thinkdev geo]$ docker ps
CONTAINER ID   IMAGE                           COMMAND       CREATED          STATUS          PORTS     NAMES
acd94d37f657   moby/buildkit:buildx-stable-1   "buildkitd"   26 minutes ago   Up 26 minutes             buildx_buildkit_crossbuilder0
# 启动
[thinktik@thinkdev geo]$ docker run -p 8080:8080 thinktik/geo:v0.0.1
Unable to find image 'thinktik/geo:v0.0.1' locally
v0.0.1: Pulling from thinktik/geo
f7a1c6dad281: Pull complete 
ea8366d5a4a5: Pull complete 
e3634e671f7d: Pull complete 
715bddf5d050: Pull complete 
68c830517c75: Pull complete 
4eb5815f08e2: Pull complete 
4f4fb700ef54: Pull complete 
98881fe8dced: Pull complete 
Digest: sha256:71000d743dda76bbcc2abc1a5b8666c64bc9145606decd59fb399025dd5fa4bc
Status: Downloaded newer image for thinktik/geo:v0.0.1

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.4)

2022-03-15 06:58:38.659  INFO 1 --- [           main] cc.omoz.geo.GeoApplication               : Starting GeoApplication using Java 11.0.14.1 on 9abfbf94bf68 with PID 1 (/home/omoz/app.jar started by root in /home/omoz)
2022-03-15 06:58:38.662  INFO 1 --- [           main] cc.omoz.geo.GeoApplication               : No active profile set, falling back to 1 default profile: "default"
2022-03-15 06:58:40.337  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-03-15 06:58:40.352  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-03-15 06:58:40.352  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.58]
2022-03-15 06:58:40.429  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-03-15 06:58:40.429  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1649 ms
2022-03-15 06:58:41.272  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint(s) beneath base path '/actuator'
2022-03-15 06:58:41.383  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-03-15 06:58:41.424  INFO 1 --- [           main] cc.omoz.geo.GeoApplication               : Started GeoApplication in 3.355 seconds (JVM running for 4.531)
2022-03-15 06:59:37.041  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-03-15 06:59:37.041  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-03-15 06:59:37.042  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms

复制代码

arm64验证

运行环境是raspberry pi 4b,它能提供ARM64 CPU运行环境.

thinktik@rpi4b:~ $ uname -a
Linux rpi4b 5.10.92-v8+ #1514 SMP PREEMPT Mon Jan 17 17:39:38 GMT 2022 aarch64 GNU/Linux
thinktik@rpi4b:~ $ cat /etc/debian_version 
11.2
thinktik@rpi4b:~ $ cat /etc/issue
Debian GNU/Linux 11 \n \l

thinktik@rpi4b:~ $ docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
thinktik@rpi4b:~ $ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
thinktik@rpi4b:~ $ docker run -p 8080:8080 thinktik/geo:v0.0.1
Unable to find image 'thinktik/geo:v0.0.1' locally
v0.0.1: Pulling from thinktik/geo
279a020076a7: Pull complete 
3eee4a820130: Pull complete 
10681f9e2933: Pull complete 
818c6d19bbc2: Pull complete 
5d79ebacfbfa: Pull complete 
67860ce0e0fc: Pull complete 
4f4fb700ef54: Pull complete 
540dd97e45f4: Pull complete 
Digest: sha256:71000d743dda76bbcc2abc1a5b8666c64bc9145606decd59fb399025dd5fa4bc
Status: Downloaded newer image for thinktik/geo:v0.0.1

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.4)

2022-03-15 07:14:11.157  INFO 1 --- [           main] cc.omoz.geo.GeoApplication               : Starting GeoApplication using Java 11.0.14.1 on e5f59f92e3f9 with PID 1 (/home/omoz/app.jar started by root in /home/omoz)
2022-03-15 07:14:11.174  INFO 1 --- [           main] cc.omoz.geo.GeoApplication               : No active profile set, falling back to 1 default profile: "default"
2022-03-15 07:14:17.048  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-03-15 07:14:17.105  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-03-15 07:14:17.107  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.58]
2022-03-15 07:14:17.369  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-03-15 07:14:17.371  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 5895 ms
2022-03-15 07:14:20.407  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint(s) beneath base path '/actuator'
2022-03-15 07:14:20.708  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-03-15 07:14:20.784  INFO 1 --- [           main] cc.omoz.geo.GeoApplication               : Started GeoApplication in 11.39 seconds (JVM running for 15.354)
2022-03-15 07:15:05.798  INFO 1 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-03-15 07:15:05.800  INFO 1 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-03-15 07:15:05.806  INFO 1 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms

复制代码

参考:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享