← Назад к вопросам

Что описывается в Dockerfile?

2.0 Middle🔥 31 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Dockerfile: описание процесса создания Docker образа

Dockerfile — это текстовый файл, который описывает пошаговый процесс создания Docker образа (image). Образ — это своего рода "снимок" приложения со всеми его зависимостями, конфигурацией и кодом. Когда ты запускаешь образ, получается контейнер (container) — изолированное окружение, где работает твоё приложение.

Основная идея

Dockerfile → docker build → Docker Image → docker run → Docker Container
"Инструкция"   "Сборка"    "Шаблон"      "Запуск"    "Рабочее ПО"

Базовая структура Dockerfile

# 1. Базовый образ (на основе которого строим наш)
FROM python:3.10-slim

# 2. Автор/мейнтейнер
LABEL maintainer="dev@example.com"

# 3. Переменные окружения для build'а
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

# 4. Рабочая директория в контейнере
WORKDIR /app

# 5. Копирование файлов из хоста в контейнер
COPY requirements.txt .

# 6. Установка зависимостей
RUN pip install --no-cache-dir -r requirements.txt

# 7. Копирование всего приложения
COPY . .

# 8. Экспонирование порта (информационно)
EXPOSE 8000

# 9. Команда запуска (что выполняется при docker run)
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Часть 1: FROM — базовый образ

FROM python:3.10-slim
# или
FROM ubuntu:22.04
# или
FROM node:18

Это образ, с которого начинаем строить. Он уже содержит:

  • Операционную систему (Linux)
  • Установленные инструменты (для Python: интерпретатор, pip)
  • Базовые утилиты

Выбор базового образа важен:

# ✅ python:3.10-slim — 150MB, оптимален для Python приложений
FROM python:3.10-slim

# ❌ python:3.10 — 900MB, содержит много лишнего
# ❌ ubuntu:22.04 — 77MB, но нужно вручную ставить Python

Часть 2: ENV — переменные окружения

ENV PYTHONUNBUFFERED=1
# Python будет выводить логи мгновенно, не буферизировать

ENV PYTHONDONTWRITEBYTECODE=1
# Python не будет создавать .pyc файлы

ENV DATABASE_URL=postgresql://localhost/mydb
# Переменная для приложения (НЕ для production!)

Часть 3: WORKDIR — рабочая директория

WORKDIR /app
# Все последующие команды выполняются из /app

# Эквивалентно:
# RUN mkdir -p /app && cd /app

Часть 4: COPY и ADD — копирование файлов

# Копировать файл requirements.txt в контейнер
COPY requirements.txt .
# COPY <source на хосте> <destination в контейнере>

# Копировать всю папку
COPY . .
# Текущая папка с хоста → текущая папка в контейнере (т.е. /app)

# Исключить файлы (через .dockerignore)
# .dockerignore:
# __pycache__
# *.pyc
# .venv
# .git

Разница COPY vs ADD:

COPY requirements.txt .          # ✅ Рекомендуется
ADD https://example.com/file.z . # ✅ Если нужен файл из интернета
ADD archive.tar.gz .            # ✅ Если нужно автоматически распаковать

Часть 5: RUN — выполнение команд при build'е

# Установка зависимостей
RUN pip install --no-cache-dir -r requirements.txt

