Как выбрать порт для сервиса и почему
Что проверяют
Знаете ли вы, откуда берутся ограничения на номер порта и что в продакшене его чаще выбирает инфраструктура, а не разработчик. Следом обычно спрашивают, что будет, если порт уже занят, и как поднять несколько экземпляров сервиса на одной машине.
Как отвечать
Начните с диапазонов, закреплённых IANA:
- системные, от 0 до 1023: отданы стандартным протоколам (80 HTTP, 443 HTTPS, 22 SSH). В Linux слушать их может только root или процесс с
CAP_NET_BIND_SERVICE, поэтому Java-сервис на них не сажают; - зарегистрированные, от 1024 до 49151: здесь привычные 8080, 5432 у PostgreSQL, 9092 у Kafka. Порт своего сервиса берут отсюда, проверив, что он не пересекается с соседями;
- динамические, от 49152 до 65535: из них ОС раздаёт эфемерные порты исходящим соединениям. В Linux диапазон свой, по умолчанию от 32768 до 60999 (
net.ipv4.ip_local_port_range), и фиксированный порт сервиса туда не ставят: его может занять чужое исходящее соединение.
В Spring Boot порт задаёт server.port, по умолчанию 8080, и приходит он из конфигурации или переменной SERVER_PORT, а не из кода. server.port=0 берёт случайный свободный порт, это удобно в тестах вместе с @SpringBootTest(webEnvironment = RANDOM_PORT) и @LocalServerPort. Actuator можно вынести на отдельный management.server.port, чтобы health и метрики не торчали наружу.
В контейнере и Kubernetes у каждого пода своё сетевое пространство, поэтому приложение спокойно слушает 8080, а наружу на 443 его публикуют Service и Ingress. Конфликт портов остаётся проблемой на общем хосте: он проявляется как java.net.BindException: Address already in use, а виновника ищут через ss -ltnp или lsof -i :8080.
Где спотыкаются
Считают нестандартный порт мерой безопасности. Сканер находит открытый порт за минуты, защищают TLS, файрвол и аутентификация, а не номер.
Запускают JVM от root ради 80 или 443. Правильно слушать 8080, а на 443 поставить обратный прокси или балансировщик, который заодно терминирует TLS.
Зашивают порт в код или образ. Потом два экземпляра не поднимаются на одном хосте, а тесты на CI падают с BindException, потому что рядом идёт другая сборка.