Продакшен-практики: безопасность, логирование, профили, Docker и деплой
Мы уже научились делать MVP на Spring Boot: строить слои controller → service → repository, проектировать REST API с DTO и валидацией, подключать базу через Spring Data JPA, добавлять миграции Flyway и транзакции, улучшать качество кода тестами и документацией OpenAPI.
Теперь важный шаг: сделать приложение готовым к реальной эксплуатации. Продакшен — это окружение, где приложением пользуются реальные люди, и любая ошибка стоит времени, денег и репутации. В этой статье разберём практики, которые помогают сделать сервис безопасным, наблюдаемым и удобным для деплоя.
Полезные официальные источники:
Spring Boot Reference: Externalized Configuration
Spring Boot Reference: Profiles
Spring Boot Reference: Logging
Spring Security Reference
Spring Boot Reference: Container Images
Docker Documentation
The Twelve-Factor AppЧто меняется, когда MVP становится продакшеном
В MVP мы часто делаем упор на скорость разработки. В продакшене добавляются новые требования:
Безопасность: закрыть API от посторонних и не утекать секретами.
Наблюдаемость: понимать, что происходит в сервисе, по логам и метрикам.
Конфигурация: разные настройки для dev и prod без переписывания кода.
Воспроизводимый деплой: одинаковая сборка у всех (локально, на сервере, в CI).!Диаграмма показывает путь от кода до продакшен-деплоя и где применяются профили и Docker
Профили и конфигурация
Простыми словами: что такое профиль
Профиль (profile) — это имя набора настроек. Обычно используют:
dev — локальная разработка
test — тесты
prod — продакшенИдея: код один и тот же, а настройки разные.
Как хранить настройки
В Spring Boot чаще всего используют файлы:
application.yml — общие настройки
application-dev.yml — настройки для разработки
application-prod.yml — настройки для продакшенаПример application.yml (общие настройки):
Пример application-dev.yml (локальная база, подробные логи):
Пример application-prod.yml (логи спокойнее, SQL не печатаем):
Здесь важный принцип продакшена:
секреты не храним в репозитории
вместо этого используем переменные окружения (в примере: DB_USERNAME, DB_PASSWORD)Как включить профиль
Способы включения профиля:
через переменную окружения SPRING_PROFILES_ACTIVE=prod
через аргумент запуска --spring.profiles.active=prodПример запуска:
Когда нужен @Profile
Иногда нужно включать не только настройки, но и разные бины (объекты Spring) в разных окружениях.
Пример: в dev хотим тестовые данные, а в prod — нет.
Логирование: чтобы понимать, что происходит
Зачем нужны логи
Логи — это записи о событиях в приложении. Они помогают:
быстро понять причину ошибки
увидеть, какие запросы приходят
отследить проблемные местаВ Spring Boot обычно используется связка SLF4J + Logback.
Уровни логов простыми словами
| Уровень | Когда использовать |
|---|---|
| ERROR | операция провалилась и требует внимания |
| WARN | подозрительная ситуация, но приложение продолжает работать |
| INFO | важные бизнес-события и жизненный цикл приложения |
| DEBUG | подробности для разработки |
| TRACE | совсем детальные шаги, редко нужен |
Правило для кода: логируем через log, а не через System.out
Пример сервиса:
Практические правила:
не пишите в логи пароли, токены и персональные данные
на каждый неожиданный Exception должен быть либо понятный ответ клиенту, либо запись ERROR (обычно и то, и другое)
логи должны помогать восстановить цепочку событийКорреляция запросов: как связать логи одного запроса
Корреляция — это способ связать между собой все логи, относящиеся к одному HTTP-запросу, через идентификатор запроса.
Минимальный вариант для MVP:
принимать заголовок X-Request-Id от клиента или прокси
если заголовка нет, генерировать новый
добавлять этот id в логиВ реальном продакшене это часто делается фильтрами и настройкой логирования. Если вы используете инфраструктуру вроде Kubernetes и централизованный сбор логов, это экономит много времени при разборе инцидентов.
Безопасность: минимальный набор для MVP в продакшене
Базовые угрозы, о которых важно помнить
Если оставить API «как есть», обычно быстро происходят такие проблемы:
кто угодно может читать и менять данные
кто угодно может создавать нагрузку (очень много запросов)
случайно публикуются секреты в конфигурации и логахНиже — минимальный, но практичный набор.
Аутентификация и авторизация простыми словами
Аутентификация: кто ты такой (например, логин и пароль).
Авторизация: что тебе разрешено делать (например, удалять можно только свои заметки).В прошлых статьях мы уже делали бизнес-проверку «удалять может только владелец». В продакшене это должно опираться на реального пользователя, а не на currentUserId, который клиент может подделать.
Минимальная защита через Spring Security
Самый простой способ закрыть API в MVP — включить Spring Security и потребовать логин/пароль.
Зависимость:
Пример минимальной конфигурации (закрываем всё, кроме health-check):
Пояснения простыми словами:
httpBasic включает простую схему логин/пароль для запросов.
csrf.disable() часто применяют для чистых REST API, когда нет cookie-сессий и HTML-форм.
permitAll() для /actuator/health полезен, чтобы инфраструктура могла проверять, жив ли сервис.> Если вы не уверены, что именно делаете, не выключайте безопасность «на всякий случай». Лучше начать с базового варианта и осознанно расширять. Spring Security Reference
CORS: когда фронтенд и бэкенд на разных доменах
CORS — это правило браузера, которое ограничивает запросы с одного сайта на другой. Это нужно не для серверов, а для браузеров.
Если у вас фронтенд на https://app.example.com, а API на https://api.example.com, то CORS-настройка может понадобиться.
Минимальное правило:
разрешайте только нужные домены
не используйте «разрешить всем» в продакшенеУправление секретами
Что считать секретом:
пароль базы данных
API-ключи внешних сервисов
секреты подписи токеновПрактика:
храните секреты в переменных окружения
не добавляйте секреты в Git
не печатайте секреты в логиActuator: технические эндпоинты для продакшена
Spring Boot Actuator добавляет эндпоинты для проверки состояния приложения.
Зависимость:
Минимальная настройка, чтобы открыть только health:
Эндпоинт:
GET /actuator/health показывает, что приложение живоВажно:
не открывайте в интернет всё подряд из actuator
открывайте только то, что реально нужноDocker: упаковываем приложение, чтобы оно одинаково запускалось везде
Зачем Docker
Docker-образ — это упакованное приложение со всем, что нужно для запуска. Это решает типичные проблемы:
«у меня локально работает, а на сервере нет»
разные версии Java
сложные инструкции для запускаDockerfile для Spring Boot (через jar)
Предположим, вы собираете jar:
Пример Dockerfile:
Пояснения:
eclipse-temurin:21-jre — образ с JRE для запуска
JAVA_OPTS позволяет добавлять параметры JVM без пересборки образаDocker Compose для приложения и PostgreSQL
Пример docker-compose.yml:
Практические замечания:
depends_on не гарантирует, что база уже готова принимать подключения, он только управляет порядком запуска
миграции Flyway при старте приложения помогают привести схему в нужное состояниеАльтернатива: buildpacks вместо Dockerfile
Spring Boot умеет собирать контейнерный образ без Dockerfile, через buildpacks.
Это удобно, когда вы хотите меньше поддерживать инфраструктурный код.
Смотрите: Spring Boot Reference: Container Images и Cloud Native Buildpacks.
Деплой: минимальный чеклист
Конфигурация деплоя по принципам Twelve-Factor
Хорошее правило для сервисов:
конфигурация живёт вне кода
приложение не зависит от конкретного сервераКороткий ориентир: The Twelve-Factor App.
Что нужно подготовить для продакшена
Ниже — практичный минимум, который подходит для большинства MVP.
Профиль prod включается на уровне окружения
- через
SPRING_PROFILES_ACTIVE=prod.
Секреты приходят из окружения
- пароли, ключи, токены.
Миграции включены
- Flyway применяет миграции на старте.
Health-check доступен инфраструктуре
-
/actuator/health.
Логи пишутся в stdout
- так их проще собирать в Docker/Kubernetes.
Ошибки возвращаются в едином формате
- как мы делали через
GlobalExceptionHandler.
Ничего лишнего не открыто наружу
- actuator не открыт полностью
- Swagger UI в продакшене либо закрыт авторизацией, либо выключен
!Иллюстрация показывает типичную продакшен-схему и где находятся безопасность, логи и health-check
Типичные ошибки при переходе к продакшену
| Ошибка | Почему плохо | Что сделать вместо |
|---|---|---|
| хранить пароли в application-prod.yml в Git | секреты утекут | переменные окружения или секрет-хранилище |
| включить logging.level.root=DEBUG в прод | логи раздуваются и могут утечь данные | INFO, а DEBUG включать точечно |
| открывать все actuator-эндпоинты наружу | можно получить доступ к внутренней информации | открывать минимум, обычно только health |
| отключить Security «на время» | «время» превращается в навсегда | закрыть API базовой схемой и постепенно улучшать |
| использовать ddl-auto: update в прод | схема может измениться непредсказуемо | миграции Flyway + ddl-auto: validate |
Как это связывается с предыдущими статьями курса
Наши DTO, валидация и GlobalExceptionHandler дают стабильный контракт API и понятные ошибки.
JPA, связи и транзакции важны для целостности данных, а Flyway делает изменения базы контролируемыми при деплое.
Сервисный слой и тесты уменьшают риск регрессий перед выкладкой.
Профили, логирование, безопасность, Docker и health-check — это «упаковка» всего сделанного в форму, готовую для реальной эксплуатации.Что дальше изучать после этой статьи
Практичные направления развития после продакшен-минимума:
расширенная авторизация (роли, права, токены)
ограничение частоты запросов (rate limiting) на уровне API gateway или прокси
централизованный сбор логов и метрик
интеграционные тесты с реальной базой через Testcontainers
деплой в Kubernetes (база терминов и стартовая конфигурация)