Мультиплатформенные образы

Образы Docker могут поддерживать несколько платформ, что означает, что один образ может содержать варианты для разных архитектур, а иногда и для разных операционных систем, например, Windows.

При запуске образа с поддержкой нескольких платформ docker автоматически выбирает образ, соответствующий вашей ОС и архитектуре.

Большинство официальных образов Docker на Docker Hub содержат разнообразие архитектур. Например, образ busybox поддерживает amd64, arm32v5, arm32v6, arm32v7, arm64v8, i386, ppc64le и s390x. При запуске этого образа на компьютере x86_64/amd64 извлекается и запускается опция amd64.

Создание многоплатформенных образов

Сейчас Docker как никогда упрощает разработку контейнеров на серверах и устройствах Arm и для них. Используя стандартные инструменты и процессы Docker, вы можете приступить к созданию, продвижению, извлечению и запуску образов на различных вычислительных архитектурах. В большинстве случаев вам не придется вносить какие-либо изменения в файлы Docker или исходный код, чтобы начать сборку для Arm.

BuildKit с Buildx предназначен для сборки для нескольких платформ, а не только для архитектуры и операционной системы, на которой работает пользователь, вызывающий сборку.

Когда вы вызываете сборку, вы можете установить флаг --platform, чтобы указывает целевую платформу для вывода сборки (например, linux/amd64, linux/arm64 или darwin/amd64).

Когда текущий экземпляр сборщика поддерживается драйвером docker-container, вы можете указывает несколько платформ вместе. В этом случае создаётся список манифестов, содержащий образы для всех указанных архитектур. Когда вы используете данный образ в запуск Docker или служба докеров, Docker выбирает правильный образ на основе платформы узла.

Вы можете создавать многоплатформенные образы, используя три различные стратегии, которые поддерживаются Buildx и Dockerfiles:

  1. Использование поддержки эмуляции QEMU в ядре

  2. Построение на нескольких собственных узлах с использованием одного экземпляра построителя

  3. Использование этапа в Dockerfile для кросс-компиляции на разных архитектурах

QEMU — самый простой способ начать работу, если ваш узел уже поддерживает его (например. если вы используете Docker Desktop). Он не требует изменений в вашем Dockerfile, а BuildKit автоматически определяет доступные вторичные архитектуры. Когда BuildKit необходимо выполнить бинарник для другой архитектуры, он автоматически загружает его через бинарник, зарегистрированный в обработчике binfmt_misc.

Чтобы двоичные файлы QEMU, зарегистрированные с помощью binfmt_misc в операционной системе хоста, могли прозрачно работать внутри контейнеров, они должны быть статически скомпилированы и зарегистрированы с флагом fix_binary. Для этого требуется ядро >= 4.8 и поддержка binfmt >= 2.1.7. Вы можете проверяет правильность регистрации, проверив, есть ли F среди флагов в /proc/sys/fs/binfmt_misc/qemu-*. Хотя Docker Desktop поставляется с предварительно настроенной поддержкой binfmt_misc для дополнительных платформ, для других установок его, вероятно, необходимо установить с использованием образа tonistiigi/binfmt.

$ docker run --privileged --rm tonistiigi/binfmt --install all

Использование нескольких собственных узлов обеспечивает лучшую поддержку более сложных случаев, которые не обрабатываются QEMU, и обычно имеет лучшую производительность. Вы можете добавить дополнительные узлы к экземпляру сборщика с помощью флага --append.

Предположим, что контексты node-amd64 и node-arm64 существуют в docker context ls;

$ docker buildx create --use --name mybuild node-amd64
mybuild
$ docker buildx create --append --name mybuild node-arm64
$ docker buildx build --platform linux/amd64,linux/arm64 .

Наконец, в зависимости от вашего проекта, используемый вами язык может иметь хорошую поддержку кросс-компиляции. В этом случае многоэтапные сборки в Dockerfiles можно эффективно использовать для сборки двоичных файлов для платформы, указанной с помощью --platform, используя родную архитектуру узла сборки. Список аргументов сборки, таких как BUILDPLATFORM и TARGETPLATFORM, автоматически доступен внутри вашего Dockerfile и может быть использован процессами, запущенными в рамках вашей сборки.

# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:alpine AS build
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
FROM alpine
COPY --from=build /log /log

Начало работы

Выполните docker buildx ls command, чтобы перечислить существующих строителей:

$ docker buildx ls
NAME/NODE  DRIVER/ENDPOINT  STATUS   BUILDKIT PLATFORMS
default *  docker
  default  default          running  20.10.17 linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6

Здесь отображается встроенный драйвер по умолчанию, который использует серверные компоненты BuildKit, встроенные непосредственно в движок docker, также известный как драйвер Docker.

Создаёт новый билдер с помощью драйвер docker-контейнера, который даст вам доступ к более сложным функциям, таким как многоплатформенные сборки и более продвинутые экспортеры кэша, которые в настоящее время не поддерживаются в стандартном драйвере docker:

$ docker buildx create --name mybuilder --driver docker-container --bootstrap
mybuilder

