Czy skrypt ma zostać wykonany po uruchomieniu sieci?


102

Jestem stosunkowo nowy w systemd i uczę się jego architektury.

W tej chwili próbuję wymyślić, jak uruchomić niestandardowy skrypt powłoki. Ten skrypt musi zostać uruchomiony po uruchomieniu warstwy sieciowej.

Korzystam z Arch, używając zarówno systemd, jak i netctl.

Aby przetestować, napisałem prosty skrypt, który po prostu się uruchamia ip addr list > /tmp/ip.txt. Utworzyłem następujący plik usługi dla tego skryptu.

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

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Następnie włączyłem skrypt za pomocą,

systemctl enable test

Po zrestartowaniu skrypt rzeczywiście działa, ale działa przed uruchomieniem sieci. Innymi słowy, wyjście w ip.txtnie wyświetla adresu IPv4 przypisanego do interfejsu głównego. Do czasu zalogowania adres IPv4 rzeczywiście został przypisany i sieć działa.

Zgaduję, że mógłbym zmienić punkt, w którym skrypt działa, mieszając się z WantedByparametrem, ale nie jestem pewien, jak to zrobić.

Czy ktoś może skierować mnie w dobrym kierunku?

Odpowiedzi:


126

Zależności konfiguracji systemowej sieci

Bardzo łatwo jest wpłynąć na kolejność jednostek systemd. Z drugiej strony musisz uważać na to, co gwarantuje ukończona jednostka.

Skonfiguruj swoją usługę

W obecnych systemach zamawianie po network.targetprostu gwarantuje, że usługa sieciowa została uruchomiona, a nie faktyczną konfigurację. Aby network-online.targetto osiągnąć, musisz złożyć zamówienie później i pociągnąć.

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

Aby zachować zgodność ze starszymi systemami, konieczne może być zamówienie również po network.target.

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

To jest dla pliku jednostkowego twojej usługi i dla systemd.

Wdrożenie w aktualnych wersjach oprogramowania

Teraz musisz się upewnić, że network-online.targetdziała zgodnie z oczekiwaniami (lub przynajmniej możesz użyć network.target).

Obecna wersja NetworkManager oferuje to, NetworkManager-wait-online.serviceco jest pobierane przez, network-online.targeta zatem przez twoją usługę. Ta specjalna usługa zapewnia, że ​​usługa będzie czekać, aż wszystkie połączenia skonfigurowane do automatycznego uruchomienia zostaną pomyślnie zakończone, zakończone niepowodzeniem lub przekroczą limit czasu.

