Docker构建失败的ARM映像

时间:2019-07-24 08:44:43

标签: linux docker travis-ci multiarch

我尝试在Travis-CI上为多种架构构建docker映像。对于amd64和i386来说,这很好用,但对ARM来说却失败了。

Dockerfile构建在{ARCH}/nextcloud:apache之上,而Dockerfile构建在php:7.3-apache-stretch之上,后者再次使用debian:stretch-slim。因此,所有图像都使用相同的堆栈,并且应该具有相似的反应。

.travis.yml

env:
  - TAG=i386     ARCH=i386
  - TAG=amd64    ARCH=amd64
  - TAG=armhf    ARCH=arm32v7
  - TAG=aarch64  ARCH=arm64v8

before_script:
  - docker run --rm --privileged multiarch/qemu-user-static:register --reset

script:
  - docker build --pull --build-arg ARCH=$ARCH -t escoand/nextcloud:$TAG nextcloud

Dockerfile

ARG ARCH

FROM ${ARCH}/nextcloud:apache

RUN apt-get update && apt-get install -y supervisor && \
    rm -rf /var/lib/apt/lists/* && \
    mkdir /var/log/supervisord /var/run/supervisord

如前所述,i386和amd64的构建可以正常工作。使用第一个RUN命令,ARM构建已经失败:

standard_init_linux.go:185: exec user process caused "no such file or directory"
The command '/bin/sh -c apt-get update && apt-get install -y supervisor &&     rm -rf /var/lib/apt/lists/* &&     mkdir /var/log/supervisord /var/run/supervisord' returned a non-zero code: 1

https://travis-ci.org/escoand/dockerfiles/jobs/562967055

对我来说,这听起来像是/bin/sh的问题,但不知道如何处理。

1 个答案:

答案 0 :(得分:1)

首先,让我们了解一下,您尝试使用以下技巧来准确地做到

before_script:
  - docker run --rm --privileged multiarch/qemu-user-static:register --reset

当您要求Linux内核运行某些可执行文件时,它需要知道如何加载此特定文件以及该文件是否与当前计算机兼容。默认情况下,为arm64v8编译的ELF二进制文件被运行在amd64硬件上的内核拒绝。

但是,内核的binfmt_misc功能允许您告诉它如何处理通常无法自行处理的可执行文件-包括内核不知道二进制格式或认为二进制格式的情况与当前计算机不兼容。

从图像multiarch/qemu-user-static:register开始的容器做什么?它为为替代体系结构构建的ELF二进制文件注册新的处理程序,例如:

$ cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64-static
flags: 
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff

注册该处理程序后,内核知道如果它面对以magic字段中指定的魔术字节开头的二进制文件(还考虑了mask),则必须运行{ {1}}二进制文件(解释器),并让它负责加载和运行请求的二进制文件。

您的问题是:/usr/bin/qemu-aarch64-static解释器在哪里,它知道如何在/usr/bin/qemu-aarch64-static上运行aarch64二进制文件? 没有人,因为您使用的基本图像不包含该图像(我手动拉出并自省了amd64图像以确认这一点)!

根据arm64v8/nextcloud:apache的联机帮助页,当内核无法加载解释器时,它将返回“ ENOENT”(无此类文件或目录)错误:

execve(2)

因此,这就是发生的情况:构建映像并指定为ARM机器构建的基础映像。在第一个ERRORS <...> ENOENT The file pathname or a script or ELF interpreter does not exist, or a shared library needed for the file or interpreter cannot be found. 上,内核尝试从映像执行RUN文件,找到这种二进制文件的QEMU处理程序,然后寻找解释器,找不到它并失败,因此,“ 没有这样的文件或目录”错误。

要解决此问题,您必须使用已安装QEMU(因此内部有/bin/sh)的基础映像,这将允许您执行/usr/bin/qemu-aarch64-static s。