我在工作中使用AWS作为公有云平台,它在提供传统的X64 CPU计算资源的同时,也提供了基于ARM64 CPU的自研Graviton2计算资源,并宣称有更好性能和消费比优势。当前ARM架构的CPU大放异彩,逐渐扩展到数字世界的各个领域。我在使用ECS编排Spring Cloud集群的时候,突然想到能不能让我们的程序同时具备运行在X64和ARM64的能力?由于我的程序是容器化的,那么Docker镜像最好是同时提供X64和ARM64共2个版本.
现在docker hub大部分的热门镜像都支持X64和ARM64,例如openjdk:
那么我能不能也做到跨平台构建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
复制代码
最后的效果:
构建
docker hub中托管的镜像已经显示支持了amd64和arm64
验证
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