
Я пытаюсь создать переносимый кросс-архитектурный Docker-контейнер с использованием QEMU. Однако в зависимости от хост-системы и программ, установленных на хосте, контейнер ведет себя по-разному.
Запускаем контейнер на Windows, эмуляция работает отлично. Также отлично работает на Ubuntu 16.04когдаqemu-user-static установлен. Но если его нет, то эмуляция прекратится.
Эмуляция работает до тех пор, пока включена поддержка binfmt в ядре хоста (для Docker на Linux) или в ядре виртуальной машины (для Docker на Windows) И необходимые двоичные файлы доступны в файловой системе контейнера.
Моя цель — сделать контейнер переносимым и запускаемым без необходимости регистрации qemu как интерпретатора в ядре, поскольку любые изменения в самой Host-OS или ее ядре запрещены нашим заказчиком. Но в настоящее время это результат запуска контейнера:
$ sudo docker run -ti qemu:xenial_arm64
qemu-aarch64-static: /usr/bin/groups: cannot execute binary file: Exec format error
/usr/bin/lesspipe: line 28: /usr/bin/basename: cannot execute binary file: Exec format error
/usr/bin/lesspipe: line 282: /usr/bin/dirname: cannot execute binary file: Exec format error
/usr/bin/lesspipe: line 295: [: =: unary operator expected
qemu-aarch64-static: /usr/bin/dircolors: cannot execute binary file: Exec format error
root@41f2795e2569:/# uname -m
qemu-aarch64-static: /bin/uname: cannot execute binary file: Exec format error
Однако если я установлю qemu-user-static (при его установке qemu также будет включен в binfmt_misc):
$ sudo apt-get -yqq install qemu-user-static
Selecting previously unselected package qemu-user-static.
(Reading database ... 245713 files and directories currently installed.)
Preparing to unpack .../qemu-user-static_1%3a2.5+dfsg-5ubuntu10.42_amd64.deb ...
Unpacking qemu-user-static (1:2.5+dfsg-5ubuntu10.42) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up qemu-user-static (1:2.5+dfsg-5ubuntu10.42) ...
$ sudo docker run -ti qemu:xenial_arm64
root@7903b45a3c1e:/# uname -m
aarch64
Мое объяснение этому таково:
- qemu-aarch64-static начинает эмулировать /bin/bash
- /bin/bash использует execve(..) для вызова некоторых других исполняемых файлов
- Linux-хост:
- если binfmt_misc включен либо хостом, либо контейнером (в Linux хост и гостевая система Docker совместно используют ядро), qemu будет динамически назначен в качестве интерпретатора для исполняемых файлов arm64
- в противном случае выполнение завершится ошибкой и будет выдано сообщение «Ошибка формата Exec».
- Хост Windows:
- Поскольку Windows и Linux имеют разные ядра, гостевые системы Linux не могут быть запущены путем передачи системных вызовов ядру хоста.
- поэтому в Windows контейнеры работают внутри виртуальной машины с отдельным ядром; это ядро затем используется совместно с контейнерами
- если qemu-user-static с binfmt-support был однажды установлен и включен в любом контейнере, он все равно будет выполнять свою задачу и динамически назначать qemu в качестве интерпретатора для исполняемых файлов другой архитектуры
Выполнение в Linux и Windows дает эквивалентные результаты.
Возможным решением будет запуск контейнера с использованием флага --privileged. Тогда я смогу смонтировать binfmt_misc и тем самым зарегистрировать qemu-user-static как интерпретатор внутри контейнера. Но наш клиент запрещает использовать этот флаг.
Я уже опробовал описанный подход.здесьа также флаг -0 у qemu-user. Ни один из них не работает.
Dockerfile:
FROM scratch
ADD xenial-arm64-rootfs /
ADD qemu-aarch64-static /usr/bin/qemu-aarch64-static
RUN chmod +x /usr/bin/qemu-aarch64-static
ENTRYPOINT ["/usr/bin/qemu-aarch64-static", "-0", "/usr/bin/qemu-aarch64-static"]
CMD ["/bin/bash"]
qemu-aarch64-static берется из /usr/bin/qemu-aarch64-static (устанавливается с помощью qemu-user-static), xenial-arm64-rootfs создается с помощью:
qemu-debootstrap --arch=arm64 --components=main,universe,multiverse,restricted --variant=buildd --foreign xenial xenial-arm64-rootfs http://ports.ubuntu.com/ubuntu-ports/
Что я могу сделать, чтобы эмуляция продолжалась?