Penyebab skrip untuk dieksekusi setelah jaringan dimulai?

102

Saya relatif baru untuk systemd dan saya sedang belajar arsitekturnya.

Saat ini, saya mencoba mencari cara untuk menjalankan skrip shell khusus. Skrip ini perlu dijalankan setelah lapisan jaringan dimulai.

Saya menjalankan Arch, menggunakan systemd dan juga netctl.

Untuk menguji, saya menulis skrip sederhana yang dijalankan ip addr list > /tmp/ip.txt. Saya membuat file layanan berikut untuk skrip ini.

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

[Service]
ExecStart=/root/test.script

[Install]
WantedBy=multi-user.target

Saya kemudian mengaktifkan skrip dengan,

systemctl enable test

Saat memulai ulang, skrip memang berjalan, tetapi berjalan sebelum jaringan dimulai. Dengan kata lain, output di ip.txttidak menampilkan alamat IPv4 yang ditetapkan untuk antarmuka utama. Pada saat saya masuk, alamat IPv4 memang telah ditetapkan dan jaringan sudah aktif.

Saya kira saya bisa mengubah titik di mana skrip berjalan dengan mengacaukan WantedByparameter, tapi saya tidak yakin bagaimana melakukannya.

Bisakah seseorang mengarahkan saya ke arah yang benar?

fdmillion
sumber

Jawaban:

126

Pada dependensi konfigurasi jaringan systemd

Sangat mudah untuk mempengaruhi pemesanan unit systemd. Di sisi lain, Anda perlu berhati-hati tentang apa yang dijamin unit lengkap.

Konfigurasikan layanan Anda

Pada sistem saat ini, memesan setelah network.targethanya menjamin bahwa layanan jaringan telah dimulai, bukan bahwa ada beberapa konfigurasi yang sebenarnya. Anda perlu memesan setelah network-online.targetdan menariknya untuk mencapai itu.

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

Untuk kompatibilitas dengan sistem yang lebih lama, Anda mungkin perlu memesan setelah network.target juga.

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

Itu untuk file unit layanan Anda dan untuk systemd.

Implementasi dalam versi perangkat lunak saat ini

Sekarang Anda perlu memastikan bahwa itu network-online.targetberfungsi seperti yang diharapkan (atau setidaknya Anda dapat menggunakannya network.target).

Versi NetworkManager saat ini menawarkan penawaran NetworkManager-wait-online.serviceyang ditarik network-online.targetoleh layanan Anda. Layanan khusus ini memastikan bahwa layanan Anda akan menunggu hingga semua koneksi yang dikonfigurasi untuk dimulai secara otomatis berhasil, gagal, atau habis waktu.

