⚖️ Старый vs Новый: Dockerfile best practices

⚡ Главные изменения

  • FROM ubuntu:18.04FROM python:3.12-slim (меньше, целевой образ)
  • ADD url ...COPY (ADD по URL — непредсказуемо, непрозрачно)
  • Работа под root → USER appuser (безопасность)
  • Пароль в ENV в Dockerfile → передавать через -e при docker run
  • Несколько RUN → один RUN с && + очистка кеша

Антипаттерн 1: Тяжёлый базовый образ вместо целевого

В примере из лекции используется FROM ubuntu:18.04 как базовый образ для Python-приложения. Ubuntu содержит сотни пакетов, которые не нужны приложению.

Из лекции (старое)

# Dockerfile (из лекции)
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y python3
COPY . /app
WORKDIR /app
CMD ["python3", "app.py"]

Размер образа: ~180 МБ только базовый. Устаревшая Ubuntu 18.04 (EOL апрель 2023).

Современный подход

# Dockerfile
FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

CMD ["python3", "app.py"]

python:3.12-slim ~ 50 МБ. Python уже установлен. Актуальная версия.

Антипаттерн 2: ADD для скачивания URL вместо COPY

В примере сложного Dockerfile из лекции использовалась инструкция ADD с URL. Это считается антипаттерном — скачанный файл не верифицируется, сборка зависит от доступности внешнего ресурса.

Из лекции (старое)

# Dockerfile (из лекции)
FROM python:3.7.2-alpine3.8
ADD https://raw.githubusercontent.com/...
    /my_app_directory

Проблемы: зависит от интернета при сборке, нет проверки целостности, сложно кешировать.

Современный подход

# Dockerfile
FROM python:3.12-alpine

# Скачать заранее, проверить хеш, положить в проект
# Или использовать пакетный менеджер
COPY vendor/ /app/vendor/
# ADD только для .tar.gz с локальной распаковкой:
ADD archive.tar.gz /app/

COPY — явно, воспроизводимо, кешируется правильно.

Антипаттерн 3: Запуск под root

По умолчанию все команды в Dockerfile выполняются от пользователя root. Если приложение скомпрометировано, злоумышленник получает root-доступ к файловой системе контейнера.

Из лекции (старое)

# Dockerfile (из лекции)
FROM debian:stable-slim
RUN apt-get update && apt-get install -y curl
COPY fetch_data.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/fetch_data.sh
CMD ["/usr/local/bin/fetch_data.sh"]
# Всё выполняется под root!

Современный подход

# Dockerfile
FROM debian:stable-slim
RUN apt-get update && apt-get install -y curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Создать непривилегированного пользователя
RUN useradd -m -u 1001 appuser

COPY fetch_data.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/fetch_data.sh

# Переключиться на непривилегированного пользователя
USER appuser

CMD ["/usr/local/bin/fetch_data.sh"]

Антипаттерн 4: Пароль в переменной окружения Dockerfile

Хардкодить пароли через ENV в Dockerfile — грубая ошибка безопасности. Они попадают в историю образа и видны через docker history и docker inspect.

Небезопасно (НИКОГДА ТАК)

# Dockerfile — ОПАСНО!
FROM mysql:8.0
ENV MYSQL_ROOT_PASSWORD=my-hardcoded-pw
# Пароль виден в docker inspect и docker history!

Правильно

# Dockerfile
FROM mysql:8.0
# Пароли не указываем здесь!
# EXPOSE 3306
# Терминал — передаём при запуске
docker run -d \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8.0

Или используйте Docker Secrets / .env файл с Docker Compose.

Антипаттерн 5: Несколько RUN вместо объединённого

Каждый RUN создаёт новый слой. Разбитые команды — больше слоёв, больше итоговый образ.

Из лекции (устарело)

# Dockerfile
RUN apt-get update
RUN apt-get upgrade
RUN apt-get install -y curl
RUN apt-get install -y git
# 4 слоя, кеш пакетов не очищается

Современный подход

# Dockerfile
RUN apt-get update && apt-get install -y \
    curl \
    git \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*
# 1 слой, кеш очищен, образ меньше

Антипаттерн 6: Порядок слоёв — код перед зависимостями

Неоптимально (частая ошибка)

# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY . .                       # 1. копируем ВСЁ
RUN pip install -r requirements.txt  # 2. ставим зависимости
CMD ["python3", "app.py"]
# При любом изменении кода → кеш requirements сбрасывается!

Оптимально (кеш зависимостей сохраняется)

# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .        # 1. только requirements
RUN pip install --no-cache-dir -r requirements.txt  # 2. кешируется!
COPY . .                       # 3. код — меняется часто
CMD ["python3", "app.py"]
Итог: современный Dockerfile — это: актуальный минимальный базовый образ (slim/alpine), COPY вместо ADD, один объединённый RUN с очисткой кеша, правильный порядок слоёв (зависимости → код), непривилегированный USER, .dockerignore, пароли только через -e при docker run.
← К оглавлению урока