sh: write error: Invalid argument - Centos 7 qemu报错解决方案

QEMU作用

qemu是用于将不同架构的机器码指令转译为当前服务器架构的机器码指令,通常用于跨架构执行某些程序,或用于docker buildkit/podman/builah等跨架构编译构建镜像。
在linux上启用qemu只需要执行一个特权模式的docker容器,该容器会自动配置服务器内容。

理想情况

# 未开启前,运行异构镜像会报错
docker run --rm -it --platform linux/arm64 nginx:1.21.3-alpine uname -m
# standard_init_linux.go:219: exec user process caused: exec format error

# 开启qemu仿真
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

# 再次运行异构镜像,成功显示架构
docker run --rm -it --platform linux/arm64 nginx:1.21.3-alpine uname -m
# aarch64

现实很残酷

# 未开启前,运行异构镜像会报错
docker run --rm -it --platform linux/arm64 nginx:1.21.3-alpine uname -m
# standard_init_linux.go:219: exec user process caused: exec format error

# 尝试开启安装qemu,报错
[root@xxx nginx]# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
sh: write error: Invalid argument
Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha
Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm
sh: write error: Invalid argument
Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb
sh: write error: Invalid argument
sh: write error: Invalid argument
Setting /usr/bin/qemu-sparc-static as binfmt interpreter for sparc
Setting /usr/bin/qemu-sparc32plus-static as binfmt interpreter for sparc32plus
sh: write error: Invalid argument
Setting /usr/bin/qemu-sparc64-static as binfmt interpreter for sparc64
sh: write error: Invalid argument
sh: write error: Invalid argument

翻了一下issues: #100,发现有说是内核版本比较低,不支持-p yes参数(your kernel 3.10.0-1062.9.1.el7.x86_64 (= uname -r) is too old to use the command or the option -p yes.)

两种解决方案

  1. 升级内核
  • Install the latest unofficial mainline kernel
  • Select the newly installed kernel to be default in grub
  • Profit
  1. 手动挡实现-p yes功能
  • 第一种方式可以在构建跨架构镜像时,将qemu模块放到镜像里
# 先安装qemu,这回应该不会报错了
docker run --rm --privileged multiarch/qemu-user-static --reset

# 构建一个异构镜像
docker build --rm -t my-arm64-nginx:1.21.3-alpine -<<EOF
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
FROM nginx:1.21.3-alpine
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
EOF

# 运行该镜像,成功运行
docker run --rm -it --platform linux/arm64 my-arm64-nginx:1.21.3-alpine uname -m
# aarch64
  • 第二种方式也大同小异,就是执行容器的时候将qemu可执行文件挂载到容器
# 从qemu镜像中取qemu执行文件
docker run --rm --privileged multiarch/qemu-user-static:register --reset
docker create -it --name dummy multiarch/qemu-user-static:x86_64-aarch64 bash
docker cp dummy:/usr/bin/qemu-aarch64-static qemu-aarch64-static
docker rm -f dummy
# 将取出来的可执行文件挂载到nginx容器
docker run --rm -t -v $(pwd)/qemu-aarch64-static:/usr/bin/qemu-aarch64-static my-arm64-nginx:1.21.3-alpine uname -m
# aarch64

跨架构构建

思路是在构建过程中,如果有RUN指令,在指令前将qemu文件加进去。
以buildah为例,跟docker buildx应该没有差异。

# 声明Dockerfile
cat << EOF > Dockerfile
FROM multiarch/qemu-user-static:latest as qemu
FROM nginx:1.21.3-alpine
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
RUN echo "hello world" > /hello.txt

# 运行buildah 构建命令
buildah build --tls-verify=false --platform linux/arm64 --manifest my-arm64-nginx:1.21.3-alpine .
#[1/2] STEP 1/1: FROM multiarch/qemu-user-static:latest AS qemu
#Trying to pull multiarch/qemu-user-static:latest...
#Getting image source signatures
#...
#--> edbc833d569
#[Warning] one or more build args were not consumed: [TARGETARCH TARGETOS TARGETPLATFORM]
#edbc833d569598b9b6060679ea0da9bbab4eb756ff0f10fe340242a56123084

# 如果是docker buildx的话,应该是这条命令,没测过
docker buildx --platform linux/arm64 -t my-arm64-nginx:1.21.3-alpine .

总结

以上方法感觉都很麻烦...期望有更便捷的解决方案

posted @ 2022-09-30 16:14  小小记录本  阅读(1628)  评论(0编辑  收藏  举报