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

Многоэтапные сборки для создания эффективных образов

Многоэтапные сборки (multi-stage builds) в Docker  —  эффективный метод создания компактных и более безопасных образов Docker за счет разделения среды сборки и производственной среды в одном Dockerfile. Этот метод не только помогает уменьшить конечный размер образа, но и минимизирует поверхность атаки за счет исключения ненужных инструментов и файлов из образа этапа выполнения.

Что такое многоэтапная сборка?

Многоэтапные сборки позволяют использовать несколько операторов FROM в Dockerfile. Каждая инструкция FROM может использовать отдельные базы, при этом каждый этап может быть назван по-своему. Это позволяет копировать артефакты из одного этапа в другой, оставляя в финальном образе все необходимое.

Как использовать многоэтапные сборки

# Синтаксис для многоэтапной сборки 
# Этап 1: сборка приложения
FROM golang:1.15 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .

# Этап 2: создание финального образа
FROM alpine:latest
COPY --from=builder /app/myapp /app/myapp
ENTRYPOINT ["/app/myapp"]

Этот пример демонстрирует простую многоэтапную сборку Go-приложения. На этапе сборки используется образ Golang для компиляции приложения, а на последнем этапе создается легковесный образ Alpine, содержащий только скомпилированный бинарник.

Случаи использования многоэтапных сборок

  • Уменьшение размера образа: если процесс сборки приложения предусматривает компиляцию кода или включение зависимостей, которые не нужны во время выполнения.
  • Повышение безопасности: минимизация поверхности атаки конечного образа за счет исключения инструментов и файлов, не требующихся для работы приложения.
  • Разделение сред сборки: когда нужно собирать приложения в определенной среде, но запускать их в другой.

Рекомендуемые практики

  • Оптимизация использования кэша сборки: внимательно располагайте команды COPY и RUN, чтобы максимально использовать послойное кэширование.
  • Минимизация размера конечного образа: копируйте в финальный образ только те артефакты, которые необходимы для работы приложения.
  • Маркирование этапов сборки: используйте именованные этапы для улучшения читабельности и удобства сопровождения Docker-файла.

Распространенные ошибки

  • Чрезмерное усложнение: избегайте излишне сложных многоэтапных сборок, которые могут привести к появлению сложных в обслуживании Docker-файлов.
  • Игнорирование контекста сборки: следите за контекстом сборки, который вы отправляете Docker-демону, так как неоправданно большие контексты могут замедлить процесс сборки.

Дополнительная информация

Сжатие слоев образов

Сжатие (squashing) слоев образов в Docker  —  это техника, которая позволяет значительно уменьшить размер образов Docker. Объединение всех слоев, созданных в процессе сборки образа, в один слой позволяет оптимизировать хранение и распространение образов Docker.

Что такое сжатие?

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

Как использовать сжатие

Чтобы сжать слои образов, можно использовать флаг --squash при сборке образов с включенным Docker BuildKit. Вот как можно включить BuildKit и использовать squash-функцию:

# Включение Docker BuildKit
export DOCKER_BUILDKIT=1

# Сборка и сжатие образа
docker build --tag myapp:latest --squash .

Примечание: флаг --squash является экспериментальной функцией и может потребовать включения экспериментальных функций в конфигурации Docker.

Случаи использования сжатия

  • Оптимизация размера образа: используйте сжатие, когда нужно уменьшить размер конечного образа Docker; особенно это полезно при распространении образов по сети или хранении их в реестре.
  • Упрощение слоев образа: если Dockerfile содержит много команд RUN и COPY, которые увеличивают количество слоев и общий размер образа.

Рекомендуемые практики

  • Выборочный подход к сжатию: подумайте, какие образы больше всего выиграют от сжатия; некоторые слои лучше не сжимать для целей кэширования, особенно во время разработки.
  • Учет кэширования: сжатие может повлиять на механизм кэширования слоев Docker; многократное сжатие чревато увеличением времени сборки, поскольку Docker не сможет эффективно кэшировать промежуточные слои.
  • Соблюдение мер безопасности: сжатие может скрыть историю образа, поэтому убедитесь, что последний сжимаемый слой не содержит конфиденциальных данных, предназначенных для удаления в промежуточных слоях.

