GNU/Linux >> Belajar Linux >  >> Linux

Kelola startup menggunakan systemd

Saat menyiapkan sistem Linux baru-baru ini, saya ingin tahu cara memastikan bahwa dependensi untuk layanan dan unit lain telah aktif dan berjalan sebelum layanan dan unit dependen tersebut dimulai. Secara khusus, saya membutuhkan lebih banyak pengetahuan tentang bagaimana systemd mengelola urutan startup, terutama dalam menentukan layanan pesanan dimulai dalam apa yang pada dasarnya adalah sistem paralel.

Anda mungkin tahu bahwa SystemV (pendahulu systemd, seperti yang saya jelaskan di artikel pertama dalam seri ini) mengurutkan urutan startup dengan memberi nama skrip startup dengan awalan SXX, di mana XX adalah angka dari 00 hingga 99. SystemV kemudian menggunakan urutan pengurutan dengan nama dan menjalankan setiap skrip awal secara berurutan untuk runlevel yang diinginkan.

Namun systemd menggunakan file unit, yang dapat dibuat atau dimodifikasi oleh sysadmin, untuk menentukan subrutin tidak hanya untuk inisialisasi tetapi juga untuk operasi reguler. Pada artikel ketiga dalam seri ini, saya menjelaskan cara membuat file unit mount. Dalam artikel kelima ini, saya menunjukkan cara membuat jenis file unit yang berbeda—file unit layanan yang menjalankan program saat startup. Anda juga dapat mengubah pengaturan konfigurasi tertentu di file unit dan menggunakan jurnal systemd untuk melihat lokasi perubahan Anda dalam urutan startup.

Persiapan

Pastikan Anda telah menghapus rhgb dan quiet dari GRUB_CMDLINE_LINUX= baris di /etc/default/grub file, seperti yang saya tunjukkan di artikel kedua dalam seri ini. Ini memungkinkan Anda untuk mengamati aliran pesan startup Linux, yang akan Anda perlukan untuk beberapa eksperimen dalam artikel ini.

Program

Dalam tutorial ini, Anda akan membuat program sederhana yang memungkinkan Anda untuk mengamati pesan selama startup di konsol dan kemudian di jurnal systemd.

Buat program shell /usr/local/bin/hello.sh dan tambahkan konten berikut. Anda ingin memastikan bahwa hasilnya terlihat saat startup dan Anda dapat dengan mudah menemukannya saat melihat melalui jurnal systemd. Anda akan menggunakan versi program "Hello world" dengan beberapa bar di sekitarnya, sehingga menonjol. Pastikan file dapat dieksekusi dan memiliki kepemilikan pengguna dan grup secara root dengan 700 izin untuk keamanan:

#!/usr/bin/bash
# Simple program to use for testing startup configurations
# with systemd.
# By David Both
# Licensed under GPL V2
#
echo "###############################"
echo "######### Hello World! ########"
echo "###############################"

Jalankan program ini dari baris perintah untuk memverifikasi bahwa itu berfungsi dengan benar:

[root@testvm1 ~]# hello.sh 
###############################
######### Hello World! ########
###############################
[root@testvm1 ~]#

Program ini dapat dibuat dalam bahasa skrip atau bahasa apa pun yang dikompilasi. hello.sh program juga dapat ditempatkan di tempat lain berdasarkan struktur hierarki sistem file (FHS) Linux. Saya menempatkannya di /usr/local/bin direktori sehingga dapat dengan mudah dijalankan dari baris perintah tanpa harus menambahkan jalur saat saya mengetik perintah. Saya menemukan bahwa banyak program shell yang saya buat perlu dijalankan dari baris perintah dan dengan alat lain seperti systemd.

File unit layanan

Buat file unit layanan /etc/systemd/system/hello.service dengan konten berikut. File ini tidak perlu dieksekusi, tetapi untuk keamanan, diperlukan kepemilikan pengguna dan grup dengan root dan izin 644 atau 640:

# Simple service unit file to use for testing 
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh

[Install]
WantedBy=multi-user.target

Verifikasi bahwa file unit layanan berfungsi seperti yang diharapkan dengan melihat status layanan. Kesalahan sintaksis apa pun akan muncul di sini:

[root@testvm1 ~]# systemctl status hello.service 
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)
[root@testvm1 ~]#

Anda dapat menjalankan jenis layanan "oneshot" ini beberapa kali tanpa masalah. Jenis oneshot ditujukan untuk layanan di mana program yang diluncurkan oleh file unit layanan adalah proses utama dan harus diselesaikan sebelum systemd memulai proses yang bergantung.

Ada tujuh jenis layanan, dan Anda dapat menemukan penjelasan masing-masing (bersama dengan bagian lain dari file unit layanan) di halaman manual systemd.service(5). (Anda juga dapat menemukan informasi lebih lanjut di sumber daya di akhir artikel ini.)

Betapapun penasarannya saya, saya ingin melihat seperti apa kesalahan itu. Jadi, saya menghapus "o" dari Type=oneshot baris, sehingga terlihat seperti Type=neshot , dan jalankan perintah lagi:

[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 06 08:50:09 testvm1.both.org systemd[1]: /etc/systemd/system/hello.service:12: Failed to parse service type, ignoring: neshot
[root@testvm1 ~]#

Hasil ini memberi tahu saya dengan tepat di mana letak kesalahannya dan membuatnya sangat mudah untuk menyelesaikan masalah.

Lebih banyak sumber daya Linux

  • Lembar contekan perintah Linux
  • Lembar contekan perintah Linux tingkat lanjut
  • Kursus online gratis:Ikhtisar Teknis RHEL
  • Lembar contekan jaringan Linux
  • Lembar contekan SELinux
  • Lembar contekan perintah umum Linux
  • Apa itu container Linux?
  • Artikel Linux terbaru kami

Perlu diketahui bahwa bahkan setelah Anda memulihkan hello.service file ke bentuk aslinya, kesalahan akan tetap ada. Meskipun reboot akan menghapus kesalahan, Anda tidak perlu melakukan itu, jadi saya mencari metode untuk menghapus kesalahan terus-menerus seperti ini. Saya mengalami kesalahan layanan yang memerlukan perintah systemctl daemon-reload untuk mengatur ulang kondisi kesalahan, tetapi itu tidak berhasil dalam kasus ini. Pesan kesalahan yang dapat diperbaiki dengan perintah ini sepertinya selalu memiliki pernyataan untuk itu, jadi Anda tahu untuk menjalankannya.

Namun, Anda disarankan untuk menjalankan systemctl daemon-reload setelah mengubah file unit atau membuat yang baru. Ini memberi tahu systemd bahwa perubahan telah dibuat, dan ini dapat mencegah jenis masalah tertentu dengan mengelola layanan atau unit yang diubah. Silakan dan jalankan perintah ini.

Setelah mengoreksi kesalahan ejaan dalam file unit layanan, systemctl restart hello.service sederhana dibersihkan kesalahannya. Bereksperimenlah sedikit dengan memasukkan beberapa kesalahan lain ke dalam hello.service file untuk melihat jenis hasil yang Anda dapatkan.

Mulai layanan

Sekarang Anda siap untuk memulai layanan baru dan memeriksa status untuk melihat hasilnya. Meskipun Anda mungkin melakukan restart di bagian sebelumnya, Anda dapat memulai atau me-restart layanan oneshot sebanyak yang Anda inginkan karena berjalan sekali dan kemudian keluar.

Silakan dan mulai layanan (seperti yang ditunjukkan di bawah), lalu periksa statusnya. Bergantung pada seberapa banyak Anda bereksperimen dengan kesalahan, hasil Anda mungkin berbeda dari hasil saya:

[root@testvm1 ~]# systemctl start hello.service 
[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

Perhatikan dalam output perintah status bahwa pesan systemd menunjukkan bahwa hello.sh skrip dimulai dan layanan selesai. Anda juga dapat melihat output dari skrip. Tampilan ini dihasilkan dari entri jurnal dari permintaan layanan terbaru. Coba mulai layanan beberapa kali, lalu jalankan perintah status lagi untuk melihat apa yang saya maksud.

Anda juga harus melihat isi jurnal secara langsung; ada beberapa cara untuk melakukan ini. Salah satu caranya adalah dengan menentukan pengidentifikasi tipe record, dalam hal ini, nama skrip shell. Ini menunjukkan entri jurnal untuk reboot sebelumnya serta sesi saat ini. Seperti yang Anda lihat, saya telah meneliti dan menguji artikel ini untuk beberapa waktu sekarang:

[root@testvm1 ~]# journalctl -t hello.sh
<snip>
-- Reboot --
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
May 08 15:55:47 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
May 08 16:01:51 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

Untuk menemukan catatan systemd untuk hello.service unit, Anda dapat mencari di systemd. Anda dapat menggunakan G+Enter ke halaman ke akhir entri jurnal dan kemudian gulir kembali untuk menemukan entri yang Anda minati. Gunakan -b opsi untuk hanya menampilkan entri untuk startup terbaru:

[root@testvm1 ~]# journalctl -b -t systemd
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:50 testvm1.both.org systemd[1]: Starting D-Bus System Message Bus...
May 10 10:37:50 testvm1.both.org systemd[1]: Started D-Bus System Message Bus.

Saya menyalin beberapa entri jurnal lain untuk memberi Anda gambaran tentang apa yang mungkin Anda temukan. Perintah ini memuntahkan semua baris jurnal yang berkaitan dengan systemd—109.183 baris ketika saya menulis ini. Itu banyak sekali data yang harus dipilah. Anda dapat menggunakan fasilitas pencarian pager, yang biasanya less , atau Anda dapat menggunakan grep . bawaan fitur. -g (atau --grep= ) opsi menggunakan ekspresi reguler yang kompatibel dengan Perl:

[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:01:01 EDT. --
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

Anda dapat menggunakan grep GNU standar perintah, tetapi itu tidak akan menampilkan metadata log di baris pertama.

Jika Anda tidak ingin hanya melihat entri jurnal yang berkaitan dengan hello . Anda service, Anda dapat mempersempit sedikit dengan menentukan rentang waktu. Misalnya, saya akan mulai dengan waktu awal 10:54:00 pada VM pengujian saya, yang merupakan awal dari saat entri di atas berasal. Perhatikan bahwa --since= opsi harus diapit tanda kutip dan opsi ini juga dapat dinyatakan sebagai -S "<time specification>" .

Tanggal dan waktu akan berbeda di host Anda, jadi pastikan untuk menggunakan stempel waktu yang sesuai dengan waktu di jurnal Anda:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:00"
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=54 op=LOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd"'
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/"'
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <error> [1589122560.0633] dhcp4 (enp0s3): error -113 dispatching events
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <info>  [1589122560.0634] dhcp4 (enp0s3): state changed bound -> fail
<snip>

since spesifikasi melewatkan semua entri sebelum waktu itu, tetapi masih ada banyak entri setelah waktu itu yang tidak Anda perlukan. Anda juga dapat menggunakan until opsi untuk memangkas entri yang datang sedikit setelah waktu yang Anda minati. Saya ingin seluruh menit saat peristiwa terjadi dan tidak lebih:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:04:59 EDT. --
May 10 10:54:35 testvm1.both.org systemd[1]: Reloading.
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=27 op=UNLOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=26 op=UNLOAD
<snip>
ay 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
lines 1-46/46 (END)

Jika ada banyak aktivitas dalam jangka waktu ini, Anda dapat lebih mempersempit aliran data yang dihasilkan menggunakan kombinasi opsi berikut:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00" -t "hello.sh"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:10:41 EDT. --
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

Hasil Anda harus serupa dengan saya. Anda dapat melihat dari rangkaian eksperimen ini bahwa layanan dijalankan dengan benar.

Reboot—akhirnya

Sejauh ini, Anda belum me-reboot host tempat Anda menginstal layanan Anda. Jadi lakukan itu sekarang karena, bagaimanapun, cara ini adalah tentang menjalankan program saat startup. Pertama, Anda perlu mengaktifkan layanan untuk diluncurkan selama urutan startup:

[root@testvm1 ~]# systemctl enable hello.service 
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
[root@testvm1 ~]#

Perhatikan bahwa tautan dibuat di /etc/systemd/system/multi-user.target.wants direktori. Ini karena file unit layanan menetapkan bahwa layanan "diinginkan" oleh multi-user.target .

Reboot, dan pastikan untuk menonton aliran data selama urutan startup untuk melihat pesan "Hello world". Tunggu ... Anda tidak melihatnya? Yah, saya juga tidak. Meskipun berjalan sangat cepat, saya melihat pesan systemd bahwa itu memulai hello.service .

Lihatlah jurnal sejak boot sistem terbaru. Anda dapat menggunakan less alat pencarian pager untuk menemukan "Halo" atau "halo". Saya memangkas banyak baris data, tetapi saya meninggalkan beberapa entri jurnal di sekitarnya, sehingga Anda dapat merasakan seperti apa tampilan entri yang berkaitan dengan layanan Anda secara lokal:

[root@testvm1 ~]# journalctl -b
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Listening on SSSD Kerberos Cache Manager responder socket.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Sockets.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Basic System.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Modem Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Network Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Avahi mDNS/DNS-SD Stack...
May 10 10:37:49 testvm1.both.org systemd[1]: Condition check resulted in Secure Boot DBX (blacklist) updater being skipped.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
May 10 10:37:49 testvm1.both.org systemd[1]: Started irqbalance daemon.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=irqbalance comm="systemd" exe="/usr/lib/sy>"'
May 10 10:37:49 testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Hardware Monitoring Sensors...
<snip>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting NTP client/server...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=livesys-late comm="systemd" exe="/usr/lib/>"'
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>"'
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
May 10 10:37:50 testvm1.both.org audit: BPF prog-id=28 op=LOAD
<snip>

Anda dapat melihat bahwa systemd memulai hello.service unit, yang menjalankan hello.sh skrip shell dengan output yang dicatat dalam jurnal. Jika Anda dapat menangkapnya saat boot, Anda juga akan melihat pesan systemd yang menunjukkan bahwa skrip sedang memulai dan pesan lain yang menunjukkan bahwa layanan berhasil. Dengan melihat pesan systemd pertama dalam aliran data di atas, Anda dapat melihat bahwa systemd memulai layanan Anda segera setelah mencapai target sistem dasar.

Tapi saya ingin melihat pesan yang ditampilkan saat startup juga. Ada cara untuk mewujudkannya:Tambahkan baris berikut ke [Service] bagian hello.service berkas:

StandardOutput=journal+console

hello.service file sekarang terlihat seperti ini:

# Simple service unit file to use for testing 
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh
StandardOutput=journal+console

[Install]
WantedBy=multi-user.target

Setelah menambahkan baris ini, reboot sistem, dan lihat aliran data saat menggulung layar selama proses boot. Anda akan melihat pesan di kotak kecilnya. Setelah urutan startup selesai, Anda dapat melihat jurnal untuk boot terbaru dan menemukan entri untuk layanan baru Anda.

Mengubah urutan

Sekarang layanan Anda berfungsi, Anda dapat melihat di mana itu dimulai dalam urutan startup dan bereksperimen dengan mengubahnya. Penting untuk diingat bahwa maksud systemd adalah untuk memulai sebanyak mungkin layanan dan jenis unit lainnya secara paralel dalam setiap target utama:basic.target , multi-user.target , dan graphical.target . Anda seharusnya baru saja melihat entri jurnal untuk boot terbaru, yang akan terlihat mirip dengan jurnal saya pada output di atas.

Perhatikan bahwa systemd memulai layanan pengujian Anda segera setelah mencapai sistem dasar target. Inilah yang Anda tentukan dalam file unit layanan di WantedBy garis, jadi itu benar. Sebelum Anda mengubah apa pun, buat daftar konten /etc/systemd/system/multi-user.target.wants direktori, dan Anda akan melihat tautan simbolis (lunak) ke file unit layanan. [Install] bagian dari file unit layanan menentukan target mana yang akan memulai layanan, dan menjalankan systemctl enable hello.service perintah membuat tautan di direktori "target want" yang sesuai:

hello.service -> /etc/systemd/system/hello.service

Layanan tertentu harus dimulai selama basic.target , dan yang lainnya tidak perlu memulai kecuali sistem memulai graphical.target . Layanan dalam eksperimen ini tidak akan dimulai di basic.target —anggap Anda tidak memerlukannya untuk memulai sampai graphical.target . Jadi ubah WantedBy baris:

WantedBy=graphical.target

Pastikan untuk menonaktifkan hello.service dan aktifkan kembali untuk menghapus tautan lama dan menambahkan yang baru di graphical.targets.wants direktori. Saya perhatikan bahwa jika saya lupa menonaktifkan layanan sebelum mengubah target yang diinginkan, saya dapat menjalankan systemctl disable perintah, dan tautan akan dihapus dari kedua direktori "keinginan target". Kemudian, saya hanya perlu mengaktifkan kembali layanan dan mem-boot ulang.

Satu perhatian dengan memulai layanan di graphical.target adalah jika host melakukan booting ke multi-user.target , layanan ini tidak akan dimulai secara otomatis. Itu mungkin yang Anda inginkan jika layanan memerlukan antarmuka desktop GUI, tetapi mungkin juga bukan yang Anda inginkan.

Lihat entri jurnal untuk graphical.target dan multi-user.target menggunakan -o short-monotonic opsi yang menampilkan detik setelah startup kernel dengan presisi mikrodetik:

[root@testvm1 ~]# journalctl -b -o short-monotonic

Beberapa hasil untuk multi-user.target :

[   17.264730] testvm1.both.org systemd[1]: Starting My hello shell script...
[   17.265561] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<SNIP>
[   19.478468] testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
[   19.507359] testvm1.both.org iptables.init[844]: iptables: Applying firewall rules: [  OK  ]
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
[   19.507835] testvm1.both.org hello.sh[843]: ######### Hello World! ########
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
<SNIP>
[   21.482481] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   21.482550] testvm1.both.org smartd[856]: Opened configuration file /etc/smartmontools/smartd.conf
[   21.482605] testvm1.both.org systemd[1]: Finished My hello shell script.

Dan beberapa hasil untuk graphical.target :

[   19.436815] testvm1.both.org systemd[1]: Starting My hello shell script...
[   19.437070] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<SNIP>
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.612614] testvm1.both.org hello.sh[841]: ######### Hello World! ########
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.629455] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629569] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629682] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   19.629782] testvm1.both.org systemd[1]: Finished My hello shell script.

Meskipun memiliki graphical.target "ingin" di file unit, hello.service unit berjalan sekitar 19,5 atau 19,6 detik ke startup. Tapi hello.service dimulai sekitar 17,24 detik di multi-user.target dan 19,43 detik dalam target grafis.

Apa artinya ini? Lihat /etc/systemd/system/default.target tautan. Isi file itu menunjukkan bahwa systemd pertama kali memulai target default, graphical.target , yang kemudian menarik multi-user.target :

[root@testvm1 system]# cat default.target
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
[root@testvm1 system]#

Apakah itu memulai layanan dengan graphical.target atau multi-user.target , hello.service unit berjalan sekitar 19,5 atau 19,6 detik ke startup. Berdasarkan ini dan hasil jurnal (terutama yang menggunakan output monoton), Anda tahu bahwa kedua target ini dimulai secara paralel. Lihat satu hal lagi dari keluaran jurnal:

[   28.397330] testvm1.both.org systemd[1]: Reached target Multi-User System.
[   28.397431] testvm1.both.org systemd[1]: Reached target Graphical Interface.

Kedua target finis di waktu yang hampir bersamaan. Ini konsisten karena graphical.target menarik multi-user.target dan tidak dapat selesai sampai multi.user target tercapai, yaitu selesai. Tapi  hello.service selesai lebih awal dari ini.

Apa artinya semua ini adalah bahwa kedua target ini memulai cukup banyak secara paralel. Jika Anda menjelajahi entri jurnal, Anda akan melihat berbagai target dan layanan dari masing-masing target utama tersebut sebagian besar dimulai secara paralel. Jelas bahwa multi-user.target tidak perlu diselesaikan sebelum graphical.target dimulai. Oleh karena itu, hanya menggunakan target utama ini untuk mengurutkan startup tidak bekerja dengan baik, meskipun dapat berguna untuk memastikan bahwa unit dimulai hanya ketika dibutuhkan untuk graphical.target .

Sebelum melanjutkan, kembalikan hello.service file unit ke WantedBy=multi-user.target (jika belum.)

Pastikan layanan dimulai setelah jaringan berjalan

Masalah urutan startup yang umum adalah memastikan bahwa unit dimulai setelah jaringan aktif dan berjalan. Artikel Freedesktop.org Menjalankan layanan setelah jaringan aktif mengatakan tidak ada konsensus nyata tentang kapan jaringan dianggap "naik". Namun, artikel tersebut memberikan tiga opsi, dan yang memenuhi kebutuhan jaringan yang beroperasi penuh adalah network-online.target . Perlu diketahui bahwa network.target digunakan selama shutdown daripada startup, sehingga tidak ada gunanya bagi Anda ketika Anda mencoba untuk mengurutkan startup.

Sebelum membuat perubahan lain, pastikan untuk memeriksa jurnal dan memverifikasi bahwa hello.service unit dimulai jauh sebelum jaringan. Anda dapat mencari network-online.target dalam jurnal untuk diperiksa.

Layanan Anda tidak benar-benar membutuhkan layanan jaringan, tetapi Anda dapat menggunakannya sebagai avatar untuk layanan yang membutuhkannya.

Karena menyetel WantedBy=graphical.target does not ensure that the service will be started after the network is up and running, you need another way to ensure that it is. Fortunately, there is an easy way to do this. Add the following two lines to the [Unit] section of the hello.service unit file:

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

Both of these entries are required to make this work. Reboot the host and look for the location of entries for your service in the journals:

[   26.083121] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0293] device (enp0s3): Activation: successful, device activated.
[   26.083349] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0301] manager: NetworkManager state is now CONNECTED_GLOBAL
[   26.085818] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0331] manager: startup complete
[   26.089911] testvm1.both.org systemd[1]: Finished Network Manager Wait Online.
[   26.090254] testvm1.both.org systemd[1]: Reached target Network is Online.
[   26.090399] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-wait-online comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? termina>"'
[   26.091991] testvm1.both.org systemd[1]: Starting My hello shell script...
[   26.095864] testvm1.both.org sssd[be[implicit_files]][1007]: Starting up
[   26.290539] testvm1.both.org systemd[1]: Condition check resulted in Login and scanning of iSCSI devices being skipped.
[   26.291075] testvm1.both.org systemd[1]: Reached target Remote File Systems (Pre).
[   26.291154] testvm1.both.org systemd[1]: Reached target Remote File Systems.
[   26.292671] testvm1.both.org systemd[1]: Starting Notify NFS peers of a restart...
[   26.294897] testvm1.both.org systemd[1]: iscsi.service: Unit cannot be reloaded because it is inactive.
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.304682] testvm1.both.org hello.sh[1010]: ######### Hello World! ########
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.306569] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306669] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306772] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   26.306862] testvm1.both.org systemd[1]: Finished My hello shell script.
[   26.584966] testvm1.both.org sm-notify[1011]: Version 2.4.3 starting

This confirms that the hello.service unit started after the network-online.target . This is exactly what you want. You may also have seen the "Hello World" message as it passed by during startup. Notice also that the timestamp is about six seconds later in the startup than it was before.

The best way to define the start sequence

This article explored Linux startup with systemd and unit files and journals in greater detail and discovered what happens when errors are introduced into the service file. As a sysadmin, I find that this type of experimentation helps me understand the behaviors of a program or service when it breaks, and breaking things intentionally is a good way to learn in a safe environment.

As the experiments in this article proved, just adding a service unit to either the multi-user.target or the graphical.target does not define its place in the start sequence. It merely determines whether a unit starts as part of a graphical environment or not. The reality is that the startup targets multi-user.target and graphical.target —and all of their Wants and Requires—start up pretty much in parallel. The best way to ensure that a unit starts in a specific order is to determine the unit it is dependent on and configure the new unit to "Want" and "After" the unit upon which it is dependent.

Resources

There is a great deal of information about systemd available on the internet, but much is terse, obtuse, or even misleading. In addition to the resources mentioned in this article, the following webpages offer more detailed and reliable information about systemd startup.

  • The Fedora Project has a good, practical guide to systemd. It has pretty much everything you need to know in order to configure, manage, and maintain a Fedora computer using systemd.
  • The Fedora Project also has a good cheat sheet that cross-references the old SystemV commands to comparable systemd ones.
  • For detailed technical information about systemd and the reasons for creating it, check out Freedesktop.org's description of systemd.
  • Linux.com's "More systemd fun" offers more advanced systemd information and tips.

There is also a series of deeply technical articles for Linux sysadmins by Lennart Poettering, the designer and primary developer of systemd. These articles were written between April 2010 and September 2011, but they are just as relevant now as they were then. Much of everything else good that has been written about systemd and its ecosystem is based on these papers.

  • Rethinking PID 1
  • systemd for Administrators, Part I
  • systemd for Administrators, Part II
  • systemd for Administrators, Part III
  • systemd for Administrators, Part IV
  • systemd for Administrators, Part V
  • systemd for Administrators, Part VI
  • systemd for Administrators, Part VII
  • systemd for Administrators, Part VIII
  • systemd for Administrators, Part IX
  • systemd for Administrators, Part X
  • systemd for Administrators, Part XI

Linux
  1. Menggunakan perintah systemctl untuk mengelola unit systemd

  2. Panduan Ansible:Kelola File menggunakan Ansible

  3. Cara Mengelola Layanan Systemd dengan Systemctl di Linux

  1. Mengganti rc.local di systemd sistem Linux

  2. Bagaimana Cara Menulis Script Startup Untuk Systemd?

  3. Cara mengarahkan output dari layanan systemd ke file

  1. Cara Menggunakan Perintah Systemctl untuk Mengelola Layanan Systemd

  2. Menggunakan Logrotate di linux Untuk Mengelola File Log (dengan contoh)

  3. Menggunakan nc untuk mentransfer file besar