В предыдущем уроке мы познакомились с Docker Compose и научились описывать многоконтейнерные приложения с помощью YAML-файлов. Теперь пришло время углубиться в создание собственных образов Docker с помощью Dockerfile. В этом уроке мы подробно рассмотрим, как писать Dockerfile, оптимизировать образы и применять лучшие практики при их создании.
Что такое Dockerfile?
Dockerfile — это текстовый файл, содержащий последовательность команд и инструкций для сборки образа Docker. С помощью Dockerfile вы можете автоматизировать процесс создания образов, описывая все необходимые шаги: выбор базового образа, установка зависимостей, копирование файлов, настройка переменных окружения и т.д.
Основные инструкции Dockerfile.
Давайте рассмотрим основные команды, используемые в Dockerfile:
FROM
Указывает базовый образ, от которого будет строиться ваш образ.
FROM python:3.9-slim
WORKDIR
Задает рабочую директорию внутри контейнера.
WORKDIR /app
COPY
Копирует файлы и директории с хоста в образ.
COPY requirements.txt ./
RUN
Выполняет команду в процессе сборки образа.
RUN pip install --no-cache-dir -r requirements.txt
CMD и ENTRYPOINT
Определяют команду, которая будет выполнена при запуске контейнера.
CMD ["python", "app.py"]
ENV
Устанавливает переменные окружения внутри контейнера.
ENV APP_ENV=production
EXPOSE
Документирует, какой порт будет использоваться приложением внутри контейнера.
EXPOSE 80
ADD
Похоже на COPY, но может распаковывать архивы и загружать файлы по URL.
ADD https://example.com/app.tar.gz /app/
Пример создания Dockerfile для веб-приложения на Python.
Давайте создадим Dockerfile для простого веб-приложения на Flask.
Шаг 1: Создайте директорию проекта.
mkdir myflaskapp
cd myflaskapp
Шаг 2: Создайте файл app.py с простым приложением Flask.
from flask import Flask
app = Flask(__name__)
@app.route('/') def hello():
return 'Hello from Docker!'
if __name__ == '__main__':
app.run(host='0.0.0.0')
Шаг 3: Создайте файл requirements.txt с зависимостями
flask
Шаг 4: Напишите Dockerfile.
# Используем официальный образ Python 3.9 на базе slim
FROM python:3.9-slim
# Устанавливаем переменную окружения для предотвращения буферизации вывода
ENV PYTHONUNBUFFERED=1
# Устанавливаем рабочую директорию
WORKDIR /app
# Копируем файл зависимостей
COPY requirements.txt ./
# Устанавливаем зависимости
RUN pip install --no-cache-dir -r requirements.txt
# Копируем исходный код приложения
COPY . .
# Указываем порт, который будет использован
EXPOSE 5000
# Определяем команду запуска приложения
CMD ["python", "app.py"]
Разбор Dockerfile:
- FROM python:3.9-slim: Используем легковесный образ Python 3.9.
- ENV PYTHONUNBUFFERED=1: Обеспечиваем немедленный вывод логов в терминал.
- WORKDIR /app: Устанавливаем рабочую директорию внутри контейнера.
- COPY requirements.txt ./: Копируем файл с зависимостями.
- RUN pip install --no-cache-dir -r requirements.txt: Устанавливаем зависимости без сохранения кеша.
- COPY . .: Копируем все файлы проекта в контейнер.
- EXPOSE 5000: Документируем использование порта 5000.
- CMD ["python", "app.py"]: Определяем команду для запуска приложения.
Сборка и запуск образа.
Сборка образа:
docker build -t myflaskapp .
-t myflaskapp: Присваиваем имя образу.
.: Указываем контекст сборки (текущая директория).
Запуск контейнера:
docker run -d -p 5000:5000 myflaskapp
-d: Запуск в фоновом режиме.
-p 5000:5000: Переадресация порта хоста на порт контейнера.
Проверьте работу приложения, открыв в браузере http://localhost:5000.
Оптимизация Dockerfile.
Использование многоэтапной сборки (Multi-stage builds).
Позволяет уменьшить размер конечного образа, исключив ненужные зависимости и файлы.
# Первый этап — сборка
FROM python:3.9-slim AS builder
WORKDIR /app
COPY requirements.txt ./
RUN pip install --user --no-cache-dir -r requirements.txt
# Второй этап — создание финального образа
FROM python:3.9-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Минимизация слоёв.
Каждая инструкция RUN, COPY, ADD создаёт новый слой. Объединяйте команды, чтобы уменьшить количество слоёв.
RUN apt-get update && apt-get install -y package1 package2 && rm -rf /var/lib/apt/lists/*
Использование .dockerignore.
Создайте файл .dockerignore, чтобы исключить ненужные файлы из контекста сборки. Пример содержимого .dockerignore:
.git
*.pyc
__pycache__
Лучшие практики при создании Dockerfile.
Используйте официальные базовые образы: Они регулярно обновляются и поддерживаются сообществом.
Минимизируйте размер образа: Используйте легковесные базовые образы (например, alpine).
Избегайте хранения секретов: Не включайте пароли и ключи API в образ.
Документируйте: Используйте инструкции LABEL для добавления метаданных об образе.
LABEL maintainer="yourname@example.com"
LABEL version="1.0"
LABEL description="Example Flask application"
Домашнее задание.
Задание 1: Создание Dockerfile для Node.js приложения.
- Создайте простое приложение на Node.js, которое возвращает "Hello from Node.js in Docker!".
- Напишите Dockerfile для этого приложения.
- Соберите образ и запустите контейнер.
- Убедитесь, что приложение работает корректно.
Задание 2: Оптимизация Dockerfile.
- Модифицируйте Dockerfile из задания 1, используя многоэтапную сборку для уменьшения размера образа.
- Добавьте файл .dockerignore, чтобы исключить ненужные файлы и директории.
Задание 3*: Исследование базовых образов.
- Попробуйте использовать разные базовые образы для вашего приложения (например, node:alpine).
- Сравните размеры полученных образов и время их сборки.
- Сделайте выводы о том, какие образы предпочтительнее использовать в разных ситуациях.
Что дальше?
В следующем уроке мы рассмотрим безопасность контейнеров. Продолжайте практиковаться и изучать Docker, чтобы стать профессионалом в контейнеризации приложений!