Распространенные ошибки

  • Злоупотребление сжатием в процессе разработки: сжатие после каждой сборки во время разработки может значительно замедлить время сборки из-за потери преимуществ кэширования.
  • Игнорирование экспериментального статуса: помните, что squash-функция является экспериментальной и может вести себя непоследовательно в разных версиях или конфигурациях Docker.

Дополнительная информация

Docker BuildKit Secrets

Docker BuildKit представляет более безопасный способ работы с секретными данными (Secrets) в процессе сборки, решая проблему использования приватных ресурсов без их раскрытия в конечном образе. Возможности управления секретами BuildKit позволяют передавать конфиденциальную информацию во время сборки, не оставляя следов в слоях образа.

Что такое Docker BuildKit Secrets?

Docker BuildKit Secrets  —  это функция системы сборки BuildKit от Docker. Она позволяет безопасно передавать секретную информацию (например, пароли, закрытые ключи и API-токены) в процесс сборки. Эти секреты не хранятся ни в конечном образе, ни в промежуточных слоях, что делает процесс сборки более безопасным.

Как использовать Docker BuildKit Secrets

Перед использованием Docker BuildKit Secrets убедитесь, что Docker BuildKit включен. Это можно сделать, установив переменную среды DOCKER_BUILDKIT=1. Затем используйте флаг --secret в процессе сборки, чтобы предоставить секретные данные.

# Включение Docker BuildKit
export DOCKER_BUILDKIT=1

# Процесс сборки с секретными данными
docker build --secret id=mysecret,src=/path/to/secret/file.txt -t myapp:latest .

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

# syntax=docker/dockerfile:1.2
FROM alpine
# Использование секретных данных без раскрытия их в образе
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

Случаи использования Docker BuildKit Secrets

  • Доступ к приватным Git-репозиториям: когда сборка требует извлечения зависимостей из приватных репозиториев.
  • Использование приватных ключей: когда вам нужно использовать приватные ключи для доступа по SSH или для расшифровки файлов во время сборки.
  • API-токены: если в процессе сборки требуется доступ к API, требующим аутентификации.

Рекомендуемые практики

  • Соблюдение осторожности при раскрытии секретных данных: используйте такие данные только в случае крайней необходимости и избегайте их логирования или раскрытия на промежуточных этапах.
  • Ограничение секретов: четко определяйте и распределяйте секретные данные по конкретным этапам сборки, где они необходимы, снижая таким образом риск их раскрытия.
  • Закрепление версий: всегда указывайте версию синтаксиса в Dockerfile при использовании функций BuildKit, чтобы обеспечить совместимость и предсказуемость.

Распространенные ошибки

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

Дополнительная информация

Использование .dockerignore

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

Что такое .dockerignore?

Подобно .gitignore, файл .dockerignore указывает Docker, какие файлы и каталоги игнорировать при сборке образа. Это особенно важно, поскольку каждый файл, отправляемый Docker-демону как часть контекста сборки, может неоправданно увеличить время и сложность сборки, особенно в больших проектах.

Как использовать .dockerignore

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

Пример файла .dockerignore

.git
.gitignore
Dockerfile*
*.md
node_modules
temp/

В этом примере запрещается включать в контекст сборки Docker метаданные Git, файлы Markdown, все файлы Dockerfile, каталог node_modules и любой каталог temp.

Случаи использования .dockerignore

  • Большие репозитории: для проектов с большим количеством данных, особенно тех, которые не нужны для сборки или во время выполнения.
  • Чувствительная информация: исключение файлов, содержащих секреты и конфиденциальную информацию, которые не должны быть включены в контекст сборки Docker.
  • Каталоги зависимостей: для языков, загружающих зависимости в локальные каталоги (например, node_modules для Node.js), которые не нужны в контексте сборки, если вы устанавливаете зависимости во время сборки.