Obecna wersja systemd-networkd blokuje twoją usługę, dopóki wszystkie urządzenia nie zostaną skonfigurowane zgodnie z żądaniem. Jest to łatwiejsze, ponieważ obecnie obsługuje tylko konfiguracje, które są stosowane podczas rozruchu (a dokładniej czas uruchomienia `systemd-networkd.service).

Ze względu na kompletność, /etc/init.d/networkusługa w Fedorze, zgodnie z interpretacją bieżących wersji systemd, blokuje, network.targeta zatem pośrednio bloki network-online.targeti twoją usługę. To przykład implementacji opartej na skryptach.

Jeśli implementacja, niezależnie od tego, czy jest oparta na daemonie, czy na skryptach, zachowuje się jak jedna z powyższych usług zarządzania siecią, opóźni uruchomienie usługi do momentu pomyślnego ukończenia konfiguracji sieci, niepowodzenia z uzasadnionego powodu lub przekroczenia limitu czasu po rozsądnym czasie. ramka do ukończenia.

Możesz sprawdzić, czy netctl działa w ten sam sposób i czy ta informacja byłaby cennym dodatkiem do tej odpowiedzi.

Implementacje w starszych wersjach oprogramowania

Nie sądzę, żebyś zobaczył wystarczająco starą wersję systemd, w której nie działałoby to dobrze. Ale możesz sprawdzić, czy przynajmniej network-online.targetistnieje i że zostanie zamówiony później network.target.

Poprzednio NetworkManager gwarantował, że zostanie zastosowane co najmniej jedno połączenie. I nawet aby to zadziałało, trzeba by to NetworkManager-wait-online.servicewyraźnie włączyć . Zostało to od dawna naprawione w Fedorze, ale zostało niedawno zastosowane wcześniej.

systemctl enable NetworkManager-wait-online.service

Uwagi dotyczące implementacji network.target i network-online.target

Nie powinny kiedykolwiek trzeba zrobić oprogramowania zależą NetworkManager.serviceani NetworkManager-wait-online.serviceani żadnych innych konkretnych usług. Zamiast tego wszystkie usługi zarządzania siecią powinny zamawiać się przed network.targeti opcjonalnie network-online.target.

Prosta usługa zarządzania siecią oparta na skryptach powinna zakończyć konfigurację sieci przed wyjściem i powinna zamówić się przed, network.targeta zatem pośrednio przed network-online.target.

[Unit]
Before=network.target

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

Usługa zarządzania siecią oparta na demonie powinna również zamówić się wcześniej, network.targetnawet jeśli nie jest to bardzo przydatne.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Usługa, która czeka na zakończenie działania demona, powinna zamówić się po określonej usłudze i wcześniej network-online.target. Powinien być używany Requisitew usłudze demona, aby natychmiast przestał działać, jeśli dana usługa zarządzania siecią nie jest używana.

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

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

Pakiet powinien zainstalować dowiązanie symboliczne do usługi oczekiwania w wantskatalogu network-online.target, aby było pobierane przez usługi, które chcą czekać na skonfigurowaną sieć.

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

Powiązana dokumentacja

Uwagi końcowe

Mam nadzieję, że nie tylko pomogłem odpowiedzieć na twoje pytanie w momencie, w którym je zadałeś, ale również przyczyniłem się do poprawy sytuacji w dystrybucji upstream i Linuksie, dzięki czemu mogę teraz udzielić lepszej odpowiedzi niż było to możliwe w momencie pisania oryginalnej .


Czy masz na myśli opcję automatycznego łączenia przez „poczekaj, aż wszystkie połączenia skonfigurowane do automatycznego uruchomienia się powiodą”? Czy mogę to wykorzystać, gdy ustawię no-auto-default = *, ale mam jedno połączenie automatyczne na jednym z moich połączeń? I ostatnie pytanie - nie rozumiem - opcja czekania na uruchomienie strony nm-online i strony podręcznika niewiele pomaga. Dziękujemy za ten list, bardzo mile widziane!
lzap

O ile mi wiadomo, nm-online nie obchodzi no-auto-default, tylko auto. Czy masz jakieś konkretne pytanie? Moim zdaniem strona internetowa nm-online wyraźnie stwierdza, że ​​wraz z -snią czeka na próbę nawiązania wszystkich automatycznych połączeń, tj. Połączenia lub awarii.
Pavel Šimerda

Po tym, jak przez godzinę bawiłem się tym gównem, znalazłem rozwiązanie: apt-get install sysv-init. :-) Złożoność dodana przez system jako zamiennik kilku skryptów powłoki jest zadziwiająca.
Ktoś

@Ktoś obawiam się, że skrypty nie są w tym przypadku odpowiedzią. Jeśli korzystasz z NetworkManager lub innego narzędzia do dynamicznej konfiguracji, skrypty startowe nie mogą zamawiać się po pełnej konfiguracji sieci. Możesz uzyskać ograniczoną konfigurację dynamiczną za pomocą /etc/init.d/networklub podobnego, ale to nie działa uniwersalnie.
Pavel Šimerda

@Pavel Šimerda Init wykonuje się szeregowo, a odpowiedni skrypt startowy nie powróci, dopóki nie zakończy działania, na którym muszą polegać kolejne skrypty. Dla sieci oznacza to, że wszystkie odpowiednie adaptery są gotowe i gotowe. O ile nie był to po prostu szczęśliwy moment, NM zachowuje się dobrze w tym kontekście. Prawdziwym problemem jest oczywiście wynalezienie obsługi sieci NM zamiast korzystania z istniejących, prostych i sprawdzonych struktur. Ludzie pulpitu wydają się nie mieć pojęcia o niebezpieczeństwie złożoności. ;-)
Ktoś

9

Możesz użyć Afterw [Unit]sekcji, aby zdefiniować usługę, która powinna zostać uruchomiona przed uruchomieniem usługi. Na przykład, jeśli używasz NetworkManagera, możesz uruchomić usługę po uruchomieniu NetworkManagera.

[Unit]
Description=test service
After=NetworkManager.service

BindsTonie jest tu tak właściwe, ponieważ usługa jest zdarzeniem jednorazowym, a nie usługą trwałą (chyba że zawiera również ExecStopfunkcję uruchamiania po awarii sieci).
goldilocks

usuniętoBindsTo
phoops

Możesz jednak dodać coś do zastąpienia BindsTo, np. RequiresJeśli chcesz, aby usługa była uruchamiana tylko wtedy, gdy robi to NetworkManager. Aftertak naprawdę nie robi tego - oznacza to tylko, że NM również działa, a następnie uruchom to później. Jeśli NM nie zostanie uruchomiony, usługa zostanie uruchomiona w dowolnym punkcie.
goldilocks

4
After = network.target jest lepszy niż After = NetworkManager.service, ponieważ jest bardziej ogólny.
Pavel Šimerda

7
Zauważ, że określającą After=foobędzie nie powodują, że foourządzenie, aby rozpocząć, jeśli nie jest już uruchomiony, to będzie tylko powiedzieć Systemd jak zamówić jednostek jeśli oba są uruchamiane w tym samym czasie . Używanie zarówno, After=foojak i Wants=foolub Requires=foobędzie skutkować wciągnięciem, foojeśli nie zostanie uruchomione, a także sprawi, że system uporządkuje jednostki poprawnie.
Emil Lundberg,

8

Jeśli twoja usługa zapewnia serwer, który może biernie czekać na połączenie z kimś, użyj tego:

[Unit]
After=network.target

Twoja usługa powinna być powiązana z interfejsem wieloznacznym. Jeśli używa aktywacji gniazda (zalecane) lub jeśli jest tylko lokalna, możesz całkowicie zignorować cele sieciowe.

Jeśli Twoja usługa działa jako klient lub jest peer to peer, jest to bardziej odpowiednie:

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

Przed systemd 213 , network-online.target wymaga obejścia wspomnianego Pavela (musisz ręcznie włączyć usługę, która będzie czekać na uruchomienie sieci). Od wersji 213 jest to wykonywane domyślnie. systemd-networkd-wait-onlinebędzie czekał na skonfigurowanie co najmniej jednego adresu (routowalnego lub lokalnego) dla interfejsu bez sprzężenia zwrotnego.

Konfigurowanie systemd-networkd, NetworkManager lub równoważnego jest niezależnym zadaniem. DHCP (dla IPv4) i NDP (dla IPv6) zwykle działają od razu po wyjęciu z pudełka, ale należy je skonfigurować tak, aby wyzwoliła się precyzyjna definicja „sieci nie działa” network-online.target.

Dokumentacja:


Ciekawe, dlaczego nowa odpowiedź, a nie tylko drobne ulepszenia istniejącej i (miejmy nadzieję) dobrze ustrukturyzowanej odpowiedzi.
Pavel Šimerda

Pierwsze dwa łącza do dokumentacji są obecnie nieczynne.
Peter Hansen

Dlaczego warto używać Wymaga zamiast Chcieć?
Karl Morrison,

4

Zgaduję, że mógłbym zmienić punkt, w którym skrypt działa, mieszając się z parametrem WantedBy

Będzie to miało odwrotny efekt niż chcesz. Od man systemd.unit:

WantedBy =, RequiredBy =

[...] Dowiązanie symboliczne jest tworzone w katalogu .wants / lub .requires / każdej z wymienionych jednostek, gdy ta jednostka jest instalowana przez systemctl enable. Powoduje to, że zależność typu Wants = lub Require = jest dodawana z wymienionej jednostki do bieżącej jednostki .

Na tej podstawie możemy zobaczyć, że właściwa opcja jednostki to „Chce” lub „Wymaga”; na podstawie ich opisu „Wymagane” jest prawdopodobnie poprawne, z dodatkiem „Po”, aby zapewnić nie tylko uruchomienie usługi sieciowej, ale także uruchomienie jej przed tym urządzeniem.

Żadna z opcji jednostek, AFAIK, nie może zawierać warunku, że rozpoczęta perquisite musiała zostać ukończona lub osiągnęła pewien punkt (sieć to prawdopodobnie usługa demona), tylko że zaczyna się pierwsza. Mając to na uwadze, możesz chcieć zrobić skrypt Type=forkingi wprowadzić zdrowe opóźnienie (powiedzmy 30 sekund) lub coś w rodzaju pętli wyjścia z sukcesem, w tym opóźnienia, aby upewnić się, że najpierw dzierżawisz DHCP.


1
Ani WantedBy, ani RequiredBy nie wpływają na zamawianie.
Pavel Šimerda

1
@ PavelŠimerda: Nikt tutaj nie twierdził, że tak. Zamawianie dlatego wyraźnie wspomniałem Afterw połączeniu z Requires„w celu zapewnienia nie tylko uruchomienia usługi sieciowej, ale także jej uruchomienia przed tym urządzeniem”.
złotowłosa

1
Tak, Afterdziała razem Wantslub w Requiresten sposób. Z drugiej strony wyraźne opóźnienia są złym nawykiem w narzędziach opartych na zależnościach, szczególnie gdy istnieje wyraźny sposób oczekiwania na konfigurację sieci określoną w dokumentacji systemowej, więc muszę nalegać na głosowanie negatywne.
Pavel Šimerda

3

Użyj Afterw tej [Unit]sekcji, aby określić, co należy uruchomić przed własną usługą. (Ta część poprzedniej odpowiedzi jest poprawna).

Aby uruchomić usługę po uruchomieniu sieci, użyj celu sieciowego, który powinien obowiązywać niezależnie od tego, czy korzystasz z NetworkManager, systemu conf.d / netctl w Arch, czy innej usługi, o której systemd jest świadomy.

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

Krótkie spojrzenie potwierdzi, że każda inna usługa w twoim systemie, która korzysta z łączności sieciowej, zawiera tę dyrektywę.

Jest także przenośny dla dowolnej dystrybucji używającej systemd. Twój plik jednostki będzie taki sam dla Arch, Fedora, RHEL 7, przyszłych wersji Debiana ...


Usługi, które rozpoczynają połączenie sieciowe, takie jak skrypty Arch lub własne, powinny to określać w swoich plikach jednostkowych.

[Unit]
Wants=network.target
Before=network.target

Nie podoba mi się ta Wantsczęść, ponieważ ma skutki uboczne w innych pakietach. Popatrz na moją odpowiedź.
Pavel Šimerda

Wystarczy sobie sprawę, że Wantson network.targetjest dobrym pomysłem tutaj.
Pavel Šimerda

naprawdę chcesz użyć network-online.target. ref
Edward Torvalds,

1

Chciałem dodać punkt do tego artykułu. Obecnie (lato 2015) w RHEL7 / CentOS 7, network-online.target jest niepoprawnie ustawiony przed uruchomieniem sieci IPv6, więc demony, które mają

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

w ich definicji usługi, która również jawnie wiąże się z adresami IPv6, prawdopodobnie zostanie uruchomiona przed uruchomieniem IPv6, co spowoduje ich awarię.


Wydaje mi się, że dzieje się tak tylko w przypadku automatycznej konfiguracji IPv6 opartej na jądrze, która i tak jest wadliwa. Jeśli chcesz poprawnie zamówić po IPv6, zdecydowanie powinieneś użyć NetworkManager zamiast /etc/init.d/network. Jeśli ten sam problem występuje nawet w przypadku NM, byłby to dobry powód, aby złożyć żądanie funkcji. Nie sprawdziłem za pomocą RHEL / CentOS, mogę ci pomóc, jeśli jesteś zainteresowany.
Pavel Šimerda 18.04.16

0
[Unit]
After=systemd-networkd.service

pracuje dla mnie.


Nie jestem pewien, czy to działa w niektórych szczególnych przypadkach, ale z kilku powodów jest źle. Jednym z nich jest networkdświadczenie własnej usługi / wait-online /. Przyciąganie i zamawianie po network-online.targetjest właściwym sposobem na skorzystanie z każdej usługi, która to obsługuje.
Pavel Šimerda 18.04.16
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.