这篇文章介绍一下使用QEMU进行容器化的构建和执行方式。
- QEMU是什么
- 常见问题的场景
- 问题再现
-
- 事前准备
- 启动容器并进入
- 解决方法
- 结果确认
- 构建ARM镜像并确认
QEMU是一个通用的开源的跨平台仿真模拟器,提供user和system两种模式。其模拟的作用可是可以模拟在特定的体系结构下的应用的执行或者构建,比如在x86的体系结构的操作系统上运行ARM的应用。
常见问题的场景在ARM体系结构的硬件环境中安装Docker,然后构建并运行ARM的镜像自然非常简单,但是如果没有ARM环境,只有x86的机器又想做这件事情,这时QEMU也就有了用武之地,比如用友的技术中台似乎就是通过QEMU来模拟ARM硬件进行模拟。
- 获取ARM格式的Alpine镜像
执行命令:docker pull arm64v8/alpine:3.12.1
liumiaocn:~ liumiao$ docker images |grep arm64v8/alpine arm64v8/alpine 3.12.1 2e77e061c27f 6 days ago 5.32MB liumiaocn:~ liumiao$启动容器并进入
- 启动容器并进入
执行命令:docker run --rm -it arm64v8/alpine:3.12.1 sh
可以看到在x86的机器上执行时出现了如下错误信息:
liumiaocn:~ liumiao$ uname -m x86_64 liumiaocn:~ liumiao$ docker run --rm -it arm64v8/alpine:3.12.1 sh standard_init_linux.go:211: exec user process caused "no such file or directory" liumiaocn:~ liumiao$
有的时候提示现象不同,其实主要原因就在于体系架构不同所导致的
解决方法可以根据需要到QEMU上下载对应的可执行文件进行执行,还有一种最为简单的方式就是使用容器的方式执行,使用如下命令,可使得当前机器可以直接直接模拟相应的体系结构
执行命令:docker run --rm --privileged multiarch/qemu-user-static --reset --persistent yes
liumiaocn:~ liumiao$ docker run --rm --privileged multiarch/qemu-user-static --reset --persistent yes Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb Setting /usr/bin/qemu-sparc-static as binfmt interpreter for sparc Setting /usr/bin/qemu-sparc32plus-static as binfmt interpreter for sparc32plus Setting /usr/bin/qemu-sparc64-static as binfmt interpreter for sparc64 Setting /usr/bin/qemu-ppc-static as binfmt interpreter for ppc Setting /usr/bin/qemu-ppc64-static as binfmt interpreter for ppc64 Setting /usr/bin/qemu-ppc64le-static as binfmt interpreter for ppc64le Setting /usr/bin/qemu-m68k-static as binfmt interpreter for m68k Setting /usr/bin/qemu-mips-static as binfmt interpreter for mips Setting /usr/bin/qemu-mipsel-static as binfmt interpreter for mipsel Setting /usr/bin/qemu-mipsn32-static as binfmt interpreter for mipsn32 Setting /usr/bin/qemu-mipsn32el-static as binfmt interpreter for mipsn32el Setting /usr/bin/qemu-mips64-static as binfmt interpreter for mips64 Setting /usr/bin/qemu-mips64el-static as binfmt interpreter for mips64el Setting /usr/bin/qemu-sh4-static as binfmt interpreter for sh4 Setting /usr/bin/qemu-sh4eb-static as binfmt interpreter for sh4eb Setting /usr/bin/qemu-s390x-static as binfmt interpreter for s390x Setting /usr/bin/qemu-aarch64-static as binfmt interpreter for aarch64 Setting /usr/bin/qemu-aarch64_be-static as binfmt interpreter for aarch64_be Setting /usr/bin/qemu-hppa-static as binfmt interpreter for hppa Setting /usr/bin/qemu-riscv32-static as binfmt interpreter for riscv32 Setting /usr/bin/qemu-riscv64-static as binfmt interpreter for riscv64 Setting /usr/bin/qemu-xtensa-static as binfmt interpreter for xtensa Setting /usr/bin/qemu-xtensaeb-static as binfmt interpreter for xtensaeb Setting /usr/bin/qemu-microblaze-static as binfmt interpreter for microblaze Setting /usr/bin/qemu-microblazeel-static as binfmt interpreter for microblazeel Setting /usr/bin/qemu-or1k-static as binfmt interpreter for or1k liumiaocn:~ liumiao$结果确认
然后再次使用同样命令即可发现可进入ARM格式的容器中,使用uname命令也可以确认到其体系结构为ARM格式(aarch64)
liumiaocn:~ liumiao$ docker run --rm -it arm64v8/alpine:3.12.1 sh liumiaocn:~ liumiao$ docker run --rm -it arm64v8/alpine:3.12.1 sh / # uname -m aarch64 / # date Wed Oct 28 11:42:38 UTC 2020 / #
可以看到此处为UTC的时间,主要用来跟后面CST的中国时区的时间进行对比
构建ARM镜像并确认liumiaocn:~ liumiao$ docker run --rm -it arm64v8/alpine:3.12.1 sh / # uname -m aarch64 / # date Wed Oct 28 11:42:38 UTC 2020 / #
- 构建ARM镜像 使用如下Dockerfile构建ARM镜像
liumiaocn:armimage liumiao$ cat Dockerfile FROM arm64v8/alpine:3.12.1 RUN set -x \ && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories \ && echo 'http://mirrors.aliyun.com/alpine/edge/testing' >> /etc/apk/repositories \ && apk update \ && addgroup -g 101 -S nginx \ && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \ && apk add --no-cache --allow-untrusted tzdata \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ && /bin/rm -rf /tmp/* /var/cache/apk/* liumiaocn:armimage liumiao$
使用docker build在x86机器上构建此ARM镜像
liumiaocn:armimage liumiao$ docker build -t myarmimage . Sending build context to Docker daemon 2.56kB Step 1/2 : FROM arm64v8/alpine:3.12.1 ---> 2e77e061c27f Step 2/2 : RUN set -x && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories && echo 'http://mirrors.aliyun.com/alpine/edge/testing' >> /etc/apk/repositories && apk update && addgroup -g 101 -S nginx && adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx && apk add --no-cache --allow-untrusted tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone && /bin/rm -rf /tmp/* /var/cache/apk/* ---> Running in ffb20ef332b9 + sed -i s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/ /etc/apk/repositories + echo http://mirrors.aliyun.com/alpine/edge/testing + apk update fetch http://mirrors.aliyun.com/alpine/v3.12/main/aarch64/APKINDEX.tar.gz fetch http://mirrors.aliyun.com/alpine/v3.12/community/aarch64/APKINDEX.tar.gz fetch http://mirrors.aliyun.com/alpine/edge/testing/aarch64/APKINDEX.tar.gz v3.12.1-8-ge053f6efb7 [http://mirrors.aliyun.com/alpine/v3.12/main] v3.12.1-5-g0954f48dc3 [http://mirrors.aliyun.com/alpine/v3.12/community] v20200917-2860-gaeb4459434 [http://mirrors.aliyun.com/alpine/edge/testing] OK: 16530 distinct packages available + addgroup -g 101 -S nginx + adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx + apk add --no-cache --allow-untrusted tzdata fetch http://mirrors.aliyun.com/alpine/v3.12/main/aarch64/APKINDEX.tar.gz fetch http://mirrors.aliyun.com/alpine/v3.12/community/aarch64/APKINDEX.tar.gz fetch http://mirrors.aliyun.com/alpine/edge/testing/aarch64/APKINDEX.tar.gz (1/1) Installing tzdata (2020c-r0) Executing busybox-1.31.1-r19.trigger OK: 9 MiB in 15 packages + ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + echo Asia/Shanghai + /bin/rm -rf '/tmp/*' /var/cache/apk/APKINDEX.3a1aa0e6.tar.gz /var/cache/apk/APKINDEX.792faddc.tar.gz /var/cache/apk/APKINDEX.f46ee61c.tar.gz Removing intermediate container ffb20ef332b9 ---> 181684f5ebfc Successfully built 181684f5ebfc Successfully tagged myarmimage:latest liumiaocn:armimage liumiao$
- 在x86机器上运行ARM格式的镜像并确认结果
liumiaocn:armimage liumiao$ docker images |grep myarmimage myarmimage latest 181684f5ebfc 9 seconds ago 6.12MB liumiaocn:armimage liumiao$ liumiaocn:armimage liumiao$ docker run --rm -it myarmimage sh / # uname -a Linux 2bcff8eaae37 4.9.184-linuxkit #1 SMP Tue Jul 2 22:58:16 UTC 2019 aarch64 Linux / # uname -m aarch64 / # date Wed Oct 28 19:46:04 CST 2020 / # exit liumiaocn:armimage liumiao$
可以看到此ARM镜像已经成功构建完成,并且运行起来之后新的容器中的时区已经按照Dockerfile中设定的那样改为中国时区CST不再是UTC,说明是可以正常运行的。