Dockerfile для Python-приложения: slim, кэш слоёв, не root

Категория: docker · Язык: Dockerfile · Обновлено:

Базовый Dockerfile для Python-приложения: образ python:3.13-slim, копирование requirements.txt и установка зависимостей отдельным слоем, затем код приложения и запуск не от root. Порядок важен: пока зависимости не менялись, Docker берёт их из кэша и сборка проходит за секунды.

Файлы проекта

Текст
app/
├── Dockerfile
├── .dockerignore
├── requirements.txt
└── app.py

Минимальное приложение на Flask:

Python
from flask import Flask

app = Flask(__name__)

@app.get("/")
def index():
    return {"status": "ok"}

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Файл requirements.txt:

Текст
flask>=3.0
gunicorn>=22.0

Dockerfile

Dockerfile
FROM python:3.13-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

WORKDIR /app

# Зависимости отдельным слоем: он пересобирается только при изменении requirements.txt
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Код приложения
COPY . .

# Запуск без прав root
RUN useradd --create-home appuser
USER appuser

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

Что делает каждый шаг:

Строка

Зачем

python:3.13-slim

Облегчённый образ на Debian, заметно меньше полного

PYTHONUNBUFFERED=1

Вывод print и логов сразу попадает в docker logs

PYTHONDONTWRITEBYTECODE=1

Не создавать файлы .pyc в образе

pip install --no-cache-dir

Не хранить кэш pip внутри слоя, образ меньше

USER appuser

Процесс работает с ограниченными правами

Файл .dockerignore

Он не даёт копировать в образ лишнее и ускоряет сборку:

Текст
.git
.venv
__pycache__
*.pyc
.env
Dockerfile
.dockerignore

Собрать и запустить

Bash
docker build -t my-app .
docker run -d --name my-app -p 8000:8000 my-app
curl http://localhost:8000
docker logs my-app

Параметр -p 8000:8000 публикует порт контейнера на порту хоста. Ответом будет {"status":"ok"}.

Передать настройки

Bash
docker run -d -p 8000:8000 -e APP_ENV=production --env-file .env.prod my-app

Частые вопросы

slim или alpine?

slim основан на Debian и совместим с колёсами pip, поэтому большинство пакетов ставятся без компиляции. Образы Alpine меньше, но библиотеки там часто собираются из исходников и бывают проблемы совместимости.

Почему при каждом изменении кода зависимости ставятся заново?

Скорее всего, COPY . . стоит до pip install. Сначала копируйте только requirements.txt, затем устанавливайте, и только потом копируйте код.

Как запускать FastAPI?

Установите uvicorn и замените команду: CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"].