Главная/Материалы/Материал

fastapi-basic

FastAPI в container'е. Используется в уроке 6.10 и в проекте 2.

Что демонстрирует

  • точка входа python -m uvicorn, а не fastapi run — см. ниже, почему;
  • один процесс на container; репликация — задача оркестратора или Compose;
  • lifespan вместо устаревших @app.on_event — корректный graceful shutdown;
  • раздельные /healthz (liveness) и /readyz (readiness);
  • structured logging в JSON, вывод в stdout — все строки, включая строки uvicorn;
  • валидация конфигурации при старте: приложение падает сразу, а не в момент запроса;
  • multi-stage со стадией тестов, не входящей в образ.

Почему не fastapi run. Официальная рекомендация FastAPI — именно fastapi run, и для разработки она удобна. Но в container'е она ломает пятый пункт списка: команда печатает баннер до импорта приложения и перенастраивает логирование uvicorn после импорта, отменяя настройку из logging_config. Измерено на этом образе: fastapi run — 7 не-JSON строк из 10, python -m uvicorn — 0 из 9. Подробный разбор — урок 6.10.

Запуск

bash
docker build -t fastapi-basic .
docker run -d --name api -p 8000:8000 fastapi-basic
curl -s localhost:8000/ | python3 -m json.tool

Тесты как отдельная стадия:

bash
docker build --target test -t fastapi-basic:test .

Через Compose:

bash
docker compose up -d
docker compose ps

Проверки

Пробы отвечают по-разному:

bash
curl -s localhost:8000/healthz
curl -s localhost:8000/readyz
docker inspect api --format '{{.State.Health.Status}}'

Валидация входных данных:

bash
curl -s -X POST localhost:8000/echo -H 'Content-Type: application/json' -d '{"message":"привет"}'
curl -s -o /dev/null -w '%{http_code}\n' -X POST localhost:8000/echo \
     -H 'Content-Type: application/json' -d '{"message":""}'

Ожидается 200 и 422.

Structured logging — каждая строка валидный JSON:

bash
docker logs api 2>&1 | tail -3
docker logs api 2>&1 | tail -1 | python3 -m json.tool

Graceful shutdown с активным запросом:

bash
docker rm -f api 2>/dev/null
docker run -d --name api -p 8000:8000 -e SHUTDOWN_DELAY=2 fastapi-basic
sleep 5
curl -s "localhost:8000/slow?seconds=5" &   # длинный запрос
sleep 1
time docker stop api                         # ждёт завершения запроса
docker logs api 2>&1 | grep -i 'закрыт\|завершаюсь'
docker inspect api --format 'exit code: {{.State.ExitCode}}'

Ожидается код 0 и записи о закрытии ресурсов.

Валидация конфигурации при старте:

bash
docker run --rm -e SHUTDOWN_DELAY=не-число fastapi-basic 2>&1 | tail -2

Приложение падает сразу с понятным сообщением.

Запуск не от root:

bash
docker exec api id -u

Уборка

bash
docker rm -f api
docker compose down
docker rmi fastapi-basic fastapi-basic:test
Markdown на GitHub ↗