Как использовать команду docker buildx build для сборки и управления образами

DockerDockerBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этой лабораторной работе вы получите практический опыт использования команды docker buildx build для сборки и управления Docker-образами. Вы начнёте с создания простого образа с настройками по умолчанию, изучив, как определять инструкции для образа с помощью Dockerfile.

Выйдя за рамки базовых возможностей, вы исследуете более продвинутые функции, такие как использование аргументов сборки (build arguments) и выбор конкретных стадий в многоэтапной сборке (multi-stage build). Вы также научитесь эффективно управлять кешем сборки для оптимизации времени сборки с помощью параметров --cache-from и --cache-to. Кроме того, лабораторная работа проведёт вас через процесс сборки мультиплатформенных образов и их отправки в реестр, а также покажет, как безопасно передавать секреты и SSH-агенты во время сборки.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/ImageOperationsGroup(["Image Operations"]) docker(("Docker")) -.-> docker/SystemManagementGroup(["System Management"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ImageOperationsGroup -.-> docker/push("Push Image to Repository") docker/ImageOperationsGroup -.-> docker/rmi("Remove Image") docker/ImageOperationsGroup -.-> docker/images("List Images") docker/SystemManagementGroup -.-> docker/login("Log into Docker Registry") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/run -.-> lab-555045{{"Как использовать команду docker buildx build для сборки и управления образами"}} docker/push -.-> lab-555045{{"Как использовать команду docker buildx build для сборки и управления образами"}} docker/rmi -.-> lab-555045{{"Как использовать команду docker buildx build для сборки и управления образами"}} docker/images -.-> lab-555045{{"Как использовать команду docker buildx build для сборки и управления образами"}} docker/login -.-> lab-555045{{"Как использовать команду docker buildx build для сборки и управления образами"}} docker/build -.-> lab-555045{{"Как использовать команду docker buildx build для сборки и управления образами"}} end

Сборка простого образа с настройками по умолчанию

На этом шаге вы узнаете, как собрать простой Docker-образ с использованием Dockerfile. Dockerfile — это текстовый документ, содержащий все команды, которые пользователь может выполнить в командной строке для сборки образа. Docker может автоматически собирать образы, читая инструкции из Dockerfile.

Сначала перейдите в директорию ~/project, которая является рабочей для этой лабораторной работы.

cd ~/project

Теперь создадим простой Dockerfile. Этот файл определит образ на основе базового образа ubuntu и будет выводить "Hello, Docker!" при запуске контейнера из этого образа.

Используйте редактор nano, чтобы создать файл Dockerfile в директории ~/project.

nano Dockerfile

Добавьте следующее содержимое в Dockerfile:

FROM ubuntu:latest
CMD ["echo", "Hello, Docker!"]

Разберём этот простой Dockerfile:

  • FROM ubuntu:latest: Эта инструкция задаёт базовый образ для нашего нового образа. Мы используем последнюю версию официального образа Ubuntu из Docker Hub.
  • CMD ["echo", "Hello, Docker!"]: Эта инструкция определяет команду, которая будет выполнена при запуске контейнера из этого образа. В данном случае она запустит команду echo с аргументом "Hello, Docker!".

Сохраните файл, нажав Ctrl + S, и выйдите из редактора nano, нажав Ctrl + X.

Теперь, когда у нас есть Dockerfile, мы можем собрать образ с помощью команды docker build. Символ . в конце команды указывает Docker искать Dockerfile в текущей директории (~/project). Мы также присвоим образу имя, например, my-hello-image.

docker build -t my-hello-image .

Вы увидите вывод, показывающий, что Docker собирает образ слой за слоем. Сначала он загрузит образ ubuntu:latest, если его ещё нет в системе, а затем выполнит инструкцию CMD.

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

docker images

В выводе должен появиться образ my-hello-image.

Наконец, запустим контейнер из нашего нового образа, чтобы увидеть результат выполнения инструкции CMD.

docker run my-hello-image

Вы должны увидеть вывод "Hello, Docker!" в терминале. Это подтверждает, что образ был собран корректно, а инструкция CMD работает, как ожидалось.

Использование аргументов сборки и целевых стадий

На этом шаге вы научитесь использовать аргументы сборки (ARG) и целевые стадии в Dockerfile для создания более гибких и эффективных сборок. Аргументы сборки позволяют передавать переменные в процесс сборки, а целевые стадии дают возможность определять несколько этапов сборки в одном Dockerfile и собирать только конкретную стадию.

Сначала убедитесь, что находитесь в директории ~/project.

cd ~/project

Модифицируем существующий Dockerfile, добавив аргумент сборки и простую многостадийную сборку. Мы определим аргумент для приветственного сообщения и используем вторую стадию для копирования файла из первой стадии.

Откройте Dockerfile с помощью nano:

nano Dockerfile

Замените содержимое на следующее:

## Stage 1: Builder stage
FROM ubuntu:latest as builder
ARG GREETING="Hello from build argument!"
RUN echo $GREETING > /app/greeting.txt

## Stage 2: Final stage
FROM ubuntu:latest
COPY --from=builder /app/greeting.txt /greeting.txt
CMD ["cat", "/greeting.txt"]

Разберём изменения:

  • ARG GREETING="Hello from build argument!": Определяет аргумент сборки GREETING со значением по умолчанию. Это значение можно переопределить во время сборки.
  • FROM ubuntu:latest as builder: Начинает первую стадию сборки с именем builder. Это полезно для многостадийных сборок.
  • RUN echo $GREETING > /app/greeting.txt: В стадии builder создаёт файл greeting.txt в директории /app и записывает в него значение аргумента GREETING.
  • FROM ubuntu:latest: Начинает вторую стадию сборки. По умолчанию это будет итоговый образ.
  • COPY --from=builder /app/greeting.txt /greeting.txt: Копирует файл greeting.txt из стадии builder (из /app/greeting.txt) в корневую директорию (/) текущей стадии. Так передаются артефакты между стадиями.
  • CMD ["cat", "/greeting.txt"]: Устанавливает команду, которая выполняется при запуске контейнера из финального образа. Она выводит содержимое файла /greeting.txt.

Сохраните Dockerfile и выйдите из nano.

Теперь соберём образ с помощью команды docker build. Используем флаг --build-arg для передачи кастомного значения аргумента GREETING и присвоим образу имя my-arg-image.

docker build --build-arg GREETING="Greetings from the command line!" -t my-arg-image .

Наблюдайте за выводом. Вы должны увидеть, что процесс сборки использует переданный аргумент.

После завершения сборки проверьте список образов, чтобы убедиться в наличии my-arg-image.

docker images

Запустите контейнер из my-arg-image, чтобы увидеть результат.

docker run my-arg-image

Вы должны увидеть сообщение "Greetings from the command line!", что подтверждает использование аргумента сборки.

Теперь соберём только стадию builder. Это полезно для создания промежуточных образов с артефактами сборки без финального приложения. Используем флаг --target для указания имени стадии.

docker build --target builder -t my-builder-stage .

Снова проверьте список образов. Теперь вы должны видеть my-builder-stage в дополнение к my-arg-image.

docker images

Запуск контейнера из my-builder-stage не даст того же вывода, что и my-arg-image, так как инструкция CMD из финальной стадии не включена в стадию builder. Попробуем запустить его (скорее всего, он просто запустится и быстро завершится, так как нет команды по умолчанию).

docker run my-builder-stage

Это демонстрирует, как целевые стадии позволяют контролировать, какая часть Dockerfile будет собрана в образ.

Управление кэшем сборки с помощью --cache-from и --cache-to

На этом шаге вы научитесь управлять кэшем сборки Docker, используя флаги --cache-from и --cache-to. Кэш сборки может значительно ускорить последующие сборки за счёт повторного использования слоёв из предыдущих сборок. --cache-from позволяет указать образ для использования в качестве источника кэша, а --cache-to позволяет экспортировать кэш сборки в указанное место (например, в реестр или локальную директорию).

Сначала убедитесь, что находитесь в директории ~/project.

cd ~/project

Немного изменим наш Dockerfile, чтобы смоделировать изменение, которое обычно нарушает кэш. Добавим простую инструкцию RUN.

Откройте Dockerfile с помощью nano:

nano Dockerfile

Добавьте следующую строку после инструкции ARG в стадии builder:

RUN echo "Adding a new layer"

Обновлённый Dockerfile должен выглядеть так:

## Stage 1: Builder stage
FROM ubuntu:latest as builder
ARG GREETING="Hello from build argument!"
RUN echo "Adding a new layer"
RUN echo $GREETING > /app/greeting.txt

## Stage 2: Final stage
FROM ubuntu:latest
COPY --from=builder /app/greeting.txt /greeting.txt
CMD ["cat", "/greeting.txt"]

Сохраните Dockerfile и выйдите из nano.

Теперь соберём образ снова без использования специальных опций кэширования. Docker автоматически использует локальный кэш, если он доступен.

docker build -t my-cached-image .

Вы увидите, что некоторые слои собираются с нуля, так как мы добавили новую инструкцию, что сделало недействительным кэш для последующих инструкций.

Теперь смоделируем сценарий, когда вы хотите использовать ранее собранный образ в качестве источника кэша, возможно из реестра или другой сборки. Для демонстрации мы будем использовать только что собранный образ my-cached-image в качестве источника кэша для новой сборки.

Сначала внесём ещё одно небольшое изменение в Dockerfile, чтобы смоделировать очередную модификацию.

Откройте Dockerfile:

nano Dockerfile

Измените сообщение в новой инструкции RUN:

RUN echo "Adding another new layer"

Обновлённый Dockerfile должен выглядеть так:

## Stage 1: Builder stage
FROM ubuntu:latest as builder
ARG GREETING="Hello from build argument!"
RUN echo "Adding another new layer"
RUN echo $GREETING > /app/greeting.txt

## Stage 2: Final stage
FROM ubuntu:latest
COPY --from=builder /app/greeting.txt /greeting.txt
CMD ["cat", "/greeting.txt"]

Сохраните и выйдите из nano.

Теперь соберём образ снова, но на этот раз используем флаг --cache-from, чтобы указать my-cached-image в качестве источника кэша.

docker build --cache-from my-cached-image -t my-cached-image-from .

Вы увидите, что Docker пытается использовать слои из my-cached-image. Слой, соответствующий первой инструкции RUN, скорее всего будет пересобран, так как инструкция изменилась, но последующие слои могут быть взяты из кэша, если они совпадают.

Флаг --cache-to используется для экспорта кэша сборки. Это особенно полезно в CI/CD-пайплайнах для совместного использования кэша между сборками. Для использования --cache-to обычно требуется драйвер сборки, поддерживающий экспорт кэша, например docker-container.

Сначала установим Docker Compose, который часто используется с buildx.

sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Теперь создадим экземпляр сборщика buildx.

docker buildx create --use

Теперь соберём образ и экспортируем кэш в локальную директорию. Мы будем использовать экспортёр кэша local.

docker buildx build --cache-to type=local,dest=./build-cache -t my-exported-cache-image . --load
  • docker buildx build: Использует инструмент buildx для сборки
  • --cache-to type=local,dest=./build-cache: Экспортирует кэш в локальную директорию build-cache в текущей директории
  • -t my-exported-cache-image: Присваивает тег результирующему образу
  • .: Указывает контекст сборки (текущая директория)
  • --load: Загружает собранный образ в локальный кэш образов Docker

Вы увидите вывод, показывающий процесс сборки и экспорт кэша. В вашей директории ~/project будет создана директория build-cache.

Теперь смоделируем чистую среду сборки и попробуем собрать, используя экспортированный кэш. Сначала удалим собранные образы.

docker rmi my-cached-image my-cached-image-from my-exported-cache-image

Теперь соберём образ снова, на этот раз используя экспортированный кэш в качестве источника.

docker buildx build --cache-from type=local,src=./build-cache -t my-imported-cache-image . --load
  • --cache-from type=local,src=./build-cache: Импортирует кэш из локальной директории build-cache

Вы увидите, что Docker использует слои из экспортированного кэша, что значительно ускоряет процесс сборки по сравнению со сборкой с нуля.

Сборка мультиплатформенных образов и их отправка в реестр

На этом шаге вы научитесь собирать Docker-образы для нескольких архитектур (таких как linux/amd64 и linux/arm64) и отправлять их в контейнерный реестр. Сборка мультиплатформенных образов необходима для обеспечения работы ваших приложений на разных типах оборудования. Мы будем использовать Docker Buildx, который вы инициализировали на предыдущем шаге.

Сначала убедитесь, что находитесь в директории ~/project.

cd ~/project

Мы будем использовать существующий Dockerfile для этого шага. Давайте соберём образ для платформ linux/amd64 и linux/arm64. Мы присвоим образу имя и версию, например, your-dockerhub-username/my-multi-platform-image:latest. Замените your-dockerhub-username на ваше имя пользователя в Docker Hub. Если у вас нет аккаунта в Docker Hub, вы можете создать его бесплатно.

Для сборки под несколько платформ мы используем флаг --platform с командой docker buildx build. Также нам понадобится флаг --push для отправки результирующего манифеста и образов в реестр.

docker buildx build --platform linux/amd64,linux/arm64 -t your-dockerhub-username/my-multi-platform-image:latest . --push

Примечание: Эта команда потребует входа в Docker Hub, если вы ещё не авторизованы. При необходимости вы можете войти с помощью команды docker login в отдельной сессии терминала.

docker login

Введите имя пользователя и пароль Docker Hub при запросе.

После входа снова выполните команду docker buildx build.

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

Вы можете проверить отправку мультиплатформенного образа, посетив ваш репозиторий Docker Hub в веб-браузере. Вы должны увидеть образ my-multi-platform-image с тегом latest, а на вкладке "Tags" будет указано, что он поддерживает несколько архитектур.

Альтернативно, вы можете использовать команду docker buildx imagetools inspect для проверки отправленного манифеста. Замените your-dockerhub-username на ваше имя пользователя.

docker buildx imagetools inspect your-dockerhub-username/my-multi-platform-image:latest

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

Это демонстрирует, как собирать и отправлять образы, которые могут работать на разных архитектурах процессоров, делая ваши Docker-образы более универсальными.

Использование секретов и SSH-агента при сборке

На этом шаге вы научитесь безопасно передавать секреты и SSH-агент в процесс сборки Docker с помощью Buildx. Это важно для случаев, когда сборке требуется доступ к приватным репозиториям, установка закрытых пакетов или взаимодействие с внешними сервисами, требующими аутентификации, без внедрения конфиденциальной информации непосредственно в Dockerfile.

Сначала убедитесь, что находитесь в директории ~/project.

cd ~/project

Мы изменим наш Dockerfile, чтобы продемонстрировать использование секрета во время сборки. Для примера создадим тестовый файл с секретом и прочитаем его содержимое во время сборки.

Создайте файл mysecret.txt в директории ~/project с произвольным содержимым:

echo "This is a secret message!" > ~/project/mysecret.txt

Откройте Dockerfile в редакторе nano:

nano Dockerfile

Добавьте новую инструкцию RUN в стадии builder, использующую флаг --mount=type=secret для доступа к секрету:

## Stage 1: Builder stage
FROM ubuntu:latest as builder
ARG GREETING="Hello from build argument!"
RUN echo "Adding another new layer"
RUN echo $GREETING > /app/greeting.txt
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret > /app/secret_content.txt

## Stage 2: Final stage
FROM ubuntu:latest
COPY --from=builder /app/greeting.txt /greeting.txt
COPY --from=builder /app/secret_content.txt /secret_content.txt
CMD ["cat", "/greeting.txt", "/secret_content.txt"]

Разберём новую инструкцию:

  • RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret > /app/secret_content.txt: Эта инструкция монтирует секрет в контейнер сборки.
    • --mount=type=secret: Указывает, что монтируется секрет
    • id=mysecret: Идентификатор секрета, который мы укажем при сборке
    • cat /run/secrets/mysecret: Внутри контейнера секрет доступен по пути /run/secrets/mysecret
    • > /app/secret_content.txt: Перенаправляем содержимое секрета в файл /app/secret_content.txt

Также добавлена инструкция COPY в финальной стадии для копирования файла с секретом.

Сохраните Dockerfile и выйдите из nano.

Теперь соберём образ с использованием docker buildx build, передав секрет через флаг --secret:

docker buildx build --secret id=mysecret,src=~/project/mysecret.txt -t my-secret-image . --load
  • --secret id=mysecret,src=~/project/mysecret.txt: Передаёт секрет в сборку
    • id=mysecret: Соответствует ID из Dockerfile
    • src=~/project/mysecret.txt: Путь к файлу с секретом

После сборки запустите контейнер:

docker run my-secret-image

Вы увидите приветственное сообщение и содержимое секретного файла.

Теперь продемонстрируем использование SSH-агента при сборке. Это полезно для клонирования приватных Git-репозиториев.

Убедитесь, что SSH-агент запущен и содержит ваш ключ:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa ## Укажите путь к вашему SSH-ключу

Добавим в Dockerfile инструкцию для использования SSH-агента:

## Stage 1: Builder stage
FROM ubuntu:latest as builder
ARG GREETING="Hello from build argument!"
RUN echo "Adding another new layer"
RUN echo $GREETING > /app/greeting.txt
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret > /app/secret_content.txt
RUN --mount=type=ssh git clone [email protected]:your-username/your-private-repo.git || echo "Skipping git clone as this is a demo"

## Stage 2: Final stage
FROM ubuntu:latest
COPY --from=builder /app/greeting.txt /greeting.txt
COPY --from=builder /app/secret_content.txt /secret_content.txt
CMD ["cat", "/greeting.txt", "/secret_content.txt"]

Примечание: Замените your-username/your-private-repo.git на URL вашего репозитория.

Соберите образ с доступом к SSH-агенту:

docker buildx build --ssh default -t my-ssh-image . --load
  • --ssh default: Предоставляет доступ к SSH-агенту

После сборки запустите образ:

docker run my-ssh-image

Это демонстрирует безопасное использование секретов и SSH-агента при сборке Docker-образов.

Итоги

В этой лабораторной работе вы изучили основы создания Docker-образов с использованием Dockerfile. Вы начали с создания простого Dockerfile, который определяет образ на основе Ubuntu и выполняет базовую команду. Затем вы использовали команду docker build для сборки этого образа, понимая, как Docker обрабатывает инструкции в Dockerfile послойно и как присваивать теги результирующему образу.

На основе базовых знаний вы исследовали более продвинутые возможности команды docker buildx build. Это включало использование аргументов сборки (build arguments) для передачи динамических значений в процесс сборки и применение целевых стадий (target stages) в многоэтапной сборке для оптимизации размера образа и времени сборки. Вы также научились эффективно управлять кешем сборки с помощью --cache-from и --cache-to для ускорения последующих сборок.

Кроме того, вы получили опыт создания мультиплатформенных образов, позволяющих вашим образам работать на разных архитектурах, и отправки этих мультиплатформенных образов в контейнерный реестр. Наконец, вы узнали, как безопасно передавать секреты и использовать SSH-агент во время процесса сборки, повышая безопасность и гибкость создания образов.