centos 确定cpu是arm 还是x86_x86机器上构建arm架构的image

本文介绍了如何在x86_64机器上使用QEMU-user-static模拟ARM环境,以构建ARM架构的Docker镜像。通过multiarch/qemu-user-static镜像,可以在x86主机上执行ARM指令,实现跨架构的Docker镜像构建。文中详细阐述了qemu-user-static的工作原理,并提供了示例步骤。

本文对在x86机器上构建arm架构的image进行研究,参考文章qemu-user-static, Docker。

背景:Docker镜像技术普及之后,出现了云端和边缘端。云端主要使用Intel机器构成,底层架构多为x86_64(amd64),而边缘端都是由arm设备组成,其底层架构很多,如文章中的aarch64。云端设备资源多,功耗大,而边缘端设备资源少但功耗也小。若在边缘端生成Docker镜像文件,需要在时间和资源上做权衡。因此,云端生成边缘端镜像便成了另一种选择。

构建arm镜像的方法:在arm架构的机器上直接docker build;

使用QEMU在x86_64主机上模拟ARM环境执行docker build。QEMU是开源的machine emulator and virtualizer。

本文介绍如何在x86机器上模拟arm架构指令来构建arm架构的镜像。我们这里使用multiarch/qemu-user-static来实现在x86主机上模拟arm环境,即执行arm的指令。

下面是使用qemu-user-static的效果。

$ uname -m

x86_64

$ docker run --rm -t arm64v8/ubuntu uname -m

standard_init_linux.go:211: exec user process caused "exec format error"

$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

$ docker run --rm -t arm64v8/ubuntu uname -m

aarch64

示例主机为x86_64架构,当在主机上运行arm架构的镜像并在该镜像上执行命令时,报错,因为x86架构解析不了arm架构的指令。但在执行qemu-user-static镜像后,重新运行arm架构的镜像便可以,因为qemu-user-static将arm架构的指令解释成x86架构的指令执行。qemu-user-static支持很多ARM架构。

qemu-user-static就是一组静态的二进制文件qemu-$arch-static,作为interpreter,来执行特定架构的可执行文件。

$ uname -m

x86_64

$ file bin/hello-aarch64

bin/hello-aarch64: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=fa19c63e3c60463e686564eeeb0937959bd6f559, for GNU/Linux 3.7.0, not stripped, too many notes (256)

$ bin/hello-aarch64

bash: bin/hello-aarch64: cannot execute binary file: Exec format error

$ qemu-aarch64-static bin/hello-aarch64

Hello World!

当qemu-user-static和binfmt_misc一起使用,便能模拟各种不同架构。

qemu-user-static 镜像

qemu-user-static是一组镜像,$version为QEMU的版本,$from_arch为host architecture,$to_arch为guest architecture。

multiarch/qemu-user-static image

multiarch/qemu-user-static:$version images

multiarch/qemu-user-static:$from_arch-$to_arch images

multiarch/qemu-user-static:$from_arch-$to_arch-$version images

multiarch/qemu-user-static:$to_arch images

multiarch/qemu-user-static:$to_arch-$version images

multiarch/qemu-user-static:register image

涉及3种文件:register script: 脚本文件,用来register binfmt_misc entries;

/usr/bin/qemu-$arch-static二进制文件,存放在container中,作为interpreter文件;

/proc/sys/fs/binfmt_misc/qemu-$arch文件,binfmt_misc entry files,同时存放在host以及container中,register脚本修改host上的文件。

multiarch/qemu-user-static:$version镜像中包含register脚本及所有二进制文件/usr/bin/qemu-$arch-static;multiarch/qemu-user-static:$to_arch中包含register脚本及$to_arch对应的二进制文件;multiarch/qemu-user-static:register中只包含register脚本。

执行container时,register脚本注册除了当前架构之外的所有支持的processors对应的entry files /proc/sys/fs/binfmt_misc/qemu-$arch。由于这些文件在主机和container中是一样的,register脚本修改主机上的文件。

/proc/sys/fs/binfmt_misc/qemu-aarch64内容如下:

enabled

interpreter /usr/bin/qemu-aarch64-static

flags: F

