Вопрос или проблема
Мне интересно, как работает мой ansible playbook и как ведет себя ssh. С Ubuntu 22 изменили способ запуска ssh-сервиса и, соответственно, его поведение при использовании ListenAdress
в /etc/ssh/sshd_config
https://discourse.ubuntu.com/t/sshd-now-uses-socket-based-activation-ubuntu-22-10-and-later/30189
Поэтому я хочу использовать “старое” поведение и создал две задачи в ansible для достижения этой цели – деактивировать ssh.socket
и активировать ssh.service
.
Но я получил непоследовательное поведение. Я пробовал снова и снова с перестроенными виртуальными машинами на Hetzner, иногда все работает хорошо, иногда меня выкидывает. Мои задачи выглядят так:
- name: ssh | Использовать старое поведение
when: ansible_distribution_version is version('22.04', '>=')
block:
- name: ssh | Отключить службу ssh.socket
ansible.builtin.systemd_service:
name: ssh.socket
state: stopped
enabled: false
- name: ssh | Включить службу ssh.service
ansible.builtin.systemd_service:
name: ssh.service
state: started
enabled: true
Когда я смотрю в логи, я вижу:
systemd[1]: ssh.service: Найден остаточный процесс 1119 (sshd) в контрольной группе при запуске единицы. Игнорируется.
systemd[1]: ssh.service: Обычно это указывает на некорректное завершение предыдущего запуска или недостатки в реализации службы.
sshd[2769]: ошибка: Привязка к порту 22 на 0.0.0.0 не удалась: Адрес уже используется.
sshd[2769]: фатальная ошибка: Невозможно привязать любой адрес.
systemd[1]: ssh.service: Основной процесс завершился, код=exited, статус=255/EXCEPTION
Но это происходит не каждый раз, поэтому, может быть, кто-то знает, что происходит, когда все работает, а когда нет?
Я добавляю вывод netsta -tulpn
, когда это работало:
tcp6 0 0 :::22 :::* LISTEN 1116/sshd: /usr/sbi
и когда это не работало.
tcp6 0 0 :::22 :::* LISTEN 1108/sshd: /usr/sbi
Это было зафиксировано до того, как я действительно перезапустил демон ssh
.
Ответ или решение
Проблема с состоянием гонки при использовании SSH в Ubuntu 24.04
Ваша проблема связана с изменениями, введенными в управлении службой SSH в Ubuntu 22.10 и более поздних версиях, которые теперь используют активацию по сокетам (socket-based activation
). Давайте разберемся в сути происходящего и выясним, почему вы сталкиваетесь с проблемами при переключении на старое поведение службы SSH.
Что такое активация по сокетам?
Активация по сокетам позволяет системным службам запускаться по мере необходимости, когда приходит запрос на обслуживание. В случае SSH это означает, что служба ssh.socket
может автоматически запускать ssh.service
при попытке подключения.
Действия, выполняемые с помощью Ansible
Вы предпринимаете попытки отключить ssh.socket
и запустить ssh.service
через Ansible, чтобы воссоздать прежнее поведение. Ваш блок задач выглядит следующим образом:
- name: ssh | Use old behaviour
when: ansible_distribution_version is version('22.04', '>=')
block:
- name: ssh | Disable ssh.socket service
ansible.builtin.systemd_service:
name: ssh.socket
state: stopped
enabled: false
- name: ssh | Enable ssh.service service
ansible.builtin.systemd_service:
name: ssh.service
state: started
enabled: true
Причины непостоянного поведения
Ваша проблема с непостоянным поведением при включении и отключении служб может быть связана с состоянием гонки (race condition) между процессами sshd
, как видно из логов:
error: Bind to port 22 on 0.0.0.0 failed: Address already in use.
Это сообщение об ошибке указывает на то, что при попытке запуска ssh.service
служба уже была активной, и другой экземпляр sshd
уже слушает тот же порт, что приводит к ошибке биндинга.
Почему это происходит?
-
Асинхронные операции: Когда вы останавливаете
ssh.socket
, процесс разрывается, ноsystemd
может еще не успеть полностью освободить ресурсы, связанные с этим сокетом, прежде чем вы пытаетесь запуститьssh.service
. Это приводит к конфликту, когда управление уже заведомо недоступно для нового экземпляра службы. -
Состояние системы: Если ваша система в данный момент обрабатывает несколько операций или имеется высокая нагрузка, это может увеличить время, необходимое для очищения ресурсов, что также служит причиной гонки.
Рекомендации по исправлению
Чтобы предотвратить возникновение состояния гонки и добиться более предсказуемого поведения, вы можете внести некоторые изменения в ваши Ansible задачи.
- Используйте задержки: Вставьте задержку между остановкой
ssh.socket
и запускомssh.service
:
- name: ssh | Disable ssh.socket service
ansible.builtin.systemd_service:
name: ssh.socket
state: stopped
enabled: false
- name: Wait for SSH socket to stop
ansible.builtin.pause:
seconds: 1
- name: ssh | Enable ssh.service service
ansible.builtin.systemd_service:
name: ssh.service
state: started
enabled: true
-
Проверьте состояния: Убедитесь, что оба сервиса действительно остановлены перед запуском нового экземпляра. Вы можете использовать модуль
ansible.builtin.systemd
для проверки статуса. -
Логи и отладка: Всегда полезно проверять системные логи на наличие конфликтующих сообщений при отладке, например, с помощью
journalctl -u ssh.service
.
Заключение
Состояние гонки в вашей конфигурации Ansible для службы SSH связано с асинхронной природой остановки и услуги обработки. Применив рекомендации, вышеупомянув, вы должны увидеть улучшение в предсказуемости запуска SSH-сервиса на вашей системе Ubuntu 24.04.