Versi systemd-networkd saat ini memblokir layanan Anda sampai semua perangkat dikonfigurasi seperti yang diminta. Lebih mudah karena saat ini hanya mendukung konfigurasi yang diterapkan pada saat boot (lebih khusus waktu startup dari `systemd-networkd.service).

Demi kelengkapan, /etc/init.d/networklayanan di Fedora, sebagaimana ditafsirkan oleh versi systemd saat ini, memblokir network.targetdan dengan demikian secara tidak langsung memblokir network-online.targetdan layanan Anda. Ini adalah contoh implementasi berbasis skrip.

Jika implementasi Anda, baik berbasis daemon atau berbasis skrip, berperilaku sebagai salah satu layanan manajemen jaringan di atas, itu akan menunda dimulainya layanan Anda hingga konfigurasi jaringan berhasil diselesaikan, gagal karena alasan yang baik, atau kehabisan waktu setelah waktu yang wajar. bingkai untuk menyelesaikan.

Anda mungkin ingin memeriksa apakah netctl bekerja dengan cara yang sama dan informasi itu akan menjadi tambahan yang berharga untuk jawaban ini.

Implementasi dalam versi perangkat lunak yang lebih lama

Saya tidak berpikir Anda akan melihat versi systemd yang cukup lama di mana ini tidak bekerja dengan baik. Tetapi Anda dapat memeriksa bahwa setidaknya network-online.targetada dan dipesan setelah itu network.target.

Sebelumnya NetworkManager hanya menjamin bahwa setidaknya satu koneksi akan diterapkan. Dan bahkan agar itu berfungsi, Anda harus mengaktifkannya NetworkManager-wait-online.servicesecara eksplisit. Ini telah lama diperbaiki di Fedora tetapi baru-baru ini diterapkan di hulu.

systemctl enable NetworkManager-wait-online.service

Catatan tentang implementasi network.target dan network-online.target

Anda seharusnya tidak perlu membuat perangkat lunak Anda bergantung pada NetworkManager.serviceatau NetworkManager-wait-online.serviceatau layanan spesifik lainnya. Sebagai gantinya, semua layanan manajemen jaringan harus memesan sendiri sebelum network.targetdan secara opsional network-online.target.

Layanan manajemen jaringan berbasis skrip sederhana harus menyelesaikan konfigurasi jaringan sebelum keluar dan harus memesan sendiri sebelum network.targetdan dengan demikian secara tidak langsung sebelumnya network-online.target.

[Unit]
Before=network.target

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

Layanan manajemen jaringan berbasis daemon juga harus memesan sendiri sebelumnya network.targetmeskipun itu tidak terlalu berguna.

[Unit]
Before=network.target

[Service]
Type=simple
ExecStart=...

Layanan yang menunggu untuk selesai daemon harus memesan sendiri setelah layanan khusus dan sebelumnya network-online.target. Ini harus digunakan Requisitepada layanan daemon sehingga gagal segera jika layanan manajemen jaringan masing-masing tidak digunakan.

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

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

Paket harus menginstal symlink ke layanan tunggu di wantsdirektori network-online.targetagar ditarik oleh layanan yang ingin menunggu jaringan yang dikonfigurasi.

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

Dokumentasi terkait

Catatan akhir

Saya harap saya tidak hanya membantu menjawab pertanyaan Anda pada saat Anda menanyakannya, tetapi juga berkontribusi untuk memperbaiki situasi di distribusi hulu dan Linux, sehingga saya sekarang dapat memberikan jawaban yang lebih baik daripada yang mungkin pada saat penulisan yang asli .

Pavel Šimerda
sumber
Apakah maksud Anda opsi autoconnect dengan "tunggu sampai semua koneksi yang dikonfigurasi untuk dimulai secara otomatis berhasil"? Dapatkah saya memanfaatkan ini ketika saya menetapkan no-auto-default = * tetapi saya memiliki autoconnect = yes pada salah satu koneksi saya? Dan pertanyaan terakhir - Saya tidak mengerti opsi --wait-for-startup dari halaman nm-online dan manual tidak banyak membantu. Terima kasih atas artikel ini, sangat dihargai!
lzap
Sejauh yang saya tahu, nm-online tidak peduli no-auto-default, hanya auto. Apakah Anda memiliki pertanyaan spesifik? Menurut pendapat saya, manual nm-online menyatakan dengan jelas bahwa dengan -situ menunggu semua koneksi otomatis dicoba, yaitu terhubung atau gagal.
Pavel Šimerda
Setelah mengacaukan omong kosong ini selama satu jam, saya menemukan solusinya: apt-get install sysv-init. :-) Kompleksitas yang ditambahkan systemd sebagai pengganti beberapa skrip shell membingungkan.
Seseorang
@ Seseorang Saya takut skrip init bukan jawaban dalam kasus ini. Jika Anda menggunakan NetworkManager atau alat konfigurasi dinamis lainnya, skrip init tidak dapat memesan sendiri setelah jaringan yang sepenuhnya dikonfigurasi. Anda bisa mendapatkan konfigurasi dinamis terbatas menggunakan /etc/init.d/networkatau serupa tetapi itu tidak berfungsi secara universal.
Pavel Šimerda
@Pavel Šimerda Init dieksekusi secara serial, dan skrip init yang tepat tidak akan kembali sampai selesai melakukan apa yang harus bergantung pada skrip selanjutnya. Untuk jaringan itu berarti memiliki semua adaptor yang berlaku dan siap. Kecuali itu hanya waktu yang beruntung, NM berperilaku baik dalam konteks itu. Masalah sebenarnya tentu saja adalah NM menciptakan kembali penanganan jaringan alih-alih membangun struktur yang sudah ada dan dicoba dan diuji. Desktop orang tampaknya tidak memiliki konsep bahaya bahaya. ;-)
Seseorang
9

Anda dapat menggunakan Afterdalam [Unit]bagian ini untuk menentukan layanan yang harus dimulai sebelum layanan Anda dimulai. Misalnya jika Anda menggunakan NetworkManager, Anda dapat membuat layanan Anda dimulai setelah NetworkManager dimulai.

[Unit]
Description=test service
After=NetworkManager.service
phoops
sumber
BindsTotidak begitu tepat di sini karena layanan ini merupakan peristiwa satu kali dan bukan layanan yang terus-menerus (kecuali itu juga termasuk ExecStopfitur untuk memecat ketika jaringan turun).
goldilocks
dihapusBindsTo
phoops
Anda bisa menambahkan sesuatu untuk diganti BindsTo, misalnya Requires, jika Anda hanya ingin layanan berjalan jika NetworkManager melakukannya. Aftertidak benar-benar melakukan itu - itu hanya berarti jika NM juga berjalan, kemudian jalankan ini sesudahnya. Jika NM tidak akan dijalankan, layanan akan dijalankan pada titik arbitrer.
goldilocks
4
After = network.target lebih baik daripada After = NetworkManager.service karena lebih generik.
Pavel Šimerda
7
Perhatikan bahwa menentukan tidakAfter=foo akan menyebabkan unit untuk memulai jika belum dimulai, itu hanya akan memberi tahu systemd bagaimana cara memesan unit jika keduanya dimulai pada waktu yang sama . Menggunakan kedua serta atau akan memiliki efek menarik di jika tidak dimulai, dan juga membuat pesanan systemd unit dengan benar. fooAfter=fooWants=fooRequires=foofoo
Emil Lundberg
8

Jika layanan Anda menyediakan server, yang dapat menunggu secara pasif bagi seseorang untuk terhubung, gunakan ini:

[Unit]
After=network.target

Layanan Anda harus mengikat pada antarmuka wildcard. Jika menggunakan aktivasi soket (disarankan), atau hanya lokal, Anda dapat mengabaikan target jaringan sepenuhnya.

Jika layanan Anda bertindak sebagai klien, atau peer to peer, ini lebih tepat:

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

Sebelum systemd 213 , network-online.target membutuhkan solusi yang disebutkan Pavel (Anda harus secara manual mengaktifkan layanan yang akan menunggu jaringan untuk dinyalakan). Pada systemd 213 ini dilakukan secara default. systemd-networkd-wait-onlineakan menunggu setidaknya satu alamat (baik routable atau link-local) untuk dikonfigurasi pada antarmuka non-loopback.

Mengkonfigurasi systemd-networkd, NetworkManager atau yang setara adalah tugas yang independen. DHCP (untuk IPv4) dan NDP (untuk IPv6) cenderung bekerja di luar kotak, tetapi Anda harus mengonfigurasinya sehingga definisi tepat Anda tentang "jaringan sudah habis" adalah pemicu network-online.target.

Dokumentasi:

Tobu
sumber
Hanya ingin tahu mengapa jawaban baru dan bukan hanya perbaikan kecil untuk jawaban yang sudah ada dan (semoga) terstruktur dengan baik.
Pavel Šimerda
Dua tautan Dokumentasi yang pertama saat ini tidak berfungsi.
Peter Hansen
Mengapa menggunakan Need bukannya Want?
Karl Morrison
4

Saya kira saya bisa mengubah titik di mana skrip berjalan dengan mengacaukan parameter WantedBy

Itu akan memiliki efek sebaliknya dari apa yang Anda inginkan. Dari man systemd.unit:

WantedBy =, WajibBy =

[...] Tautan simbolis dibuat di direktori .wants / atau .requires / masing-masing unit yang terdaftar saat unit ini diinstal oleh systemctl enable. Ini memiliki efek bahwa ketergantungan tipe ingin = atau membutuhkan = ditambahkan dari unit yang terdaftar ke unit saat ini .

Berdasarkan ini, kita dapat melihat opsi unit yang tepat adalah "Mau" atau "Membutuhkan"; berdasarkan deskripsi dari mereka, "Membutuhkan" mungkin benar, dengan penambahan "Setelah" untuk memastikan tidak hanya bahwa layanan jaringan dijalankan, tetapi bahwa itu berjalan sebelum unit ini.

Tak satu pun dari opsi unit, AFAIK, dapat mencakup ketentuan bahwa persyaratan awal yang harus dipenuhi, atau mencapai titik tertentu (jaringan mungkin merupakan layanan daemon), hanya yang memulai lebih dulu. Dengan mengingat hal ini, Anda mungkin ingin membuat skrip Type=forkingdan melakukan penundaan yang sehat (katakanlah 30 detik), atau semacam loop keluar-sukses termasuk penundaan, untuk memastikan bahwa Anda memiliki sewa DHCP terlebih dahulu.

goldilocks
sumber
1
Baik WantedBy maupun RequiredBy tidak mempengaruhi pemesanan.
Pavel Šimerda
1
@ PavelŠimerda: Tidak ada orang di sini yang mengklaim mereka melakukannya. Memesan adalah alasan mengapa saya secara eksplisit disebutkan Afterdalam hubungannya dengan Requires"untuk memastikan tidak hanya bahwa layanan jaringan dijalankan, tetapi juga dijalankan sebelum unit ini".
goldilocks
1
Ya, Afterbekerja sama dengan Wantsatau dengan Requirescara itu. Di sisi lain penundaan eksplisit adalah kebiasaan buruk dalam alat berbasis ketergantungan, terutama ketika ada cara eksplisit untuk menunggu sampai jaringan dikonfigurasi ditentukan oleh dokumentasi systemd, jadi saya harus bersikeras pada downvote.
Pavel Šimerda
3

Gunakan Afterdi [Unit]bagian ini untuk menentukan apa yang harus dimulai sebelum layanan Anda sendiri. (Ini banyak dari jawaban sebelumnya yang benar.)

Untuk memulai layanan Anda setelah jaringan naik, gunakan target jaringan, yang seharusnya berlaku apakah Anda menggunakan NetworkManager, sistem conf.d / netctl di Arch, atau layanan lain yang disadari oleh systemd.

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

Pandangan singkat akan mengonfirmasi bahwa setiap layanan lain di sistem Anda yang bergantung pada konektivitas jaringan mengandung arahan ini.

Ia juga portabel untuk distribusi apa pun yang menggunakan systemd. File unit Anda akan sama untuk Arch, Fedora, RHEL 7, versi Debian yang akan datang ...


Layanan yang memulai koneksi jaringan, seperti skrip Arch atau milik Anda, harus menentukannya dalam file unit mereka sendiri .

[Unit]
Wants=network.target
Before=network.target
Michael Hampton
sumber
Saya tidak sepenuhnya menyukai Wantsbagian itu karena memiliki efek samping pada paket lain. Tolong lihat jawaban saya.
Pavel Šimerda
Baru menyadari bahwa Wantsdi network.targetadalah ide yang baik di sini.
Pavel Šimerda
Anda benar-benar ingin menggunakan network-online.target. ref
Edward Torvalds
1

Saya ingin menambahkan satu poin pada artikel ini. Saat ini (musim panas 2015) di RHEL7 / CentOS 7, network-online.target salah diatur sebelum jaringan IPv6 dinyalakan, jadi daemon yang memiliki

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

dalam definisi layanan mereka yang juga secara eksplisit mengikat ke alamat IPv6 mungkin akan dimulai sebelum IPv6 aktif dan berjalan, menyebabkan mereka gagal.

Tuan Rumah Colo
sumber
Saya kira ini hanya terjadi dengan konfigurasi otomatis IPv6 berbasis kernel yang cacat. Jika Anda ingin memesan dengan benar setelah IPv6, Anda harus menggunakan NetworkManager /etc/init.d/network. Jika Anda mendapatkan masalah yang sama bahkan dengan NM, maka itu akan menjadi alasan yang bagus untuk mengajukan permintaan fitur. Saya belum memeriksa dengan RHEL / CentOS, saya dapat membantu Anda dengan detailnya jika Anda tertarik.
Pavel Šimerda
0
[Unit]
After=systemd-networkd.service

bekerja untukku.

Zhenxiao Hao
sumber
Tidak yakin apakah itu berfungsi dalam beberapa kasus khusus tetapi itu salah karena beberapa alasan. Salah satunya adalah yang networkdmenyediakan sendiri / tunggu-online / layanan. Menarik dan memesan setelah network-online.targetadalah cara yang tepat untuk pergi dengan layanan apa pun yang mendukung itu.
Pavel Šimerda