🐛 Типичные ошибки: Multistage и Docker Compose

⚡ Топ-5 ошибок

  1. Не именовать стадию (без AS name) → нельзя использовать COPY --from=
  2. depends_on без healthcheck → приложение стартует раньше, чем БД готова принимать подключения
  3. Ключ version: в compose-файле → предупреждения, потенциальный конфликт с валидатором
  4. Секреты в environment: в compose-файле → попадают в git-историю; правильно — через .env файл
  5. Забыть --build при docker compose up → запускается старый образ после изменения кода

Ошибка 1: Не именовать стадию в Multistage

Неправильно

# Dockerfile

FROM python:3.12-slim
# Стадия без имени AS
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
# Ошибка: нет имени стадии для --from
COPY --from=??? /root/.local /root/.local

Правильно

# Dockerfile

FROM python:3.12-slim AS builder
# Стадия с именем AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
# Ссылаемся по имени
COPY --from=builder /root/.local /root/.local
Симптом: ошибка сборки invalid --from flag value.

Ошибка 2: depends_on без healthcheck

Неправильно

# docker-compose.yml

services:
  app:
    build: .
    depends_on:
      - db        # ждёт только START контейнера

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret

Правильно

# docker-compose.yml

services:
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
    healthcheck:
      test: ["CMD", "mysqladmin", "ping",
             "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
Симптом: приложение падает с ошибкой подключения к БД через несколько секунд после старта, затем перезапускается и работает. Нестабильный старт.

Ошибка 3: Секреты напрямую в docker-compose.yml

Неправильно

# docker-compose.yml  ← НЕ делать так

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: my_super_secret
      POSTGRES_USER: admin

Этот файл попадает в git-репозиторий — секрет становится публичным.

Правильно

# .env  ← добавить в .gitignore!

POSTGRES_PASSWORD=my_super_secret
POSTGRES_USER=admin
# docker-compose.yml

services:
  db:
    image: postgres:16
    env_file:
      - .env
    # или через ${VAR} из .env:
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_USER: ${POSTGRES_USER}
Правило: всегда добавляйте .env в .gitignore. Коммитьте только .env.example с placeholder-значениями.

Ошибка 4: Запуск без --build после изменения кода

Неправильно

# терминал

# Изменили app.py...
docker compose up -d
# Запускается СТАРЫЙ образ!
# Изменения не применились.

Правильно

# терминал

# После изменения кода — пересобрать:
docker compose up --build -d

# Или явно пересобрать:
docker compose build
docker compose up -d
Симптом: «я изменил код, но в контейнере ничего не поменялось». Docker кеширует образ и не пересобирает его автоматически при up.

Ошибка 5: Неправильный PATH после --user установки pip

Неправильно

# Dockerfile

FROM python:3.12-slim AS builder
RUN pip install --user -r requirements.txt
COPY app.py .

FROM python:3.12-slim
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app/app.py .
# Забыли добавить /root/.local/bin в PATH!
CMD ["flask", "run"]   # Command not found!

Правильно

# Dockerfile

FROM python:3.12-slim AS builder
WORKDIR /app
RUN pip install --user -r requirements.txt
COPY app.py .

FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app/app.py .
# Добавляем ~/.local/bin в PATH
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Симптом: /bin/sh: flask: command not found или python: can't open file 'app.py' при старте контейнера.

Ошибка 6: Потеря данных БД при docker compose down -v

Опасная команда

# терминал

# ОСТОРОЖНО: -v удаляет тома с данными!
docker compose down -v
# Все данные MySQL/PostgreSQL УДАЛЕНЫ

Безопасная остановка

# терминал

# Остановить без удаления томов (данные сохраняются)
docker compose down

# Остановить только контейнеры, тома не трогать
docker compose stop
Правило: флаг -v при docker compose down удаляет все именованные тома. Используйте только для полной очистки тестовой среды.