Memahami Unit Systemd: Service dan Timer untuk Mengelola Layanan
Di balik perintah systemctl start yang tampak sederhana, systemd mengelola setiap layanan sebagai sebuah unit: berkas teks yang menentukan cara proses dijalankan, kapan mulai, dan bagaimana sistem memulihkannya bila gagal. Banyak pengguna Linux menyalin unit dari tutorial tanpa memahami isinya, lalu bingung ketika layanan tidak ikut menyala saat boot. Artikel ini membedah struktur unit systemd dengan contoh yang telah diuji pada Ubuntu 26.04.1 LTS (systemd 259), serta cara validasi yang tidak mengubah sistem sama sekali.
Ringkasan
- Unit systemd adalah berkas teks tiga bagian: [Unit], tipe unit, dan [Install].
- Type=oneshot untuk tugas sekali jalan; Type=exec untuk proses jangka panjang.
- systemctl enable membuat symlink; tanpa enable, unit tidak ikut boot.
- Setiap perubahan unit wajib diikuti systemctl daemon-reload.
- Timer OnCalendar= menjadwalkan unit lain tanpa perlu cron.
Apa Itu Unit Systemd?
Systemd adalah sistem init modern yang dipakai hampir semua distro besar, dan situs resminya mendokumentasikan desainnya di systemd.io. Segala sesuatu yang dikelola systemd direpresentasikan sebagai unit: berkas INI berisi instruksi untuk menjalankan, menghentikan, dan mengkategorikan sebuah elemen sistem. Jenis unit yang umum terlihat dalam tabel berikut.
| Jenis unit | Ekstensi | Gunanya |
|---|---|---|
| service | .service | Menjalankan dan mengawasi sebuah proses atau daemon |
| timer | .timer | Menjadwalkan unit lain dengan kalender atau interval |
| socket | .socket | Mendengarkan port dan menunda aktivasi hingga ada koneksi |
| mount / automount | .mount, .automount | Mengelola titik mount berkas sistem |
| path | .path | Memicu unit saat sebuah berkas berubah |
| slice | .slice | Mengelompokkan unit untuk pembagian sumber daya (cgroup) |
| target | .target | Grup logis unit, misalnya multi-user.target |
Unit dicari dari direktori dengan urutan prioritas tertentu, sebagaimana dijelaskan di dokumentasi systemd.unit. Direktori admin selalu menang atas direktori vendor:
| Prioritas | Direktori | Asal |
|---|---|---|
| Tertinggi | /etc/systemd/system | Buatan administrator |
| Menengah | /run/systemd/system | Hasil runtime (transien) |
| Rendah | /usr/lib/systemd/system | Disertakan oleh paket distribusi |
Bila nama berkas sama di dua direktori, versi yang lebih tinggi menang. Fragment drop-in *.d/*.conf dapat menambah atau menimpa kunci tanpa menyentuh berkas utama, trik yang rapi untuk kustomisasi kecil.
Anatomi Berkas Unit
Sebuah unit modern terdiri dari tiga bagian: [Unit] untuk metadata dan dependensi, bagian tipe sesuai akhiran berkas, serta [Install] untuk kebijakan saat enable.
Bagian [Unit]: Metadata dan Dependensi
Bagian [Unit] paling sering memuat tiga macam kunci: deskripsi, dokumentasi, dan relasi antarunit.
| Kunci | Arti |
|---|---|
Description= | Kalimat yang tampil di systemctl status |
Documentation= | Lokasi dokumentasi (man page atau URL) |
After= / Before= | Mengatur urutan mulai, tanpa memuat unit lain |
Wants= | Memuat unit lain secara lunak; kegagalannya tidak fatal |
Requires= | Memuat unit lain secara keras; kegagalannya ikut menggagalkan |
Condition...= | Menolak memulai bila syarat tidak terpenuhi |
Poin yang tak pernah berhenti membingungkan: After= hanya menyusun antrean, ia tidak menarik unit yang disebut masuk ke dalam sesi boot. Agar unit lain ikut dimuat, gunakan Wants= atau Requires=. Requires= bersifat keras, sementara man page menyarankan Wants= bila tujuan Anda hanyalah “sebaiknya ada, bukan wajib”.
Bagian [Service]: Bagaimana Proses Dijalankan
Untuk unit .service, kunci terpenting adalah Type=, sebab ia menentukan kapan systemd menganggap unit sudah “aktif”. Nilai yang umum dijelaskan oleh dokumentasi systemd.service.
| Type | Kapan dianggap aktif | Cocok untuk |
|---|---|---|
simple | Begitu proses bercabang | Default bila Type= tidak ditulis |
exec | Begitu proses berhasil dieksekusi | Proses jangka panjang yang disarankan |
forking | Proses induk keluar, anak menjadi utama | Daemon gaya lama (daemonize) |
oneshot | Semua perintah selesai | Tugas sekali jalan, misalnya backup |
notify | Proses mengirim READY=1 | Program yang digabung dengan systemd |
dbus | Nama bus tersedia | Layanan yang memakai D-Bus |
Type=oneshot perlu ditemani RemainAfterExit=yes; tanpa itu, unit yang sudah selesai berjalan langsung berstatus inactive (dead) meski berhasil, dan orang mengiranya gagal. Aturan ExecStart= juga khas: argumen pertama wajib berkas absolut, tanpa interpretasi shell, tanda &&, ~, maupun ekspansi variabel. Awali dengan - bila kegagalan keluarannya boleh diabaikan.
Sistem tempat artikel ini ditulis memakai berkas cron.service bawaan Ubuntu sebagai contoh nyata yang sah:
# /usr/lib/systemd/system/cron.service
[Unit]
Description=Regular background program processing daemon
After=remote-fs.target nss-user-lookup.target
[Service]
EnvironmentFile=-/etc/default/cron
ExecStart=/usr/sbin/cron -f -P $EXTRA_OPTS
Restart=on-failure
[Install]
WantedBy=multi-user.targetDua hal menarik di sana: systemd menjalankan cron dengan -f agar tetap di depan, sehingga Type= standar cocok; Restart=on-failure meminta systemd menghidupkan lagi proses bila berhenti abnormal. Contoh buatan yang menyertai artikel ini, demo-long.service, menjalankan sleeper dengan Type=exec dan RestartSec=5s, dan tersedia di bawah untuk direnungkan.
[Unit]
Description=Layanan yang berjalan terus menerus
After=network.target
[Service]
Type=exec
ExecStart=/usr/bin/sleep infinity
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.targetBagian [Install]: Kapan Unit Ikut Boot
Bagian ini baru berlaku saat systemctl enable dijalankan: systemd membaca WantedBy= dan membuat symlink berkas unit ke direktori <target>.wants/. Dengan begitu, unit dimuat setiap kali target itu tercapai, misalnya multi-user.target saat sistem menyala penuh.
Konsekuensi yang sering salah duga: systemctl start menghidupkan unit hanya untuk sesi ini, sedangkan systemctl enable menautkannya ke boot. Keduanya bisa digabung dengan systemctl enable --now bila ingin sekaligus.
Perintah yang Sering Dipakai
Tabel berikut merangkum operasi systemctl yang paling harian.
| Perintah | Fungsi |
|---|---|
systemctl start/stop/restart <unit> | Mengubah status saat ini |
systemctl enable/disable <unit> | Menautkan / melepas unit dari boot |
systemctl mask/unmask <unit> | Melarang unit dijalankan oleh apa pun |
systemctl daemon-reload | Membaca ulang unit setelah berkas diubah |
systemctl status <unit> | Ringkasan status, PID, dan log terakhir |
systemctl cat <unit> | Menampilkan isi unit beserta override |
systemctl is-enabled <unit> | Memeriksa status enable |
systemctl list-units / list-unit-files | Mendaftar unit aktif / semua unit |
Sebagian besar perintah di atas butuh hak root kecuali untuk unit --user. Bila merasa baru saja mengubah berkas unit dan tidak ada efeknya, jalankan daemon-reload dulu, penyebab nomor satu unit tidak mengenali perubahan.
Timer: Menjadwalkan tanpa Cron
Unit .timer menambahkan penjadwalan berbasis kalender atau interval langsung dari systemd, mengikuti aturan pada dokumentasi systemd.timer. Secara bawaan, foo.timer membangunkan foo.service; untuk unit lain gunakan Unit=.
| Kunci | Menjadwalkan berdasarkan |
|---|---|
OnCalendar= | Ekspresi kalender, misal *-*-* 02:00:00 setiap pukul 02.00 |
OnBootSec= | Detik sejak sistem dinyalakan |
OnUnitActiveSec= | Detik sejak unit terakhir kali aktif |
Persistent=true | Menjalankan event yang terlewat (hanya untuk OnCalendar) |
Timer Ubuntu untuk anacron, yang ikut dipakai menulis artikel ini, menunjukkan kombinasi kalender yang elegan. OnCalendar=*-*-* 07..23:30 membangunkan anacron paling cepat setiap jam mulai 07.30 hingga 23.30, dan RandomizedDelaySec=5m membuat jadwalnya tidak serempak dengan host lain. Nilai AccuracySec= default adalah satu menit, dan Persistent=true memastikan event yang terlewat ketika mesin mati tetap dikejar begitu mesin hidup.
Pasangan timer buatan yang tervalidasi pada artikel ini terlihat seperti ini.
# demo.timer -> membangunkan demo.service
[Unit]
Description=Jadwal ulang demo setiap hari pukul 02:00
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.targetJangan lupa systemctl enable --now demo.timer dan periksa dengan systemctl list-timers, yang menampilkan waktu berikutnya sekaligus waktu terakhir: misalnya dpkg-db-backup.timer pada mesin ini akan terbangun Jumat 00.00 untuk dpkg-db-backup.service.
Validasi tanpa Mengubah Sistem
Dua perintah berikut aman dijalankan kapan saja dan tidak menyentuh state sistem: systemd-analyze verify memeriksa sintaks dan kewajaran berkas unit, dan systemctl cat menampilkan unit yang sedang berlaku. Ketiga contoh unit untuk artikel ini (dua service dan satu timer) diuji dengan:
systemd-analyze verify /tmp/contoh/demo.service /tmp/contoh/demo.timer /tmp/contoh/demo-long.servicePerintah itu selesai tanpa keluaran dan berstatus nol, artinya ketiganya sah. Bila ada yang cacat, systemd menyebut masalah persis per baris. Untuk menelusuri perilaku unit yang sudah berjalan, systemctl status <unit> memadukan status, PID, dan potongan log, sementara journalctl -u <unit> menampilkan log lengkap unit itu.
Kesalahan Umum
Sebagian besar “misteri” systemd di lapangan berasal dari pola berikut.
- Lupa
daemon-reloadsetelah mengubah berkas unit. ExecStart=memakai path relatif atau operator shell, padahal harus path absolut.Type=oneshottanpaRemainAfterExit=yes, sehingga unit berstatus dead padahal selesai.WantedBy=dicantumkan tapisystemctl enabletidak dijalankan, jadi unit tidak ikut boot.- Mengira
startbertahan setelah reboot; padahal yang bertahan hanyaenable.
Penutup
Unit systemd tidaklah serumit penampakannya: tiga bagian, sekumpulan kunci kecil, dan dua perintah yang mengikatnya ke boot. Pahami dulu Type=, After= lawan Wants=, serta kebiasaan daemon-reload, dan sebagian besar layanan yang “tidak mau hidup” akan bisa dijelaskan dalam beberapa menit. Timer menjadikan penjadwalan tanpa cron menjadi lebih mudah dibaca, dan systemd-analyze verify memberi jaringan pengaman sebelum unit benar-benar dipicu.