offset 0

magic 7f454c460201010000000000000000000200b700

mask ffffffffffffff00fffffffffffffffffeffffff

Docker command

语法如下:

$ docker run --rm --privileged multiarch/qemu-user-static [--reset][--help][-p yes][options]

$ docker run --rm --privileged multiarch/qemu-user-static:register [--reset][--help][options]

当/proc/sys/fs/binfmt_misc/qemu-$arch中存在同名的文件时,会报错"sh: write error: File exists"。--reset option表示register entry前移除/proc/sys/fs/binfmt_misc/下面的所有binfmt_misc entry files。-p yes表示在注册binfmt_misc entry时检查interpreter是否存在,若不存在,报错。由于multiarch/qemu-user-static:register镜像中不存在interpreter文件,所以不能使用-p yes。

register脚本执行完上面的操作,便根据提供的options执行QEMU'sscripts/qemu-binfmt-conf.sh, 脚本内容参见Script。该脚本用来配置binfmt_misc来使用qemu interpreter。

Usage: qemu-binfmt-conf.sh [--qemu-path PATH][--debian][--systemd CPU]

[--help][--credential yes|no][--exportdir PATH]

[--persistent yes|no][--qemu-suffix SUFFIX]

Configure binfmt_misc to use qemu interpreter

--help: display this usage

--qemu-path: set path to qemu interpreter ($QEMU_PATH)

--qemu-suffix: add a suffix to the default interpreter name

--debian: don't write into /proc,

instead generate update-binfmts templates

--systemd: don't write into /proc,

instead generate file for systemd-binfmt.service

for the given CPU. If CPU is "ALL", generate a

file for all known cpus

--exportdir: define where to write configuration files

(default: $SYSTEMDDIR or $DEBIANDIR)

--credential: if yes, credential and security tokens are

calculated according to the binary to interpret

--persistent: if yes, the interpreter is loaded when binfmt is

configured and remains in memory. All future uses

are cloned from the open file.

可以执行container中的二进制文件来获取一些信息。

$ docker run --rm -t multiarch/qemu-user-static:aarch64 /usr/bin/qemu-aarch64-static -help

usage: qemu-aarch64 [options] program [arguments...]

Linux CPU emulator (compiled for aarch64 emulation)

...

$ docker run --rm -t multiarch/qemu-user-static:aarch64 /usr/bin/qemu-aarch64-static -version

qemu-aarch64 version 4.0.0 (qemu-4.0.0-5.fc31)

Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers

Kernel Support for miscellaneous Binary Formats

Linux kernel支持混合的binary formats,只需要告知binfmt_misc在调用binary时使用哪个interpreter。binfmt_misc通过使用magic byte sequence来mask文件开头的几个字节来识别binary type。参见文章4.10 version, 3.10 version。

下面介绍kernel version 4.10中如何使用该feature。不同kernel版本之间会有些区别。

- 加载binfmt_misc文建系统

mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc

-生成binfmt_misc entry file

下面命令用来注册新的binary type:

# echo ":$name:$type:$offset:$magic:$mask:$interpreter:$flags" > /proc/sys/fs/binfmt_misc/register

其中,name为/proc/sys/fs/binfmt_misc目录下创建的entry file的文件名;type为识别的类型,Mfor magic andEfor extension;offset为文件中magic/mask的offset,字节为单位,默认为0;magic为binfmt_misc匹配的byte sequence;mask是optional的,与magic执行与操作,默认为oxff;interpreter为执行binary文件的程序,将binary文件作为第一个参数输入;flags用来控制interpreter的调用,optional,F表示在模拟器安装时就检查interpreter文件是否存在;

限制:register string不能超过1920字节;

magic必须在文件的128字节之内,即offset+size(magic)<128;

interpreter string需要小于127字节;

enable/disable binfmt_misc只需要更改/proc/sys/fs/binfmt_misc/status的内容为enable或disable。enable/disable某个binary type只需要在相应的entry file中修改enabled或disable。

移除指定的binary entry:

# echo -1 > /proc/sys/fs/binfmt_misc/qemu-$arch

实操

-构建aarch64架构的镜像

