Собираем Docker-образы для разных платформ

Привет, друзья! Сегодня расскажу о том, как собрать Docker-образ, который будет работать на разных архитектурах процессоров. Это особенно актуально сейчас, когда ARM-процессоры становятся всё популярнее (Apple M1/M2, Raspberry Pi, AWS Graviton и т.д.).

Зачем это нужно?

Представьте ситуацию: вы разработали приложение на своем ноутбуке с Intel/AMD процессором (архитектура x86_64), а потом хотите запустить его на Raspberry Pi (архитектура ARM). Если вы просто соберете Docker-образ на своем ноутбуке и попытаетесь запустить его на Raspberry Pi, то получите ошибку. Почему? Потому что бинарные файлы, скомпилированные для x86_64, не будут работать на ARM.

Решение? Мультиархитектурные образы!

Docker Buildx на помощь

В Docker есть отличный инструмент — Buildx, который позволяет собирать образы для разных платформ одной командой. Давайте разберемся, как им пользоваться.

Шаг 1: Проверяем, что Buildx установлен

docker buildx version

Если вы видите информацию о версии, значит всё в порядке. Если нет, то в современных версиях Docker Buildx уже включен, просто нужно его активировать:

docker buildx create --name mybuilder --use

Шаг 2: Создаем простой Dockerfile

Для примера возьмем простое приложение на Python:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY app.py .

CMD ["python", "app.py"]

Шаг 3: Собираем образ для нескольких платформ

Теперь самое интересное. Вместо обычной команды docker build используем docker buildx build:

docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t username/myapp:latest --push .

Что здесь происходит:

  • --platform указывает, для каких платформ собирать образ
  • -t username/myapp:latest задает имя и тег образа
  • --push сразу отправляет образ в Docker Hub (для этого нужно сначала выполнить docker login)

Шаг 4: Проверяем результат

После успешной сборки и отправки в репозиторий, можно проверить, что образ действительно поддерживает разные платформы:

docker manifest inspect username/myapp:latest

Вы увидите список всех платформ, для которых собран образ.

Как это работает под капотом?

Когда вы запускаете docker buildx build для нескольких платформ, Docker:

  1. Запускает виртуальные машины или контейнеры с QEMU для эмуляции целевых архитектур
  2. Собирает образ для каждой указанной платформы
  3. Создает манифест, который объединяет все эти образы
  4. Когда пользователь запускает docker pull, Docker автоматически выбирает подходящий образ для его платформы

Практические советы

1. Используйте базовые образы с поддержкой нужных платформ

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

2. Учитывайте зависимости

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

3. Тестируйте на реальном железе

Эмуляция не всегда идеальна. По возможности тестируйте свои образы на реальных устройствах с разными архитектурами.

Пример для реального проекта

Вот пример более сложного Dockerfile с учетом мультиархитектурной сборки:

# Используем многоэтапную сборку для оптимизации
FROM golang:1.18 AS builder

WORKDIR /app

# Копируем только файлы, необходимые для сборки зависимостей
COPY go.mod go.sum ./
RUN go mod download

# Копируем исходный код
COPY . .

# Компилируем для текущей архитектуры
# CGO_ENABLED=0 важен для кросс-компиляции
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

# Финальный образ
FROM alpine:latest

# Устанавливаем CA-сертификаты для HTTPS
RUN apk --no-cache add ca-certificates

WORKDIR /root/

# Копируем бинарник из предыдущего этапа
COPY --from=builder /app/app .

# Запускаем приложение
CMD ["./app"]

Сборка:

docker buildx build --platform linux/amd64,linux/arm64 -t username/goapp:latest --push .

Заключение

Мультиархитектурные Docker-образы — это мощный инструмент, который позволяет создавать действительно переносимые приложения. Теперь вы можете собрать образ один раз и запускать его где угодно: на своем ноутбуке, на сервере в облаке, на Raspberry Pi или даже на экзотическом оборудовании.

В следующих постах расскажу о том, как автоматизировать такие сборки с помощью GitHub Actions или GitLab CI. А пока — экспериментируйте и делитесь результатами в комментариях!


P.S. А вы уже используете мультиархитектурные образы в своих проектах? Расскажите о своем опыте!