Сокет и служба включены одновременно: конфликт при загрузке
Если служба и её сокет оба включены в автозапуск, при загрузке они конкурируют за адрес. Кто успел, того и порт: вторая попытка даёт ошибку о занятом адресе. При сокет-активации в автозапуске должен быть только сокет.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Служба включена вместе с сокетом
Обе ссылки автозапуска существуют, и systemd поднимает оба unit. Порядок между ними не задан, поэтому сбой случается не каждый раз — это и делает проблему запутанной.
-
Служба тянется зависимостью другого unit
Даже отключённая служба поднимется, если её требует кто-то ещё через
Requires=илиWants=.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Показывает состояние автозапуска обоих unit одной командой.
systemctl is-enabled myapp.socket myapp.serviceПорядок событий при загрузке: видно, кто занял порт первым.
journalctl -b -u myapp.socket -u myapp.service --no-pager | head -30Решение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Обе ссылки автозапуска существуют, и systemd поднимает оба unit. Порядок между ними не задан, поэтому сбой случается не каждый раз — это и делает проблему запутанной.
- Как проверить
-
Посмотрите состояния включения обоих unit.
systemctl is-enabled myapp.socket myapp.service
- Как исправить
-
Оставьте в автозапуске только сокет.
sudo systemctl disable myapp.service && sudo systemctl enable --now myapp.socket
- Почему происходит
- Даже отключённая служба поднимется, если её требует кто-то ещё через
Requires=илиWants=.
- Как проверить
-
Посмотрите, кто зависит от службы.
systemctl list-dependencies --reverse myapp.service --no-pager | head
- Как исправить
-
Замените зависимость на сокет: другие unit должны требовать
myapp.socket, а не саму службу.
Пример вывода
Сокет не смог занять адрес, потому что служба стартовала раньше. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
systemd[1]: Started myapp.service - My application.
systemd[1]: myapp.socket: Failed to listen on sockets: Address already in use
systemd[1]: myapp.socket: Failed with result 'resources'.
systemd[1]: Failed to listen on myapp.socket - Socket for myapp.
Связанные ошибки
- Служба не получает сокет при сокет-активации Сокет активен, служба запускается, но не находит переданный дескриптор. Разбор: Accept, FileDescriptorName, соответствие имён.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Сокет без Listen: unit загружен, но ничего не слушает В .socket не задан ни один параметр Listen…= — сокет не принимает соединения. Как объявить адрес прослушивания.
- Bad file descriptor в журнале службы Ошибка 9 при операции с файлом: дескриптор закрыт или не тот. Разбор для служб и сокет-активации.
- File exists при создании файла или сокета Ошибка 17: объект уже существует. Разбор для сокетов, файлов блокировки и каталогов службы.
- MySQL: Can't connect to local server through socket Клиент не находит unix-сокет MySQL: сервер не запущен, путь к сокету другой, каталог в /run не создан.
- Puma слушает сокет, а веб-сервер получает отказ доступа Разъём между приложением и веб-сервером: сокет создаётся с правами приложения, читает его другой пользователь.
- Unit is masked: служба запрещена к запуску Сообщение Unit is masked: unit заблокирован ссылкой на /dev/null. Как найти и снять маскировку.
Источники
-
systemd.socket(5)
Связь сокета и службы, порядок активации. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено включением обоих unit в автозапуск на тестовой машине.