Заставить скрипт выполняться после запуска сети?

102

Я относительно новичок в systemd и изучаю его архитектуру.

Прямо сейчас я пытаюсь выяснить, как заставить работать собственный скрипт оболочки. Этот сценарий необходимо запустить после запуска сетевого уровня.

Я использую Arch, использую systemd и netctl.

Чтобы проверить, я написал простой скрипт, который просто выполняется ip addr list > /tmp/ip.txt. Я создал следующий служебный файл для этого скрипта.

(/etc/systemd/system/test.service)
[Unit]
Description=test service

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Затем я включил сценарий,

systemctl enable test

После перезапуска скрипт действительно запускается, но он запускается до запуска сети. Другими словами, в выводе ip.txtне отображается IPv4-адрес, назначенный первичному интерфейсу. Ко времени входа в систему адрес IPv4 уже был назначен, и сеть работает.

Я предполагаю, что мог бы изменить точку запуска сценария, связавшись с WantedByпараметром, но я не уверен, как это сделать.

Может ли кто-нибудь указать мне правильное направление?

fdmillion
источник

Ответы:

126

На зависимости конфигурации сети systemd

Это очень легко повлияет на порядок юнитов systemd. С другой стороны, вы должны быть осторожны с тем, что гарантирует законченный блок.

Настройте свой сервис

В современных системах заказ после network.targetгарантирует только то, что сетевой сервис запущен, а не то, что есть какая-то фактическая конфигурация. Вы должны сделать заказ после network-online.targetи потянуть его, чтобы добиться этого.

[Unit]
Wants=network-online.target
After=network-online.target

Для совместимости со старыми системами вам, возможно, придется заказывать и после network.target.

[Unit]
Wants=network-online.target
After=network.target network-online.target

Это для файла модуля вашего сервиса и для systemd.

Реализация в текущих версиях программного обеспечения

Теперь вам нужно убедиться, что он network-online.targetработает как положено (или что вы, по крайней мере, можете его использовать network.target).

Текущая версия NetworkManager предлагает то, NetworkManager-wait-online.serviceчто получает network-online.targetи, следовательно, ваш сервис. Эта специальная служба гарантирует, что ваша служба будет ожидать, пока все подключения, настроенные для автоматического запуска, успешно завершатся, завершатся неудачно или истечет время ожидания.