a. 执行命令来注册所有binary type的entry file。

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

b. 编写Dockerfile

---Dockerfile(/home/transwarp/arch/arm64v8)---

FROM arm64v8/ubuntu

RUN mkdir -p /usr/lib/hello

ENV HOME /usr/lib/hello

WORKDIR ${HOME}

RUN touch hello.log

ENV HELLO 'Hello World!'

RUN echo $HELLO > hello.log

c. 构建镜像

执行下面的docker命令来构建镜像

# 构建镜像

docker build -t arm64v8/hello_world /home/transwarp/arch/arm64v8/

# 查看镜像内容 hello.log中的内容为'Hello World!'

docker run -it arm64v8/hello_world bash

# 查看构建镜像的平台架构,注意:这里的"Architecture": "arm64"只是构建环境,x86_64架构也能模拟arm64环境

docker inspect arm64v8/hello_world

-构建amd64架构的镜像

由于我们平台本身就是amd64架构,所以本来就可以直接构建amd64架构的镜像。

a. 编写Dockerfile

---Dockerfile(/home/transwarp/arch/amd64)---

FROM 172.16.1.99/gold/ubuntu:18.04

RUN mkdir -p /usr/lib/hello

ENV HOME /usr/lib/hello

WORKDIR ${HOME}

RUN touch hello.log

ENV HELLO 'Hello World!'

RUN echo $HELLO > hello.log

b. 执行docker命令

# 构建镜像

docker build -t amd64/hello_world /home/transwarp/arch/amd64/

# 查看镜像内容 hello.log中的内容为'Hello World!'

docker run -it amd64/hello_world bash

# 查看构建镜像的平台架构

docker inspect amd64/hello_world

-amd64架构上直接构建arm架构镜像

若构建镜像的Dockerfile中没有RUN指令,在x86架构上可以不使用qemu-user-static镜像模拟arm架构来执行arm架构指令,可以直接使用docker build来生成arm架构的镜像,只要基础镜像为arm镜像。

但若Dockerfile中存在RUN命令或要执行arm架构的镜像,需要先执行multiarch/qemu-user-static镜像。

下面的示例在没有qemu-static-user镜像的主机上实验。Dockerfile中只有aarch64架构的基础镜像arm64v8/ubuntu和copy命令。

---Dockerfile(tw-node3227:/root/tmp/arm64/)---

FROM arm64v8/ubuntu

COPY ./* ./tmp

执行docker命令。

# 在x86机器上直接构建镜像

docker build -t arm64v8/hello_world3227 /root/tmp/arm64/

# 此时"Architecture": "amd64",验证这里只是构建环境的架构

docker inspect arm64v8/hello_world3227

# tag并push镜像

docker tag arm64v8/hello_world3227 172.16.1.99/tmp/hello_world3227:test

docker push 172.16.1.99/tmp/hello_world3227:test

# 执行qemu-user-static镜像的环境中运行arm镜像

docker run -it 172.16.1.99/tmp/hello_world3227:test uname -m

aarch64

运到问题

由于qemu-user-static结合binfmt_misc来实现arm架构的指令模拟,所有与Linux kernel相关。

我们遇到的问题:本地UBUNTU 16.04使用kernel 4.15.0-74-generic,可正常模拟arm架构指令;而集群中CentOS 07使用kernel 3.10.0-327.el7.x86_64,在模拟指令时出现问题,抛出“standard_init_linux.go:190: exec user process caused "no such file or directory"”错误。具体问题描述参见Issue 100.

主要问题是kernel 3.10版本上的entry file中的flags为空,不是F。

解决方法:安装Centos 8来升级kernel version;

手动mount qemu-aarch64-static到容器;

方法2需要现将需要的qemu-*-static下载到本地,执行qemu-user-static:register来生成entry file之后,运行ARM架构的docker命令是使用-v来将本地的qemu-*-static解析文件mount到容器中。下载地址Download。

docker run --rm -t -v $(pwd)/qemu-aarch64-static:/usr/bin/qemu-aarch64-static arm64v8/ubuntu uname -m

aarch64

TODO: 但是具体为什么3.10版本的kernel出现这个问题还需要研究。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值