# Создание и сборка Docker-контейнеров ## Введение * **Цель:** Научиться создавать собственные Docker-образы, которые затем используются для запуска Docker-контейнеров. * **Основной инструмент:** Dockerfile - файл с инструкциями для сборки образа. ## Этапы создания Docker-контейнера (через образ) 1. **Написание Dockerfile:** Определение базового образа, копирование файлов, установка зависимостей, настройка окружения, определение команды запуска. 2. **Сборка Docker-образа (`docker build`):** Выполнение инструкций из Dockerfile для создания слоеного образа. 3. **Запуск Docker-контейнера (`docker run`):** Создание и запуск экземпляра образа. ## Dockerfile: Подробное рассмотрение инструкций * **Структура Dockerfile:** Последовательность инструкций, выполняемых Docker Daemon. Обычно одна инструкция - один слой в образе. * **Основные инструкции (повторение и углубление):** * **`FROM [:] [AS ]`:** * **Обязательная инструкция:** Определяет базовый образ, на основе которого будет строиться новый образ. * ``: Имя образа (например, `ubuntu`, `python`, `node`). * ``: Конкретная версия образа (например, `18.04`, `3.9-slim`, `latest`). Если не указан, используется `latest`. * `AS `: Присваивает псевдоним базовому образу для использования в многоэтапных сборках (multi-stage builds). * **`RUN ` (shell form) или `RUN ["executable", "param1", "param2"]` (exec form):** * **Выполняет команды внутри образа.** Используется для установки программного обеспечения, настройки системы и выполнения других действий. * **Shell form:** Команда выполняется в оболочке (`/bin/sh -c` на Linux). * **Exec form:** Команда выполняется напрямую без оболочки. Рекомендуется для большей предсказуемости. * **Примеры:** ```dockerfile RUN apt-get update && apt-get install -y --no-install-recommends python3 python3-pip RUN ["pip3", "install", "-r", "requirements.txt"] ``` * **`COPY ... ` или `COPY --from= ... `:** * **Копирует файлы и директории с хостовой машины в образ.** * ``: Путь к файлу или директории на хосте. Может быть несколько источников. * ``: Абсолютный путь внутри образа, куда будут скопированы файлы. * `--from=`: Используется в многоэтапных сборках для копирования артефактов из предыдущего этапа сборки. * **Пример:** ```dockerfile COPY ./app /app ``` * **`ADD ... ` или `ADD --from= ... `:** * **Аналогична `COPY`, но имеет дополнительные возможности:** * Может распаковывать локальные tar-архивы. * Может загружать файлы по URL. * **Рекомендуется использовать `COPY` для простых операций копирования.** * **Пример:** ```dockerfile ADD [https://example.com/app.tar.gz](https://example.com/app.tar.gz) /app/ ``` * **`WORKDIR `:** * **Устанавливает рабочую директорию для последующих инструкций `RUN`, `CMD`, `ENTRYPOINT`, `COPY`, `ADD`.** * Если директория не существует, она будет создана. * **Пример:** ```dockerfile WORKDIR /app ``` * **`ENV = ...`:** * **Устанавливает переменные окружения внутри образа.** * Могут использоваться в последующих инструкциях и доступны в запущенном контейнере. * **Пример:** ```dockerfile ENV PYTHON_VERSION 3.9 RUN apt-get update && apt-get install -y python${PYTHON_VERSION} ``` * **`EXPOSE [/...]`:** * **Объявляет порты, которые приложение внутри контейнера прослушивает.** * **Не публикует порт автоматически на хостовой машине.** Это делается при запуске контейнера с флагом `-p`. * **Используется для документирования и взаимодействия между связанными контейнерами.** * **Пример:** ```dockerfile EXPOSE 80/tcp 443/tcp ``` * **`CMD ["executable", "param1", "param2"]` (exec form, рекомендуется) или `CMD command param1 param2` (shell form) или `CMD ["param1", "param2"]` (как аргументы для `ENTRYPOINT`):** * **Указывает команду, которая будет выполнена при запуске контейнера из образа.** * **Может быть переопределена** при запуске контейнера с помощью `docker run [arguments]`. * **В Dockerfile может быть только одна инструкция `CMD`.** * **Пример:** ```dockerfile CMD ["python", "app.py"] ``` * **`ENTRYPOINT ["executable", "param1", "param2"]` (exec form, рекомендуется) или `ENTRYPOINT command param1 param2` (shell form):** * **Указывает исполняемый файл, который будет запущен при старте контейнера.** * **Аргументы, переданные в `docker run [arguments]`, будут добавлены к команде `ENTRYPOINT`.** * **Часто используется для создания исполняемых образов.** * **Может быть переопределен** при запуске контейнера с флагом `--entrypoint`. * **В Dockerfile может быть только одна инструкция `ENTRYPOINT`.** * **Пример:** ```dockerfile ENTRYPOINT ["/bin/my-app"] ``` * **`USER [:]` или `USER [:]`:** * **Устанавливает пользователя (и опционально группу), под которым будут выполняться последующие инструкции `RUN`, `CMD` и `ENTRYPOINT`.** * Рекомендуется запускать процессы внутри контейнера от непривилегированного пользователя для безопасности. * **Пример:** ```dockerfile USER nobody ``` * **`VOLUME ["/data"]`:** * **Объявляет именованную или анонимную точку монтирования тома.** * Позволяет сохранять данные, созданные внутри контейнера, вне его файловой системы. * **Пример:** ```dockerfile VOLUME ["/var/lib/mysql"] ``` * **`ARG [=]`:** * **Определяет переменные, которые могут быть переданы во время сборки образа с помощью флага `--build-arg`.** * Могут иметь значения по умолчанию. * **Пример:** ```dockerfile ARG NODE_VERSION=16 FROM node:${NODE_VERSION}-slim ``` * **`ONBUILD `:** * **Выполняет указанную инструкцию в дочернем образе, созданном на основе текущего.** * Полезно для создания базовых образов, которые ожидают определенной настройки в производных образах. * **Пример:** ```dockerfile ONBUILD COPY . /app ONBUILD WORKDIR /app ``` * **`STOPSIGNAL `:** * **Устанавливает системный сигнал, который будет отправлен контейнеру для его корректного завершения.** По умолчанию `SIGTERM`. * **Пример:** ```dockerfile STOPSIGNAL SIGINT ``` * **`HEALTHCHECK [--interval= --timeout= --start-period= --retries=] CMD `:** * **Определяет команду для проверки работоспособности контейнера.** * Docker Daemon периодически выполняет эту команду и определяет статус контейнера (`starting`, `healthy`, `unhealthy`). * **Пример:** ```dockerfile HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost:8080/health || exit 1 ``` * **`SHELL ["executable", "parameters"]`:** * **Изменяет стандартную оболочку, используемую для инструкции `RUN` (shell form).** По умолчанию `["/bin/sh", "-c"]` на Linux. * **Пример:** ```dockerfile SHELL ["powershell", "-Command"] RUN Get-ChildItem C:\ ``` ## Сборка Docker-образа (`docker build`) * **Команда:** `docker build [OPTIONS] PATH | URL | -` * **Основные опции:** * `-t` или `--tag [:]`: Присваивает имя и опциональный тег образу. Рекомендуется указывать имя пользователя/организации перед именем образа (например, `myuser/my-app:latest`). * `-f` или `--file `: Указывает путь к Dockerfile (по умолчанию ищется файл с именем `Dockerfile` в контексте сборки). * `--build-arg =`: Передает аргументы сборки, определенные в Dockerfile с помощью `ARG`. * `--no-cache`: Отключает использование кеша при сборке. Полезно для отладки или принудительной перестройки слоев. * `--platform `: Указывает целевую платформу для сборки (полезно для создания мультиархитектурных образов). * `--target `: Используется в многоэтапных сборках для сборки только определенного этапа. * **Контекст сборки (Build Context):** Набор файлов и директорий, доступных Docker Daemon во время сборки. Обычно это текущая директория (`.`), если не указан другой `PATH`. * **Примеры:** ```bash docker build -t myuser/my-web-app:v1 . docker build -f ./dockerfiles/api.Dockerfile -t myorg/my-api-service:latest ./api docker build --build-arg API_KEY=mysecretkey -t myuser/secure-app . ``` ## Многоэтапные сборки (Multi-Stage Builds) * **Идея:** Использование нескольких инструкций `FROM` в одном Dockerfile для создания промежуточных "строительных" образов, из которых копируются только необходимые артефакты в финальный, более легкий образ. * **Преимущества:** * **Уменьшение размера финального образа:** Исключение ненужных инструментов разработки, библиотек и промежуточных файлов. * **Улучшение безопасности:** Меньше установленных пакетов означает меньшую поверхность атаки. * **Ускорение сборки:** Кеширование промежуточных этапов. * **Пример:** Сборка Go-приложения ```dockerfile # Этап сборки FROM golang:1.17 AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download -x COPY . . RUN go build -o my-app # Финальный образ FROM alpine:latest WORKDIR /app COPY --from=builder /app/my-app . EXPOSE 8080 CMD ["./my-app"] ``` ## Запуск Docker-контейнера (`docker run`) * **Команда:** `docker run [OPTIONS] IMAGE [COMMAND] [ARG...]` * **Основные опции (связанные со сборкой):** * `-d` или `--detach`: Запускает контейнер в фоновом режиме. * `-p` или `--publish [hostPort:]containerPort[/tcp|udp|sctp]`: Публикует порт контейнера на хостовой машине. * `--name `: Присваивает имя контейнеру. * `-v` или `--volume [host_path:]container_path[:ro|rw]`: Монтирует тома (bind mounts или named volumes). * `-e` или `--env `: Устанавливает переменные окружения для контейнера. * `--rm`: Автоматически удаляет контейнер после его остановки. * `--entrypoint `: Переопределяет `ENTRYPOINT`, определенный в Dockerfile. * `--cmd [args...]`: Переопределяет `CMD`, определенный в Dockerfile. * **Примеры:** ```bash docker run -d -p 8080:80 myuser/my-web-app:v1 docker run --name my-running-app --rm myorg/my-api-service docker run -v my-data:/data my-database-image docker run -e API_URL=[http://api.example.com](http://api.example.com) my-app ``` ## Лучшие практики при создании Dockerfile * **Используйте специфичные базовые образы:** Выбирайте минимально необходимые образы. * **Минимизируйте количество слоев:** Объединяйте несколько команд `RUN` в одну с помощью `&&`. * **Используйте кеш эффективно:** Располагайте инструкции, которые редко меняются, в начале Dockerfile. * **Не храните секреты в Dockerfile:** Используйте `--build-arg` или переменные окружения во время запуска. * **Создавайте непривилегированных пользователей:** Используйте инструкцию `USER`. * **Определяйте `HEALTHCHECK`:** Для мониторинга работоспособности контейнера. * **Используйте многоэтапные сборки:** Для уменьшения размера финального образа. * **Следуйте рекомендациям по безопасности Dockerfile:** Проверяйте базовые образы, обновляйте пакеты. * **Документируйте Dockerfile:** Комментируйте важные шаги. ## Заключение * Создание Docker-контейнеров начинается с написания Dockerfile. * Dockerfile содержит инструкции для сборки Docker-образа. * Команда `docker build` используется для создания образа из Dockerfile. * Команда `docker run` используется для запуска контейнеров из созданных образов. * Следование лучшим практикам позволяет создавать эффективные, безопасные и легко поддерживаемые Docker-образы.