Address already in use при socket activation: кто должен открывать порт

Для приложения добавили socket-unit, чтобы systemd держал слушающий порт и запускал сервис при обращении. Сокет активен, но приложение немедленно завершается с Address already in use. Порт действительно занят — самим менеджером служб. Значит, одновременно используются два несовместимых способа запуска: переданный дескриптор и самостоятельное открытие того же адреса.

При обычном запуске сервер вызывает bind и listen сам. При socket activation эти действия выполняет systemd, а приложение должно принять уже открытый сокет через поддерживаемый протокол. Одного файла с расширением .socket недостаточно, чтобы произвольный сервер изменил поведение. Сначала проверьте, умеет ли конкретная программа работать с активацией и какие аргументы ей нужны.

Согласовать socket и service

У обычной схемы Accept=no один service получает слушающий сокет и сам обслуживает подключения. Имя service по умолчанию соответствует имени socket. Минимальная сторона менеджера для локального TCP-порта выглядит так:

# catalog.socket
[Socket]
ListenStream=127.0.0.1:8087
Accept=no

[Install]
WantedBy=sockets.target

Далее catalog.service должен запускать программу в её режиме socket activation. Не добавляйте обычный параметр --port 8087 по привычке: в некоторых приложениях он включает самостоятельный bind. Точное имя режима берётся из документации сервера. Если программа его не поддерживает, оставьте обычную службу без socket-unit — её запуск и готовность можно контролировать другими средствами.

Accept=yes означает другой контракт: на каждое соединение создаётся экземпляр шаблонной службы. Это подходит для программ, работающих с одним соединением, а не является универсальным исправлением ошибки bind у постоянного HTTP-сервера. Смена этого параметра требует изменения service и способа передачи соединения.

Проверять владельца порта и путь запроса

На стенде сначала посмотрите systemctl status catalog.socket и ss -ltnp для нужного адреса. Владельцем слушающего сокета может отображаться systemd — это ожидаемо. Затем отправьте запрос и проверьте, что активируется catalog.service и приложение отвечает. Наличие LISTEN само по себе ещё не показывает, что прикладной протокол работает.

Полезно проверить повторный запуск приложения при оставшемся активным сокете. Он должен снова принять переданный дескриптор, а не пытаться открыть адрес заново. Если остановить только service, следующий входящий запрос может активировать его опять. Для плановых работ это важно: когда нужно прекратить приём запросов, остановки одного процесса бывает недостаточно, нужно учитывать и socket-unit.

В инструкции к сервису зафиксируйте, кто открывает порт, кто принимает соединения и какими units управляют во время обслуживания. Тогда инженер не будет «освобождать» корректно занятый systemd порт и случайно ломать рабочую схему активации.

Продолжить практику

За одной настройкой unit обычно стоит весь путь сопровождения приложения: отдельный пользователь, права на данные, сеть, журналы и повторяемые операции. В программе курса «Linux и Bash для DevOps-инженеров» эти задачи собраны вокруг учебного сервера с приложением под systemd. В практике предусмотрены Bash-скрипты проверки состояния и резервного копирования, а также runbook для воспроизводимых поломок. Это подходящее продолжение, если хочется связать отдельные команды в понятный порядок диагностики.

Посмотреть программу курса

Источник: официальная документация.

Другие задачи по теме: Запуск и жизненный цикл служб systemd.

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.