Рекомендуемые практики

  • Регулярный мониторинг: периодически просматривайте файл .dockerignore, чтобы убедиться, что он соответствует структуре и требованиям вашего проекта.
  • Явные шаблоны: используйте явные шаблоны для точного подбора нужных файлов и каталогов, чтобы избежать непреднамеренного исключения.
  • Поддержание безопасности: используйте .dockerignore для усиления безопасности; таким образом, только необходимые файлы будут включены в контекст сборки.

Распространенные ошибки

  • Небрежное отношение к .dockerignore: неиспользование или неправильная настройка файла .dockerignore может привести к медленной сборке, большим размерам образов и потенциальному включению конфиденциальной информации.
  • Злоупотребление исключением файлов: несмотря на важность исключения ненужных файлов, будьте осторожны, чтобы не исключить файлы, необходимые для процесса сборки,  —  это может привести к сбоям в сборке или неправильному поведению образа.

Дополнительная информация

Проверки “здоровья” в Docker-файлах

Реализация проверок “здоровья” (health checks) непосредственно в Docker-файлах  —  эффективный метод автоматического мониторинга рабочего состояния контейнеров. Определяя проверки “здоровья”, Docker может принимать обоснованные решения о состоянии контейнеров и предпринимать соответствующие действия, например перезапускать контейнер, с которым что-то не так, или запрещать передачу трафика до тех пор, пока он не станет “здоровым”.

Что такое проверка “здоровья” Docker?

Проверка “здоровья” Docker  —  это команда, указываемая в Dockerfile, которую Docker периодически выполняет для проверки работоспособности контейнера. Эта команда должна показать, правильно ли функционирует контейнер. Docker интерпретирует статус выхода команды проверки “здоровья” для определения статуса контейнера: статус выхода, равный 0, означает “здоров” (healthy), а ненулевой  —  “нездоров” (unhealthy).

Как использовать проверки “здоровья” в Docker-файлах

Проверки здоровья определяются в Dockerfile с помощью инструкции HEALTHCHECK. Вы можете указать:

  • команду для запуска проверки;
  • интервал между проверками;
  • таймаут для каждой проверки;
  • количество повторных попыток, после которого сервис может быть сочтен “нездоровым”;
  • начальный период, в течение которого контейнер должен стабилизироваться перед запуском проверок “здоровья”.

Пример Dockerfile с проверкой “здоровья”

В этом примере устанавливается проверка “здоровья” контейнера Nginx с помощью curl для запроса главной страницы каждые 30 секунд. Если команда не выполняется (страница возвращается некорректно) три раза подряд, Docker помечает контейнер как “нездоровый” (unhealthy).

При проверке “здоровья” используется curl для выполнения простого запроса к главной странице сервера Nginx. Docker будет выполнять эту проверку периодически в соответствии с заданными интервалами, чтобы убедиться, что контейнер функционирует как положено.

Сначала убедитесь, что Dockerfile запускается с базового образа Nginx, а затем добавьте инструкцию HEALTHCHECK, как показано ниже:

FROM nginx:latest

# Установите curl для проверки здоровья.
RUN apt-get update && apt-get install -y curl && apt-get clean

# Скопируйте пользовательские файлы конфигурации Nginx, если таковые имеются.
# COPY default.conf /etc/nginx/conf.d/

HEALTHCHECK --interval=30s --timeout=30s --retries=3 --start-period=5s \
CMD curl -f http://localhost/ || выход: 1