Переключитесь на нового строителя:

$ docker buildx use mybuilder

Примечание

В качестве альтернативы выполняет docker buildx create --name mybuilder --driver docker-container --bootstrap --use, чтобы создать новый конструктор и переключиться на него с помощью одной команды.

И осмотрите его:

$ docker buildx inspect
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Buildkit:  v0.10.4
Platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

Теперь, снова перечислив существующих строителей, мы видим, что наш новый строитель зарегистрирован:

$ docker buildx ls
NAME/NODE     DRIVER/ENDPOINT              STATUS   BUILDKIT PLATFORMS
mybuilder     docker-container
  mybuilder0  unix:///var/run/docker.sock  running  v0.10.4  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default *     docker
  default     default                      running  20.10.17 linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6

Пример

Протестируйте рабочий процесс, чтобы убедиться, что вы можете создавать, отправлять и запускать многоплатформенные образы. Создаёт простой пример Dockerfile, постройте несколько вариантов образов и отправить их в Docker Hub.

В следующем примере используется один Dockerfile для создания образа Alpine с установленным cURL для нескольких архитектур:

# syntax=docker/dockerfile:1
FROM alpine:3.16
RUN apk add curl

Собирает Dockerfile с помощью buildx, передав список архитектур для сборки:

$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t <username>/<image>:latest --push .
...
#16 exporting to image
#16 exporting layers
#16 exporting layers 0.5s done
#16 exporting manifest sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c 0.0s done
#16 exporting config sha256:a26f329a501da9e07dd9cffd9623e49229c3bb67939775f936a0eb3059a3d045 0.0s done
#16 exporting manifest sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf 0.0s done
#16 exporting config sha256:9fcc6de03066ac1482b830d5dd7395da781bb69fe8f9873e7f9b456d29a9517c 0.0s done
#16 exporting manifest sha256:29666fb23261b1f77ca284b69f9212d69fe5b517392dbdd4870391b7defcc116 0.0s done
#16 exporting config sha256:92cbd688027227473d76e705c32f2abc18569c5cfabd00addd2071e91473b2e4 0.0s done
#16 exporting manifest list sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48 0.0s done
#16 ...

#17 [auth] <username>/<image>:pull,push token for registry-1.docker.io
#17 DONE 0.0s

#16 exporting to image
#16 pushing layers
#16 pushing layers 3.6s done
#16 pushing manifest for docker.io/<username>/<image>:latest@sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48
#16 pushing manifest for docker.io/<username>/<image>:latest@sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48 1.4s done
#16 DONE 5.6s

Примечание

  • <username> должен быть действительным Docker ID, а <image> — действительным репозиторием на Docker Hub.

  • Флаг --platform сообщает buildx о необходимости создания образов Linux для 64-битной архитектуры AMD, 64-битной архитектуры Arm и архитектуры Armv7.

  • Флаг --push создаёт многоархивный манифест и размещает все образы в Docker Hub.

Осмотрите образ с помощью команды docker buildx imagetool:

$ docker buildx imagetools inspect <username>/<image>:latest
Name:      docker.io/<username>/<image>:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48

Manifests:
  Name:      docker.io/<username>/<image>:latest@sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      docker.io/<username>/<image>:latest@sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      docker.io/<username>/<image>:latest@sha256:29666fb23261b1f77ca284b69f9212d69fe5b517392dbdd4870391b7defcc116
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7

Образ теперь доступен на Docker Hub с тегом <username>/<image>:latest. Вы можете использовать данный образ для запуска контейнера на ноутбуках Intel, инстансах Amazon EC2 Graviton, Raspberry Pis и на других архитектурах. Docker извлекает правильный образ для текущей архитектуры, поэтому на Raspberry PI запускается 32-битная версия Arm, а на инстансах EC2 Graviton — 64-битная Arm.

Дайджест идентифицирует полностью квалифицированный опция образа. На Docker Desktop можно также запускать образы, предназначенные для другой архитектуры. Например, при запуске следующего образа на macOS:

$ docker run --rm docker.io/<username>/<image>:latest@sha256:2b77acdfea5dc5baa489ffab2a0b4a387666d1d526490e31845eb64e3e73ed20

uname -m aarch64
$ docker run --rm docker.io/<username>/<image>:latest@sha256:723c22f366ae44e419d12706453a544ae92711ae52f510e226f6467d8228d191 uname -m
armv7l

В приведённом выше примере uname -m возвращает aarch64 и armv7l, как и ожидалось, даже при выполнении команд на собственной машине разработчика macOS или Windows.

Поддержка на Docker Desktop

Docker Desktop обеспечивает поддержку мультиархитектуры binfmt_misc, что означает, что вы можете запускать контейнеры для различных архитектур Linux, таких как arm, mips, ppc64le и даже s390x.

Это не требует какой-либо специальной настройки в самом контейнере, поскольку он использует qemu-static из Docker for Mac VM. Из-за этого вы можете запускать контейнер ARM, например варианты arm32v7 или ppc64le образа busybox.