3

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

{ARCH}/nextcloud:apache构建在其之上的 Dockerfilephp: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问题所在,但不知道如何处理。

4

1 回答 1

8

首先,让我们了解一下您通过以下技巧尝试做什么:

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

当你要求 Linux 内核运行某个可执行文件时,它需要知道如何加载这个特定的文件,以及这个文件是否与当前机器兼容。默认情况下,编译的 ELF 二进制文件arm64v8被内核拒绝,在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),它必须运行/usr/bin/qemu-aarch64-static二进制文件(解释器)并让它负责加载和运行请求的二进制文件。

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

根据手册页execve(2),当内核无法加载解释器时,它会返回“ENOENT”(没有这样的文件或目录)错误:

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.

所以,这就是发生的事情:您构建映像并指定为 ARM 机器构建的基本映像。首先RUN,内核尝试/bin/sh从映像执行文件,找到此类二进制文件的 QEMU 处理程序,然后查找解释器,但未找到并失败,因此出现“没有这样的文件或目录”错误。

要解决此问题,您必须使用安装了 QEMU(因此也安装了 QEMU /usr/bin/qemu-aarch64-static)的基本映像,这将允许您执行RUNs.

于 2019-07-24T12:59:19.190 回答