原理:简单的理解其实就是在x86平台上生成ARM平台的可执行代码。
为什么要这么做?
答:目的平台上不允许或不能够安装我们所需要的编译器,而我们又需要这个编译器的某些特征;有时是因为目的平台上的资源贫乏,无法运行我们所需要编译器;有时又是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器。
受限于平台的环境和性能就产生了交叉编译主要方式两种:虚拟机或者编译器
QEMU:是一个主机上的虚拟机监视器,通过动态二进制转换来模拟CPU,提供一系列的硬件模型,使用guest os让自己和硬件直接接触,其实是和QEMU模拟出来的硬件打交道,QEMU再把这些指令翻译给真正硬件进行操作。
运行模式
QEMU提供多种运行模式:
User-mode emulation: 这种模式下QEMU上仅进运行一个linux或其他系统程序,由和主机不同的指令集来编译运行。这种模式一般用于交叉编译及交叉调试使用。
System emulation: 这种模式QEMU模拟一个完整的操作系统,包括外设。可用来实现一台物理主机模拟提供多个虚拟主机。QEMU也支持多种guest OS:Linux,windows,BSD等。支持多种指令集 x86,MIPS,ARMv8,PowerCP,SPARC,MicroBlaze等等。
KVM Hosting: 这种模式下QEMU处理包括KVM镜像的启停和移植,也涉及到硬件的模拟,guest的程序运行由KVM请求调用QEMU来实现。
Xen Hosting:这种模式下QEMU仅参与硬件模拟,guest的运行完全对QEMU不可见。
其中User-mode emulation就是用来做交叉编译用的。
实验环境:Ubuntu18.04
首先,安装qemu-user安装包,并更新qemu-arm的状态:
apt-get update && apt-get install -y --no-install-recommends qemu-user-static binfmt-support
update-binfmts --enable qemu-arm
update-binfmts --display qemu-arm
sudo chmod a+x /usr/bin/qemu-*
查看qemu-arm的版本:
qemu-arm-static -version
下载arm架构的容器(在dockerhub可以找到各种非x86架构的镜像):
docker pull docker.io/arm64v8/ubuntu:16.04
docker run -itd --privileged --name ubuntu -v /usr/bin/qemu-aarch64-static:/usr/bin/qemu-aarch64-static docker.io/arm64v8/ubuntu:16.04 /bin/bash
最后进入容器访问:
docker exec -it ubuntu /bin/bash
完事
在编写dockerfile的时候想执行RUN的话需将qemu拷贝到容器中,例如:
FROM docker.io/arm64v8/ubuntu:16.04
COPY ./qemu-aarch64-static /usr/bin
RUN apt-get update && apt-get install nginx
EXPOSE 80
注意:如果内核无法“理解”ARM ELF 文件,需要binfmt_misc 了,确定内核开启了 binfmt_misc,就可以手动添加:
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register
如果在获取镜像的时候提示:no matching manifest for linux/amd64 in the manifest list entries的话,那么需要手动修改 ~/.docker/config.json 文件,添加 {“experimental”:“enabled”}为 docker-cli 开启 docker manifest 命令功能。
例如:
$ docker manifest inspect python:3.6.5
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 2007,
"digest": "sha256:ebfe81b95c56a242a94001b0385f9c14b8972512e773a112adf87a30ed8e774f",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
...
]
}
python:3.6.5 镜像有完整 manifests 描述了镜像支持的平台信息,因此在不同平台直接执行 docker pull python:3.6.5 就会自动根据平台架构获取不同的镜像。
帮助文档:
https://www.tomczhen.com/2018/05/13/cross-platform-build-docker-image/