Этот Dockerfile выполняет следующее:

  • Запускается с последним образом Nginx.
  • Устанавливает curl с помощью apt-get, чтобы использовать его для проверки “здоровья” (примечание: образ Nginx основан на Debian, поэтому для установки используется apt-get).
  • Опционально: копирует любую пользовательскую конфигурацию Nginx, которая у вас может быть. Эта строка закомментирована, но включена в качестве примера того, как можно расширить Dockerfile.
  • Определяет HEALTHCHECK, которая запускается каждые 30 секунд (--interval=30s), завершается через 30 секунд (--timeout=30s), повторяет до 3 попыток, прежде чем признать контейнер “нездоровым” (--retries=3), и ожидает 5 секунд перед запуском проверки “здоровья” (--start-period=5s). Фактическая проверка выполняется в виде запроса curl к главной странице сервера Nginx (http://localhost/). Если этот запрос не выполняется (curl завершает работу с ненулевым статусом, если не может успешно выполнить HTTP-запрос), команда exit 1 сигнализирует Docker о том, что контейнер “нездоров”.

Случаи использования проверок “здоровья”

  • Доступность сервиса: когда необходимо убедиться в доступности и отзывчивости сервиса в контейнере, прежде чем отправлять на него трафик.
  • Готовность зависимостей: в многоконтейнерных приложениях, где одни контейнеры зависят от полной работоспособности других.
  • Самовосстанавливающиеся системы: создание более устойчивой системы, которая может автоматически перезапускать “нездоровые” контейнеры.

Рекомендуемые практики

  • Минимизация влияния на производительность: убедитесь, что команда проверки “здоровья” является легковесной и не оказывает существенного влияния на производительность контейнера.
  • Установление точного периода старта проверки: задайте реалистичный период запуска --start-period, чтобы дать приложению достаточно времени для инициализации до того, как проверка “здоровья” начнет давать сбой.
  • Использование конкретных конечных точек “здоровья”: рекомендуется использовать специальные конечные точки (например, /healthz), которые проверяют состояние различных компонентов приложения; таким образом, не стоит ограничиваться исследованием только главной страницы или базовой проверкой TCP.

Распространенные ошибки

  • Сложные команды: избегайте слишком сложных команд проверки “здоровья”, которые могут быть ненадежными или вызывать неожиданные побочные эффекты.
  • Игнорирование внешних зависимостей: если состояние контейнера зависит от внешних сервисов, убедитесь, что проверка “здоровья” учитывает их доступность, чтобы избежать ложных срабатываний.

Дополнительная информация

Форматирование вывода Docker CLI

Docker CLI (Command Line Interface  —  интерфейс командной строки) предоставляет мощную функцию для настройки вывода команд с помощью опции --format. Эта опция использует язык шаблонов Go, позволяя пользователям указывать, как именно должен быть структурирован вывод, что облегчает его парсинг или интеграцию с другими инструментами.

Что такое форматирование вывода Docker CLI?

Форматирование вывода Docker CLI позволяет настроить вывод команд Docker в соответствии с потребностями пользователя, используя язык шаблонов Go для указания формата вывода. Эта возможность неоценима при извлечении определенной информации из подробных выводов команд Docker, особенно при автоматизации задач или интеграции с конвейерами CI/CD.

Как использовать форматирование вывода Docker CLI

Флаг --format может использоваться с различными командами Docker CLI для настройки вывода. Вот пример того, как можно вывести список всех идентификаторов контейнеров, используя пользовательский формат:

docker ps --format '{{.ID}}'

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

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

Вот как можно вывести список образов, показывая только их хранилище, тег и размер, в формате таблицы:

docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

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

Случаи использования форматирования вывода Docker CLI

  • Работа со сценариями и автоматизация: когда требуется парсинг выходных данных команд Docker в сценариях или средствах автоматизации.
  • Создание пользовательских отчетов: создание пользовательских отчетов или дэшбордов, для которых необходима определенная информация из среды Docker.
  • Упрощение вывода: когда необходимо упростить вывод для ясности или сосредоточиться на конкретных деталях.

Рекомендуемые практики

  • Использование возможностей шаблонизатора Go: ознакомьтесь с синтаксисом шаблонов Go, чтобы эффективно использовать функции форматирования.
  • Форматирование таблиц для удобства чтения: используйте форматирование table для получения удобочитаемых результатов, особенно при обмене информацией с членами команды.
  • Комбинирование форматированного вывода Docker с другими инструментами Unix: для еще более эффективной обработки комбинируйте форматированный вывод Docker с такими инструментами Unix, как grep, awk и jq для вывода JSON.

Распространенные ошибки

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

Дополнительная информация

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи DavidW (skyDragon): 13 Docker Tricks You Didn’t Know

Предыдущая статья6 рекомендаций по устранению типичных проблем производительности Java
Следующая статьяКак создать платформу обработки и анализа данных за неделю