# Несколько команд в одном RUN (экономит слои образа)
RUN apt-get update && \
    apt-get install -y postgresql-client && \
    rm -rf /var/lib/apt/lists/*
    # rm очищает кэш, уменьшает размер образа

# Создание пользователя для безопасности
RUN groupadd -r appuser && useradd -r -g appuser appuser

Часть 6: EXPOSE — экспонирование портов

EXPOSE 8000
# Информирует Docker, что контейнер слушает на порту 8000
# НЕ открывает порт автоматически!

# Для открытия нужно:
# docker run -p 8000:8000 myapp
# или в docker-compose: ports: ["8000:8000"]

Часть 7: CMD vs ENTRYPOINT — команда запуска

# CMD — команда по умолчанию
CMD ["python", "manage.py", "runserver"]

# Это можно переопределить:
# docker run myapp python test.py
# ENTRYPOINT — точка входа, почти не переопределяется
ENTRYPOINT ["python"]
CMD ["manage.py", "runserver"]

# Результат: python manage.py runserver
# docker run myapp = python manage.py runserver
# docker run myapp test.py = python test.py

Практический пример:

# shell form (менее предпочтительно)
CMD python manage.py runserver

# exec form (рекомендуется)
CMD ["python", "manage.py", "runserver"]
# Почему? Exec form передаёт сигналы корректно (SIGTERM, SIGKILL)

Полный пример: Django приложение

# Multi-stage build для уменьшения размера
FROM python:3.10-slim as builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# --user устанавливает в ~/.local вместо /usr/local

# Финальный образ
FROM python:3.10-slim

LABEL maintainer="dev@example.com"

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PATH=/home/appuser/.local/bin:$PATH

WORKDIR /app

# Безопасность: использовать непривилегированного пользователя
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Копировать установленные пакеты из builder'а
COPY --from=builder /root/.local /home/appuser/.local

# Копировать код приложения
COPY --chown=appuser:appuser . .

USER appuser

EXPOSE 8000

# Healthcheck (для Kubernetes)
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
  CMD curl -f http://localhost:8000/health/ || exit 1

CMD ["gunicorn", "myapp.wsgi", "--bind", "0.0.0.0:8000", "--workers=4"]

Процесс сборки образа

# 1. Построить образ
docker build -t myapp:1.0 .
# -t = tag (имя и версия образа)
# . = путь к Dockerfile

# 2. Просмотреть образ
docker images myapp

# 3. Запустить контейнер из образа
docker run -p 8000:8000 myapp:1.0

# 4. Развернуть на production
docker push myregistry.azurecr.io/myapp:1.0

Слои образа (важно для кэширования)

# Каждая инструкция создаёт "слой" (layer)
FROM python:3.10-slim        # Слой 1 (от базового образа)
WORKDIR /app                 # Слой 2
COPY requirements.txt .       # Слой 3
RUN pip install -r requirements.txt  # Слой 4 (самый большой)
COPY . .                      # Слой 5
CMD ["python", "main.py"]   # Слой 6

Кэширование:

# Если я изменю requirements.txt и пересобираю образ:
# Слои 1, 2 используются из кэша (быстро)
# Слой 3 изменился → пересчитывается
# Слои 4, 5, 6 пересчитываются (долго, потому что pip)

# Оптимизация: поместить stable файлы ранше
COPY requirements.txt .       # Меняется редко
RUN pip install -r requirements.txt
COPY . .                      # Меняется часто

Лучшие практики

# ✅ Используй minimal образы (slim, alpine)
FROM python:3.10-slim  # 150MB
# ❌ вместо
FROM python:3.10       # 900MB

# ✅ Минимизируй количество слоёв
RUN apt-get update && apt-get install -y postgresql-client && \
    rm -rf /var/lib/apt/lists/*
# ❌ вместо множества RUN команд

# ✅ Используй .dockerignore
# ❌ не копируй лишние файлы

# ✅ Непривилегированный пользователь
USER appuser
# ❌ не запускай как root

# ✅ Multi-stage builds для уменьшения размера
FROM python:3.10 as builder
# ... build
FROM python:3.10-slim
# ... copy from builder

# ✅ HEALTHCHECK для мониторинга
HEALTHCHECK CMD curl http://localhost:8000/health

# ✅ Не коммитьте .env и секреты
# Используй Docker Secrets или environment variables

Dockerfile vs docker-compose

# Dockerfile описывает ОДИ контейнер (образ)
# Для одного приложения
# docker-compose.yml описывает НЕСКОЛЬКО контейнеров
# Для системы сервисов
services:
  web:
    build: .              # Используется Dockerfile для сборки
    ports: ["8000:8000"]
    environment:
      DATABASE_URL: postgres://db:5432/mydb
  
  db:
    image: postgres:14
    environment:
      POSTGRES_DB: mydb
      POSTGRES_PASSWORD: secret

Заключение

Dockerfile — это по сути "скрипт инсталляции" для приложения, описывающий:

  1. Базовую среду (FROM)
  2. Зависимости (RUN)
  3. Код приложения (COPY)
  4. Конфигурацию (ENV, EXPOSE)
  5. Команду запуска (CMD)

Это делает приложение легко переносимым между машинами (laptop, CI/CD, production) без необходимости устанавливать зависимости вручную. Это фундамент containerized разработки и microservices архитектуры.