1.前⾔
越来越多的ARM服务器进⼊了我们的视野,docker等容器也都在跨平台编译给出了⽀持,随着国产化的需求不断加强,软件产物在国产化芯⽚交付量越来越多 ,交叉编译显得尤为重要
2.Buildx
macOS 或 Windows 系统的 Docker Desktop,以及 Linux 发⾏版通过 deb 或者 rpm 包所安装的 docker 内置了 buildx,可以使⽤命令 docker buildx 命令查看是否安装了buildx,如果没有安装的话,可以到buildx的release下⾯⼆进制即可,安装⽅式如下:
export DOCKER_BUILDKIT=1
# 当然,此处使⽤的⼆进制版本可能不适合你,可以直接到https://github.com/docker/buildx/releases寻
找适合你的
wget https://github.com/docker/buildx/releases/download/v0.8.2/buildx-v0.8.2.linuxamd64
mv buildx-v0.8.2.linux-amd64 buildx
mkdir -p ~/.docker/cli-plugins
mv buildx ~/.docker/cli-plugins/docker-buildx
buildx 构建的⽅法如下:
# buildx 和 docker build 命令的使⽤体验基本⼀致
docker buildx build .
3.golang跨平台构建镜像示例 本人的开发环境是mac m1 芯片 服务器环境为linux arm 架构 本案例为go加载so动态库的简单demo
- 代码目录结构如下
- add.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char* Add(char* src, int n)
{
char str[20];
sprintf(str, "%d", n);
char *result = malloc(strlen(src)+strlen(str)+1);
strcpy(result, src);
strcat(result, str);
return result;
}
3.add.h
#ifndef __ADD_H__
#define __ADD_H__
char* Add(char* src, int n);
#endif
4.main.go
package main
/*
// 头文件的位置,相对于源文件是当前目录,所以是 .,头文件在多个目录时写多个 #cgo CFLAGS: ...
#cgo CFLAGS: -I./include
// 从哪里加载动态库,位置与文件名,-ladd 加载 libadd.so 文件
#cgo LDFLAGS: -L./lib -ladd -Wl,-rpath,lib
#include "add.h"
*/
import "C"
import "fmt"
func main() {
val := C.Add(C.CString("go"), 2022)
fmt.Println("run c: ", C.GoString(val))
}
- dockerfile
FROM golang:1.17.11-stretch
ENV CGO_ENABLED=1
ENV GOPROXY=https://goproxy.cn,direct
ENV GOOS=linux
ENV GOARCH=arm
ENV CC=arm-linux-gnueabi-gcc
ENV LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib/
RUN apt-get update
RUN apt-get install gcc-arm-linux-gnueabi -y
WORKDIR /app
COPY . .
RUN arm-linux-gnueabi-gcc -fPIC -shared -o lib/libadd.so ./include/add.c && ln -s /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib/ld-linux.so.3
RUN go build -o main main.go
RUN export LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib/
RUN echo $LD_LIBRARY_PATH
CMD ["./main"]
- 构建arm平台运行的镜像产物
#--platform 为指定构建哪些平台的镜像产物
docker buildx build --platform linux/amd64,linux/arm64 -t demo:tag -f dockerfile --push .
有几个坑,需要注意
Docker 在 Linux 系统架构下是不支持 arm 架构镜像,因此我们可以运行一个新的容器让其支持该特性,Docker 桌面版则无需进行此项设置(mac系统)。 需要在内核中使用 QEMU 仿真支持来进行多架构镜像构建
# 安装模拟器(用于多平台镜像构建)
docker run --rm --privileged tonistiigi/binfmt:latest --install all
# 验证是 binfmt_misc 否开启
ls -al /proc/sys/fs/binfmt_misc/
# 验证是否启用了相应的处理器
cat /proc/sys/fs/binfmt_misc/qemu-aarch64