За последние несколько лет потребность в мультиархитектурных образах контейнеров значительно возросла. Допустим, вы разрабатываете на локальной Linux или Windows машине с процессором amd64 и хотите опубликовать свою работу на AWS машинах с процессором Graviton2, или просто хотите поделиться своей работой с коллегами, которые используют Macbook с чипом M1, вам необходимо убедиться, что ваш образ работает на обеих архитектурах. Этот процесс значительно облегчился с появлением инструмента Docker Buildx.
Но что такое Buildx на самом деле? Согласно официальной документации Docker Buildx — это плагин CLI, который расширяет команду docker с полной поддержкой функций, предоставляемых набором инструментов для сборки Moby BuildKit. Он обеспечивает тот же пользовательский опыт, что и docker build
, со многими новыми возможностями, такими как создание экземпляров сборщика с масштабированием и одновременная сборка на нескольких узлах. Buildx также поддерживает новые возможности, которые пока недоступны для обычной сборки docker build
, такие как создание списков манифестов, распределенное кэширование и экспорт результатов сборки в тарбалы образов OCI.
В нашей демонстрации мы покажем, как настроить buildx на локальной машине и собрать простое приложение Node.js. Полный исходный код вы можете найти на этом репозитории GitHub.
Создание приложения Node.js
В демонстрационном приложении мы создали веб-сервер с помощью Node.js. Node.js предоставляет чрезвычайно простые HTTP API, поэтому пример очень прост для понимания даже для разработчиков, не владеющих javascript.
По сути, мы определяем порт, затем вызываем функцию createServer()
на модуле http и создаем ответ с кодом состояния 200 (OK), устанавливаем заголовок и выводим сообщение о том, на какой архитектуре работает программа. Архитектуру процессора мы получили через свойство arch
встроенной переменной process
. В конце мы просто запускаем сервер, прослушивающий соединения.
const http = require("http");
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end(`Hello from ${process.arch} architecture!`);
});
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Если вы хотите протестировать приложение локально, откройте терминал в рабочей директории и выполните команду node server.js
.
Для того чтобы упаковать приложение в виде контейнера, мы должны написать Dockerfile. Первое, что нам нужно сделать, это определить, из какого образа мы хотим собирать. Здесь мы будем использовать версию 16.17.0-alpine
официального образа node
, который доступен на Docker Hub. Сразу после базового образа мы создадим каталог для хранения кода приложения внутри образа.
FROM node:16.17.0-alpine
WORKDIR /usr/src/app
Чтобы поместить исходный код нашего приложения в образ Docker, мы воспользуемся простой командой copy, которая сохранит код приложения в рабочем каталоге.
COPY . .
Приложение прослушивает порт 3000, поэтому нам нужно открыть его и, наконец, запустить сервер.
EXPOSE 3000
CMD ["node", "server.js"]
Настройка Buildx и создание образа
Самый простой способ установки buildx
— это использование Docker Desktop, поскольку инструмент уже включен в приложение. Docker Desktop доступен для Windows, Linux и macOS, поэтому вы можете использовать его на любой платформе по вашему выбору.
Если вы не хотите использовать Docker Desktop, вы также можете загрузить последний бинарный файл со страницы релизов на GitHub, переименовать его в docker-buildx
(docker-buildx.exe
для Windows) и скопировать его в место назначения, соответствующее вашей ОС. Для Linux и macOS это $HOME/.docker/cli-plugins
, для Windows это %USERPROFILE%.dockercli-plugins
.
В приведенном ниже коде показана настройка для macOS:
ARCH=amd64 # change to 'arm64' if you have M1 chip
VERSION=v0.8.2
curl -LO https://github.com/docker/buildx/releases/download/${VERSION}/buildx-${VERSION}.darwin-${ARCH}
mkdir -p ~/.docker/cli-plugins
mv buildx-${VERSION}.darwin-${ARCH} ~/.docker/cli-plugins/docker-buildx
chmod +x ~/.docker/cli-plugins/docker-buildx
docker buildx version # verify installation
После установки buildx
нам нужно создать новый инстанс builder. Экземпляры Builder — это изолированные среды, в которых можно вызывать сборки.
docker buildx create --name builder
После создания нового экземпляра сборщика нам нужно переключиться на него с экземпляра по умолчанию:
docker buildx use builder
Теперь давайте посмотрим больше информации о нашем экземпляре билдера. Мы также передадим опцию --bootstrap
, чтобы убедиться, что билдер запущен, прежде чем проверять его.
docker buildx inspect --bootstrap
После того как мы убедились, какие платформы поддерживает наш экземпляр билдера, мы можем приступить к созданию образа контейнера. Buildx очень похож на команду docker build
и принимает те же аргументы, из которых мы в первую очередь сосредоточимся на --platform
, задающем целевую платформу для сборки. В приведенном ниже коде мы войдем в учетную запись Docker, соберем образ и отправим его в Docker Hub.
docker login # prompts for username and password
docker buildx build
--platform linux/amd64,linux/arm64,linux/arm/v7
-t cvitaa11/multi-arch:demo
--push
.
После завершения команды мы можем перейти в Docker Hub и увидеть наш образ со всеми поддерживаемыми архитектурами.
Пришло время проверить, как образ работает на разных машинах. Сначала мы запустим его на Windows (процессор Intel Core i5, относящийся к архитектуре amd64) с помощью команды:
docker run -p 3000:3000 cvitaa11/multi-arch:demo
Перейдем в веб-браузере на localhost:3000
и проверим ответ.
Теперь переключимся на Macbook Pro с чипом M1 и выполним ту же команду.
Откройте веб-браузер и снова перейдите на localhost:3000
:
Мы видим, что наш образ контейнера успешно работает на обеих процессорных архитектурах, что и было нашей основной целью.