Текущая версия systemd-networkd блокирует вашу службу, пока все устройства не будут настроены в соответствии с запросом. Это проще в том, что в настоящее время он поддерживает только те конфигурации, которые применяются во время загрузки (более конкретно, время запуска `systemd-networkd.service).

Для полноты картины /etc/init.d/networkсервис в Fedora, интерпретируемый текущими версиями systemd, блокирует network.targetи, таким образом, косвенно блокирует network-online.targetи ваш сервис. Это пример реализации на основе сценариев.

Если ваша реализация, будь то на основе демонов или на основе сценариев, ведет себя как одна из вышеперечисленных служб управления сетью, она будет задерживать запуск вашей службы до тех пор, пока конфигурация сети не будет успешно завершена, не удастся по уважительной причине или не истечет время ожидания по истечении разумного времени. кадр для завершения.

Вы можете проверить, работает ли netctl таким же образом, и эта информация была бы ценным дополнением к этому ответу.

Реализации в старых версиях программного обеспечения

Я не думаю, что вы увидите достаточно старую версию systemd, где это не сработает. Но вы можете проверить, что, по крайней мере, network-online.targetсуществует, и что он заказан после network.target.

Ранее NetworkManager гарантировал, что будет применено хотя бы одно соединение. И даже для того, чтобы это работало, вы должны были включить NetworkManager-wait-online.serviceявно. Это давно исправлено в Fedora, но только недавно было применено в апстриме.

systemctl enable NetworkManager-wait-online.service

Замечания о реализации network.target и network-online.target

Вы не должны когда - нибудь понадобится , чтобы сделать ваше программное обеспечение зависит от NetworkManager.serviceили NetworkManager-wait-online.serviceни каких - либо других конкретных услуг. Вместо этого все сервисы управления сетью должны заказывать себя раньше network.targetи, по желанию network-online.target.

Простой сервис управления сетью, основанный на сценариях, должен завершить настройку сети перед выходом из системы и упорядочить ее до network.targetи, следовательно, косвенно network-online.target.

[Unit]
Before=network.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

Служба управления сетью на основе демона также должна сначала упорядочить себя, network.targetдаже если она не очень полезна.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Служба, которая ожидает завершения работы демона, должна оформлять заказ после определенной службы и до нее network-online.target. Его следует использовать Requisiteв службе демона, чтобы он сразу же завершился сбоем, если соответствующая служба управления сетью не используется.

[Unit]
Requisite=...
After=...
Before=network-online.target

[Service]
Type=oneshot
ExecStart=...
RemainAfterExit=yes

Пакет должен установить символическую ссылку на ожидающую службу в wantsкаталоге, network-online.targetчтобы его доставили службы, которые хотят дождаться настроенной сети.

ln -s /usr/lib/systemd/system/... /usr/lib/systemd/system/network-online.target.wants/

Сопутствующая документация

Финальные заметки

Я надеюсь, что я не только помог ответить на ваш вопрос в то время, когда вы его задавали, но также способствовал улучшению ситуации в дистрибутивах upstream и Linux, так что теперь я могу дать лучший ответ, чем это было возможно во время написания оригинального ,

Павел Шимерда
источник
Вы имеете в виду опцию автоматического подключения: «дождаться, пока все подключения, настроенные для автоматического запуска, будут успешными»? Могу ли я использовать это, когда я установил no-auto-default = *, но у меня есть autoconnect = yes на одном из моих подключений? И последний вопрос - я не понимаю, - опция «ждать запуска» на странице nm-online и страница руководства не сильно помогают. Спасибо за эту рецензию, высоко ценится!
lzap
Насколько я знаю, nm-online не волнует no-auto-defaultтолько auto. У вас есть конкретный вопрос? По моему мнению, man-страница nm-online четко заявляет, что при этом -sона ожидает всех попыток автоматического подключения, то есть подключения или сбоя.
Павел Шимерда
Поработав с этим дерьмом в течение часа, я нашел решение: apt-get install sysv-init. :-) Сложность, которую systemd добавляет в качестве замены для нескольких сценариев оболочки, поражает воображение.
Кто-то
@ Кто-то, я боюсь, что initscripts не является ответом в этом случае. Если вы используете NetworkManager или любой другой инструмент динамической настройки, начальные скрипты не могут упорядочиться после полностью настроенной сети. Вы можете получить ограниченную динамическую конфигурацию, используя /etc/init.d/networkили подобное, но это не работает универсально.
Павел Шимерда
@Pavel Šimerda Init выполняется последовательно, и правильный сценарий init не вернется, пока не выполнит то, на что должны опираться последующие сценарии. Для работы в сети это означало бы, что все применимые адаптеры готовы и готовы. Если только это не было просто удачное время, НМ ведет себя хорошо в этом контексте. Конечно, реальная проблема заключается в том, что NM заново изобретает сетевую обработку вместо того, чтобы опираться на существующие простые и проверенные структуры. Люди, работающие на рабочем столе, похоже, не понимают опасности сложности. ;-)
Кто-то
9

Вы можете использовать Afterв [Unit]разделе, чтобы определить службу, которая должна быть запущена до запуска вашей службы. Например, если вы используете NetworkManager, вы можете запустить службу после запуска NetworkManager.

[Unit]
Description=test service
After=NetworkManager.service
phoops
источник
BindsToздесь не очень уместно, так как сервис является одноразовым событием, а не постоянным сервисом (если только он не включает в себя ExecStopфункцию, которая срабатывает при прекращении работы сети).
Златовласка
удаленоBindsTo
phoops
Вы можете добавить что-нибудь для замены BindsTo, например, Requiresесли хотите, чтобы служба работала только в том случае, если это делает NetworkManager. Afterна самом деле не делает этого - это просто означает, что если NM также работает, то запустите это позже. Если NM не будет запущен, служба будет запущена в произвольной точке.
Златовласка
4
After = network.target лучше, чем After = NetworkManager.service, поскольку он более общий.
Павел Шимерда
7
Обратите внимание на то, что задающий After=fooбудет не вызывать fooблок , чтобы начать , если он еще не запущен, он будет только сказать Systemd , как заказать единицы , если они оба начали одновременно . Использование обоих, After=fooа также Wants=fooили Requires=fooбудет иметь эффект подтягивания, fooесли оно не запущено, а также правильное упорядочение юнитов.
Эмиль Лундберг
8

Если ваша служба предоставляет сервер, который может пассивно ждать, пока кто-то подключится к нему, используйте это:

[Unit]
After=network.target

Ваш сервис должен связываться с подстановочным интерфейсом. Если он использует активацию сокета (рекомендуется), или если он только локальный, вы можете полностью игнорировать сетевые цели.

Если ваша служба действует как клиент или одноранговая, это более уместно:

[Unit]
After=network-online.target
Requires=network-online.target

До появления systemd 213 network-online.target требуется обходной путь, о котором упоминал Павел (вам нужно вручную включить службу, которая будет ожидать подключения к сети). Начиная с systemd 213 это делается по умолчанию. systemd-networkd-wait-onlineбудет ожидать, что хотя бы один адрес (либо маршрутизируемый, либо локальный для канала) будет настроен на интерфейсе без обратной связи.

Настройка systemd-networkd, NetworkManager или его эквивалента является независимой задачей. DHCP (для IPv4) и NDP (для IPv6), как правило, работают «из коробки», но вы должны настроить их так, чтобы ваше точное определение «сеть работала» - это то, что вызывает network-online.target.

Документация:

Tobu
источник
Просто любопытно, почему новый ответ, а не просто небольшие улучшения существующего и (надеюсь) хорошо структурированного ответа.
Павел Шимерда
Первые две ссылки на Документацию в настоящее время не работают.
Питер Хансен
Зачем использовать Требуется вместо Хотите?
Карл Моррисон
4

Я предполагаю, что я мог бы изменить точку запуска сценария, связавшись с параметром WantedBy

Это будет иметь эффект, противоположный тому, что вы хотите. От man systemd.unit:

WantedBy =, RequiredBy =

[...] Символическая ссылка создается в каталоге .wants / или .requires / каждого из перечисленных модулей, когда этот модуль установлен с помощью systemctl enable. Это приводит к тому, что зависимость типа Wants = или Требуется = добавляется из указанного блока в текущий блок .

Исходя из этого, мы можем видеть, что правильной единицей измерения является «Хочет» или «Требуется»; исходя из их описания, «Требуется», вероятно, является правильным, с добавлением «После», чтобы обеспечить не только запуск сетевой службы, но и ее запуск перед этим устройством.

Ни одна из опций модуля, AFAIK, не может включать условие о том, что запущенный завершающий компонент должен быть завершен или достиг определенной точки (сетевое взаимодействие, вероятно, является сервисом демона), только то, что он запускается первым. Имея это в виду, вы можете захотеть сделать свой сценарий Type=forkingи добавить работоспособную задержку (скажем, 30 секунд), или какой-то цикл выхода при успехе, включая задержку, чтобы убедиться, что у вас сначала есть аренда DHCP.

лютик золотистый
источник
1
Ни WantedBy, ни RequiredBy не влияют на порядок.
Павел Шимерда
1
@ PavelŠimerda: Никто здесь не утверждал, что они сделали. Упорядочение - это то, почему я прямо упомянул Afterв связи с Requires«чтобы не только запустить сетевой сервис, но и запустить его перед этим устройством».
Златовласка
1
Да, Afterработает вместе с тем Wantsили Requiresиным образом. С другой стороны, явные задержки являются плохой привычкой в ​​инструментах, основанных на зависимостях, особенно когда есть явный способ ждать, пока сеть не будет настроена, как указано в документации systemd, поэтому я должен настаивать на понижении.
Павел Шимерда
3

Используйте Afterв [Unit]разделе, чтобы указать, что должно быть запущено перед вашим собственным сервисом. (Это большая часть предыдущего ответа верна.)

Чтобы запустить службу после подключения к сети, используйте цель сети, которая должна применяться независимо от того, используете ли вы NetworkManager, систему conf.d / netctl в Arch или какую-либо другую службу, известную systemd.

[Unit]
#.....
After=network.target

Краткий обзор подтвердит, что каждая другая служба в вашей системе, которая зависит от сетевого подключения, содержит эту директиву.

Он также переносим на любой дистрибутив, который использует systemd. Ваш файл модуля будет одинаковым для Arch, Fedora, RHEL 7, будущих версий Debian ...


Службы, которые запускают сетевое соединение, такие как сценарии Arch или ваши собственные, должны указывать это в своих собственных файлах модулей.

[Unit]
Wants=network.target
Before=network.target
Майкл Хэмптон
источник
Мне не совсем нравится эта Wantsчасть, потому что она имеет побочные эффекты на других пакетах. Посмотрите на мой ответ, пожалуйста.
Павел Шимерда
Просто понял , что Wantsна network.targetэто хорошая идея здесь.
Павел Шимерда
Вы действительно хотите использовать network-online.target. ref
Эдвард Торвальдс,
1

Я хотел добавить пункт к этой статье. В настоящее время (лето 2015 г.) в RHEL7 / CentOS 7, network-online.target неправильно установлен до запуска сети IPv6, поэтому демоны, которые имеют

Wants=network-online.target
After=network-online.target

в их определении службы, которое также явно связывается с адресами IPv6, вероятно, будет запущено до того, как IPv6 будет запущен, что приведет к их отказу.

Colo Host
источник
Я предполагаю, что это имеет место только с автоматической настройкой IPv6 на основе ядра, которая в любом случае имеет недостатки. Если вы хотите правильно заказать после IPv6, вы должны обязательно использовать NetworkManager вместо /etc/init.d/network. Если вы столкнетесь с той же проблемой даже с NM, то это будет хорошим поводом для подачи запроса на функцию. Я не проверял с RHEL / CentOS, я могу помочь вам с деталями, если вам интересно.
Павел Шимерда
0
[Unit]
After=systemd-networkd.service

работает для меня.

Женсяо Хао
источник
Не уверен, что это работает в некоторых особых случаях, но это неправильно по нескольким причинам. Одним из них является то, что networkdпредоставляет свой собственный / ожидание онлайн / сервис. Выдвижение и заказ после network-online.target- это правильный путь для любого сервиса, который поддерживает это.
Павел Шимерда