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.
Запуск
docker build -t fastapi-basic .
docker run -d --name api -p 8000:8000 fastapi-basic
curl -s localhost:8000/ | python3 -m json.tool
Тесты как отдельная стадия:
docker build --target test -t fastapi-basic:test .
Через Compose:
docker compose up -d
docker compose ps
Проверки
Пробы отвечают по-разному:
curl -s localhost:8000/healthz
curl -s localhost:8000/readyz
docker inspect api --format '{{.State.Health.Status}}'
Валидация входных данных:
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:
docker logs api 2>&1 | tail -3
docker logs api 2>&1 | tail -1 | python3 -m json.tool
Graceful shutdown с активным запросом:
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 и записи о закрытии ресурсов.
Валидация конфигурации при старте:
docker run --rm -e SHUTDOWN_DELAY=не-число fastapi-basic 2>&1 | tail -2
Приложение падает сразу с понятным сообщением.
Запуск не от root:
docker exec api id -u
Уборка
docker rm -f api
docker compose down
docker rmi fastapi-basic fastapi-basic:test