Dockerfile для Python-приложения: slim, кэш слоёв, не root
Базовый Dockerfile для Python-приложения: образ python:3.13-slim, копирование requirements.txt и установка зависимостей отдельным слоем, затем код приложения и запуск не от root. Порядок важен: пока зависимости не менялись, Docker берёт их из кэша и сборка проходит за секунды.
Файлы проекта
app/
├── Dockerfile
├── .dockerignore
├── requirements.txt
└── app.pyМинимальное приложение на Flask:
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.0Dockerfile
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"]Что делает каждый шаг:
Строка | Зачем |
|---|---|
| Облегчённый образ на Debian, заметно меньше полного |
| Вывод |
| Не создавать файлы |
| Не хранить кэш pip внутри слоя, образ меньше |
| Процесс работает с ограниченными правами |
Файл .dockerignore
Он не даёт копировать в образ лишнее и ускоряет сборку:
.git
.venv
__pycache__
*.pyc
.env
Dockerfile
.dockerignoreСобрать и запустить
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"}.
Передать настройки
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"].