简体   繁体   English

ARM 映像的 Docker 构建失败

[英]Docker build fails for ARM images

I try to build a docker image for multiple architectures on Travis-CI.我尝试在 Travis-CI 上为多个架构构建一个 docker 镜像。 This is working quite well for amd64 and i386 but fails for ARM.这对于 amd64 和 i386 非常有效,但对于 ARM 却失败了。

The Dockerfile build on top of {ARCH}/nextcloud:apache which is build on top of php:7.3-apache-stretch which again uses debian:stretch-slim . Dockerfile 构建在{ARCH}/nextcloud:apache之上,后者构建在php:7.3-apache-stretch之上,它再次使用debian:stretch-slim So all the images use the same stack and should react similar.所以所有的图像都使用相同的堆栈并且应该做出相似的反应。

.travis.yml .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

As mentioned the build for i386 and amd64 works without problems.如前所述,i386 和 amd64 的构建没有问题。 The ARM builds fail already with the first RUN command: ARM 构建已通过第一个 RUN 命令失败:

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 https://travis-ci.org/escoand/dockerfiles/jobs/562967055

For me this sounds like the /bin/sh is the problem but don't know how to handle this.对我来说,这听起来像是/bin/sh是问题,但不知道如何处理。

First of all, let's understand, what exactly you try to do by employing the following trick:首先,让我们了解一下,通过使用以下技巧,您到底要做什么:

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

When you ask the Linux kernel to run some executable file, it needs to know, how to load this specific file, and whether this file is compatible with current machine, or not.当你要求 Linux 内核运行某个可执行文件时,它需要知道如何加载这个特定文件,以及这个文件是否与当前机器兼容。 By default, the ELF binary compiled for, say, arm64v8 is rejected by the kernel, running on amd64 hardware.默认情况下,为arm64v8编译的 ELF 二进制文件被内核拒绝,在amd64硬件上运行。

However, the binfmt_misc feature of the kernel allows you to tell it, how to handle the executables it cannot usually handle on its own - this includes the cases when the kernel does not know the binary format or considers it incompatible with current machine.但是,内核的binfmt_misc功能允许您告诉它如何处理它通常无法自行处理的可执行文件 - 这包括内核不知道二进制格式或认为它与当前机器不兼容的情况。

What the container started from the image multiarch/qemu-user-static:register does?从镜像multiarch/qemu-user-static:register开始的容器做了什么? It registers new handlers for ELF binaries built for alternative architectures, for example:它为为替代架构构建的 ELF 二进制文件注册新的处理程序,例如:

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

When this handler is registered, kernel knows that if it faces the binary starting with the magic bytes, specified in the magic field (also taking into account the mask ), it has to run /usr/bin/qemu-aarch64-static binary (the interpreter) and let it take care about the loading and running the requested binary.当这个处理程序被注册时,内核知道如果它面对以magic字段中指定的魔法字节开头的二进制文件(也考虑到mask ),它必须运行/usr/bin/qemu-aarch64-static二进制文件(解释器)并让它负责加载和运行请求的二进制文件。

The problem in your question is: where is the /usr/bin/qemu-aarch64-static interpreter, which knows how to run aarch64 binaries on amd64 ?您的问题中的问题是: /usr/bin/qemu-aarch64-static解释器在aarch64 ,它知道如何在amd64上运行aarch64二进制文件? There is no one , as the base image you use does not include it (I pulled and introspected the arm64v8/nextcloud:apache image manually to confirm this)!没有,因为您使用的基本映像不包含它(我手动拉取并内省了arm64v8/nextcloud:apache映像以确认这一点)!

As per manpage for execve(2) , when the kernel can not load the interpreter, it returns the "ENOENT" ( no such file or directory ) error:根据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.

So, this is what happens: you build the image and specify the base image, built for ARM machines.所以,这就是发生的事情:您构建映像并指定为 ARM 机器构建的基本映像。 On the first RUN , the kernel tries to execute /bin/sh file from the image, finds the QEMU handler for this type of binaries, then looks for the interpreter, does not find it and fails, hence the " no such file or directory " error.在第一次RUN ,内核尝试从映像执行/bin/sh文件,找到此类二进制文件的 QEMU 处理程序,然后查找解释器,但未找到并失败,因此“没有此类文件或目录“ 错误。

To resolve this, you have to use the base image which has QEMU installed (and, thus, has /usr/bin/qemu-aarch64-static inside), which would allow you executing RUN s.要解决这个问题,您必须使用安装了 QEMU 的基本映像(因此,里面有/usr/bin/qemu-aarch64-static ),这将允许您执行RUN

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM