Сборка Docker контейнеров для ARM архитектуры используя Buildx

Сборка Docker контейнеров тема достаточно популярная и известная. Сборка для платформ x86 не представляет никаких проблем, все работает из коробки. Но как собрать Docker образ для ARM32 и ARM64 архитектуры? Если взять плату Banana Pi BPI-M64 с 64-разрядным ARM процессором, то на ней можно собрать образ для архитектуры ARM64, ARMv8, aarch64. Но для этого необходимо задействовать плату, и скорость сборки будет весьма низкая. Для сборки контейнеров помимо привычных инструментов, есть инструмент Buildx — позволяющий собирать образы для различных архитектур на x86 процессоре. В публикации будет детальный разбор, как собирать Docker образы для ARM процессоров и загружать их в публичный Docker Hub.

Оглавление

  1. Постановка задачи
  2. Buildx
  3. Установка Buildx
  4. Сборка с помощью Buildx
  5. Загрузка образа в Docker Hub
  6. Литература

Постановка задачи

Собрать Docker образ на базе Linux Alpine с ssh-сервером для архитектуры ARM64 и загрузить его в публичных Docker Hub. Сборка должна выполняться на x86 процессоре. Сборка Docker образа будет выполняться в Ubuntu 20.04.2 LTS, Docker version 20.10.6, build 370c289.

Buildx

Buildx — инструмент командой строки позволяющий собирать Docker контейнеры для архитектур: x86, ARM, и PowerPC. Для работы требуется Docker не ниже версии 19.03. При использование с бесплатной редакцией Docker CE, необходимо включить Buildx как экспериментальную функцию. Это можно сделать двумя способами:

  • Добавить использование экспериментальной функции Buildx в конфигурационный файл  ~/.docker/config.json . Добавляемая строка: experimental»: «enabled»;
  • Каждый раз перед сборкой Docker образа задавать переменную окружения  DOCKER_CLI_EXPERIMENTAL=enabled .

Установка Docker CE для Ubuntu x86 — Install Docker Engine on Ubuntu.

Установка Buildx

Шаг 1 — Включение экспериментальной функции

Каждый раз в терминальной сессии для включения экспериментальной функции выполнять команду:

$ export DOCKER_CLI_EXPERIMENTAL=enabled

Не очень удобно. Поэтому добавим эту команду в скрипт автозапуска:  $HOME/.bashrc . Для этого необходимо выполнить следующую команду, которая добавит переменную окружения в конец файла:

$ printf "\nexport DOCKER_CLI_EXPERIMENTAL=enabled" >> ~/.bashrc

Обратите внимание на символ «>>». Если будет одна стрелка «>», то вы затрете все содержимое файла.

Дополнительно, необходимо добавить еще одну переменную окружения  DOCKER_BUILDKIT=1 :

$ printf "\nexport DOCKER_BUILDKIT=1" >> ~/.bashrc

После этого необходимо завершить текущую терминальную сессию, и снова войти в систему. После входа в систему для проверки необходимо выполнить команду отображение переменой окружения. Ход выполнения:

root@ubuntuvm:~# echo $DOCKER_CLI_EXPERIMENTAL
enabled

Шаг 2 — Загрузка утилиты buildx

В консоль для загрузки образа сборки buildx, выполнить следующие команды:

$ docker build --platform=local -o . git://github.com/docker/buildx
$ mkdir -p ~/.docker/cli-plugins
$ mv buildx ~/.docker/cli-plugins/docker-buildx

Для проверки работы buildx выполнить команду:

$ docker buildx --help

Ход выполнения:

root@ubuntuvm:~# docker buildx --help

Usage:  docker buildx [OPTIONS] COMMAND

Build with BuildKit

Options:
      --builder string   Override the configured builder instance

Management Commands:
  imagetools  Commands to work on images in registry

Commands:
  bake        Build from a file
  build       Start a build
  create      Create a new builder instance
  du          Disk usage
  inspect     Inspect current builder instance
  ls          List builder instances
  prune       Remove build cache
  rm          Remove a builder instance
  stop        Stop builder instance
  use         Set the current builder instance
  version     Show buildx version information

Run 'docker buildx COMMAND --help' for more information on a command.
root@ubuntuvm:~#

Шаг 3 — Загрузка контейнера qemu

Необходимо загрузить последний образ контейнера docker/binfmt. Для этого необходимо в закладке Tags выбрать самый последний образ. На 07.05.2021 последний образ —  a7996909642ee92942dcd6cff44b9b95f08dad64.

Контейнеры docker/binfmt
docker buildx

И выполнить команду:

$ sudo docker run --rm --privileged docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64

где, docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64 — метка a7996909… заменить на последний вариант. После выполнения данной команды произойдет загрузка и запуск контейнера, который установит обработчик qemu.

Этот шаг необходимо выполнять каждый раз после перезагрузки ОС!

Для проверки регистрации обработчика qemu, выполнить команду  cat /proc/sys/fs/binfmt_misc/qemu-aarch64 . После выполнения команды должна появиться надпись: enabled. Ход выполнения команды:

Status: Downloaded newer image for docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64
root@ubuntuvm:~# cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64
flags: OCF
offset 0
magic 7f454c460201010000000000000000000200b7
mask ffffffffffffff00fffffffffffffffffeffff
root@ubuntuvm:~#

Шаг 4 — Создание инстанса сборки

Необходимо создать инстанс сборки, зададим название — mybuilder. Для этого выполним команды:

$ docker buildx create --name mybuilder
$ docker buildx use mybuilder
$ docker buildx inspect --bootstrap

Ход выполнения:

root@ubuntuvm:~# docker buildx create --name mybuilder
mybuilder
root@ubuntuvm:~# docker buildx use mybuilder
root@ubuntuvm:~# docker buildx inspect --bootstrap
[+] Building 39.0s (1/1) FINISHED
 => [internal] booting buildkit                                                                                             39.0s
 => => pulling image moby/buildkit:buildx-stable-1                                                                          37.6s
 => => creating container buildx_buildkit_mybuilder0                                                                         1.3s
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Из результата видим, что инстанс сборки mybuilder, будет собирать контейнеры для архитектур: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6. Из этого перечня для нас представляет интерес linux/arm64 — для ARM64, и linux/arm/v7 — для ARM32.

Сборка с помощью Buildx

Шаг 1 — Создание копии репозитория Alpine с ssh-сервером для сборки

Репозиторий devdotnetorg/docker-alpine-ssh содержит файл Dockerfile.alpine, который предназначен для сборки под архитектуру ARM64, и так же под другие архитектуры. Выполним клонирование репозитория:

$ apt-get update
$ apt-get install -y git
$ git clone https://github.com/devdotnetorg/docker-alpine-ssh.git

После выполнения команд появится папка  /docker-softethervpn-alpine/  с проектом.

Шаг 2 — Сборка контейнера для архитектуры ARM64

Для сборки контейнера необходимо в папке, где располагается файл Dockerfile.alpine выполнить команду:

cd docker-alpine-ssh
docker buildx build --platform linux/arm64 -f Dockerfile.alpine -t devdotnetorg/alpine-ssh:aarch64 . --load

Где параметры:

  • —platform linux/arm64 — сборка для платформы linux/arm64;
  • -f Dockerfile.alpine — файл Dockerfile для сборки контейнера;
  • -t devdotnetorg/alpine-ssh:aarch64 — название образа devdotnetorg/alpine-ssh, тег образа — aarch64;
  • —load — загрузка образа в локальный репозиторий образов Docker.

Ход выполнения команды:

root@ubuntuvm:~/docker-alpine-ssh# docker buildx build --platform linux/arm64 -f Dockerfile.alpine -t devdotnetorg/alpine-ssh:aarch64 . --load
[+] Building 38.6s (10/10) FINISHED
 => [internal] load build definition from Dockerfile.alpine                                                                  0.0s
 => => transferring dockerfile: 1.15kB                                                                                       0.0s
 => [internal] load .dockerignore                                                                                            0.0s
 => => transferring context: 2B                                                                                              0.0s
 => [internal] load metadata for docker.io/library/alpine:3.13                                                               3.4s
 => [auth] library/alpine:pull token for registry-1.docker.io                                                                0.0s
 => [internal] load build context                                                                                            0.0s
 => => transferring context: 926B                                                                                            0.0s
 => [1/3] FROM docker.io/library/alpine:3.13@sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f         2.2s
 => => resolve docker.io/library/alpine:3.13@sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f         0.0s
 => => sha256:595b0fe564bb9444ebfe78288079a01ee6d7f666544028d5e96ba610f909ee43 2.71MB / 2.71MB                               2.0s
 => => extracting sha256:595b0fe564bb9444ebfe78288079a01ee6d7f666544028d5e96ba610f909ee43                                    0.2s
 => [2/3] COPY copyables /                                                                                                   0.0s
 => [3/3] RUN apk update  && apk add --no-cache --upgrade sudo bash sed mc htop openssh-server  && apk add --no-cache --up  28.6s
 => exporting to oci image format                                                                                            4.2s
 => => exporting layers                                                                                                      2.3s
 => => exporting manifest sha256:e8f334c619e747e49f1c698bc422a78fdff6c5924a5df26a0179937e0b68896b                            0.0s
 => => exporting config sha256:764932983a8ee71e654c051def74839d8af5f5a32bfd9154f0b8ce0bf66f50de                              0.0s
 => => sending tarball                                                                                                       1.9s
 => importing to docker                                                                                                      1.1s
root@ubuntuvm:~/docker-alpine-ssh#

После выполнения команды, образ можно найти в локальном репозитории Docker. Для отображения локальных образов Docker выполнить команду:

$ docker image ls

Ход выполнения:

root@ubuntuvm:~/docker-alpine-ssh# docker image ls
REPOSITORY                TAG                                        IMAGE ID       CREATED          SIZE
devdotnetorg/alpine-ssh   aarch64                                    764932983a8e   12 minutes ago   45.3MB
moby/buildkit             buildx-stable-1                            cf14c5e88c0e   7 days ago       123MB
portainer/portainer       latest                                     62771b0b9b09   9 months ago     79.1MB
docker/binfmt             a7996909642ee92942dcd6cff44b9b95f08dad64   b5fc739b191d   15 months ago    20.7MB

Среди списка образов есть devdotnetorg/alpine-ssh, предназначенный для ARM64 архитектуры. Каждый раз при сборки образов, buildx кэширует слои. Через некоторое время кэш может занимать значительное пространство на диске. Для очистки кэша используется команда:

$ docker buildx prune

Загрузка образа в Docker Hub

Шаг 1 — Получение токена

Для аутентификации в Docker Hub необходимо получить токен. Для этого необходимо перейти на страницу hub.docker.com, войти под своей учетной записью. Перейти в раздел Account Settings. Выбрать раздел Security и нажать на кнопку New Access Token, и получить новый токен. Более подробное руководство Managing access tokens.

Шаг 2 — Авторизация Docker ID

Затем выполнить команду:

docker login --username [DOCKER_ID]

Где DOCKER_ID — идентификатор вашей учетной записи в Docker Hub. Ход выполнения команды:

root@ubuntuvm:~# docker login --username [DOCKER_ID]
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Шаг 2 — Сборка и загрузка образа в Docker Hub

Необходимо выполнить команду сборки, параметр —load заменить на —push. Команда:

cd docker-alpine-ssh
docker buildx build --platform linux/arm64 -f Dockerfile.alpine -t devdotnetorg/alpine-ssh:aarch64 . --push

Ход выполнения команды:

root@ubuntuvm:~/docker-alpine-ssh# docker buildx build --platform linux/arm64 -f Dockerfile.alpine -t devdotnetorg/alpine-ssh:aarch64 . --push
[+] Building 48.8s (10/10) FINISHED
 => [internal] load build definition from Dockerfile.alpine                                                                  0.0s
 => => transferring dockerfile: 1.15kB                                                                                       0.0s
 => [internal] load .dockerignore                                                                                            0.0s
 => => transferring context: 2B                                                                                              0.0s
 => [internal] load metadata for docker.io/library/alpine:3.13                                                               3.1s
 => [auth] library/alpine:pull token for registry-1.docker.io                                                                0.0s
 => [internal] load build context                                                                                            0.0s
 => => transferring context: 926B                                                                                            0.0s
 => [1/3] FROM docker.io/library/alpine:3.13@sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f         3.0s
 => => resolve docker.io/library/alpine:3.13@sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f         0.0s
 => => sha256:595b0fe564bb9444ebfe78288079a01ee6d7f666544028d5e96ba610f909ee43 2.71MB / 2.71MB                               2.8s
 => => extracting sha256:595b0fe564bb9444ebfe78288079a01ee6d7f666544028d5e96ba610f909ee43                                    0.1s
 => [2/3] COPY copyables /                                                                                                   0.0s
 => [3/3] RUN apk update  && apk add --no-cache --upgrade sudo bash sed mc htop openssh-server  && apk add --no-cache --up  24.7s
 => exporting to image                                                                                                      17.9s
 => => exporting layers                                                                                                      2.3s
 => => exporting manifest sha256:e6e259f411e20ee30f7b9db1d566fdc7501b39d0af64821d66c41e10a69a8693                            0.0s
 => => exporting config sha256:45848e4f49e872cfa7b1e504066f1d49fdeab011c51c3d60e38161956c229f07                              0.0s
 => => pushing layers                                                                                                       14.9s
 => => pushing manifest for docker.io/devdotnetorg/alpine-ssh:aarch64                                                        0.6s
 => [auth] devdotnetorg/alpine-ssh:pull,push token for registry-1.docker.io                                                  0.0s
root@ubuntuvm:~/docker-alpine-ssh#

Образ залит devdotnetorg/alpine-ssh, задача выполнена.

Загруженный образ devdotnetorg/alpine-ssh
docker buildx

На одноплатном компьютере с процессором ARM64, например Banana Pi BPI-M64, для запуска контейнера выполнить команду (до выполнение команды должен быть установлен Docker — Установка Docker для ARM и 64-bit ARM (Armbian, Linux)):

$ docker run -d --name alpine-sshd -p 222:22 -e PASSWORD=123456 -v alpine-data:/data devdotnetorg/alpine-ssh:aarch64

Для сборки под другие архитектуры необходимо выполнить команду:

$ docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -f Dockerfile.alpine -t devdotnetorg/alpine-ssh:latest . --push

Литература

  1. buildx — GitHub docker/buildx
  2. Getting started with Docker for Arm on Linux — TIM TSAI Docker blog
  3. Building Multi-Architecture Docker Images With Buildx — Artur Klauser medium.com
  4. Managing access tokens — Docker docs
  5. Getting started with Docker for Arm using buildx on Linux — ARM Community
  6. Building Multi-Architecture Docker Images on ARM 64-bit AWS Graviton2 Processors — SCOTT ROSSILLO smartling

Вам также может понравиться

About the Author: Anton

Programistik