Layanan yang berhenti bekerja jarang meninggalkan pesan yang jelas. Yang biasanya muncul hanya gejala: situs tidak bisa dibuka, antr...
Layanan yang berhenti bekerja jarang meninggalkan pesan yang jelas. Yang biasanya muncul hanya gejala: situs tidak bisa dibuka, antrean menumpuk, atau pengguna melapor bahwa aplikasi "kadang jalan kadang tidak". Di server Linux modern, sebagian besar jawaban atas gejala itu tersimpan di dua tempat: status unit yang dikelola systemd, dan catatan kejadian yang dikumpulkan journald lalu dibaca lewat journalctl. Audit layanan berarti membaca kedua sumber itu secara sistematis, bukan menebak lalu me-restart service berulang kali sampai kebetulan hidup.
Artikel ini membahas alur audit yang aman untuk layanan lokal: dari memastikan unit apa yang sebenarnya berjalan, membaca status dan propertinya, menelusuri log berdasarkan waktu dan prioritas, sampai membedakan layanan yang gagal start dari layanan yang hidup tetapi tidak melayani permintaan. Semua perintah yang ditampilkan bersifat baca-saja. Contohnya diambil dari pola laboratorium lokal berupa satu mesin virtual dengan beberapa service uji, dan bagian akhir menyebut secara eksplisit apa yang belum diuji, termasuk perilaku pada klaster besar, layanan berbasis container orchestration, dan environment dengan kebijakan log terpusat.
Meletakkan Dasar: Unit, Target, dan Sumber Kebenaran
systemd mengelola hampir semua hal sebagai unit: service, socket, timer, mount, target, dan sebagainya. Unit bukan sekadar skrip yang dijalankan sekali; ia adalah kontrak yang menyatakan bagaimana sebuah proses harus dimulai, dengan dependensi apa, di bawah pembatasan sumber daya apa, dan apa yang harus terjadi bila proses itu berhenti. Karena itu, audit yang benar dimulai dari membaca definisi unit, bukan dari menjalankan ulang perintah start. Kesalahan paling umum adalah memperbaiki gejala pada lapisan aplikasi padahal akar masalahnya ada pada kontrak unit: dependensi yang hilang, direktori kerja yang salah, atau user yang tidak punya izin ke berkas konfigurasi.
Inventaris cepat sebelum menyentuh apa pun
Langkah pertama adalah memetakan apa yang berjalan dan dari mana definisinya dibaca. systemd menggabungkan definisi dari beberapa lokasi, dan systemctl cat menampilkan hasil gabungan itu beserta komentar berisi path asal setiap fragmen — informasi yang sangat berguna ketika unit di-override oleh drop-in di direktori lain.
# Inventaris layanan yang sedang berjalan (baca-saja)
systemctl list-units --type=service --state=running --no-pager
# Lihat definisi unit beserta asal setiap fragmen konfigurasi
systemctl cat nginx.service
# Cek apakah ada drop-in override yang mengubah perilaku default
systemctl cat nginx.service | grep -n "^# /"
Baris komentar yang diawali path pada keluaran systemctl cat adalah petunjuk penting. Bila ada fragmen tambahan di /etc/systemd/system/<unit>.d/, berarti seseorang pernah mengubah perilaku unit tanpa menyentuh berkas aslinya. Saat audit, fragmen inilah yang sering menjelaskan mengapa dua server dengan paket versi sama berperilaku berbeda.
Prinsip aman: baca dulu, ubah belakangan
Audit yang baik menjaga batas antara observasi dan perubahan. Perintah seperti status, show, list-units, list-dependencies, dan journalctl tidak mengubah keadaan sistem. Sebaliknya, restart, reload, daemon-reload, edit, mask, dan set-property mengubah keadaan dan berpotensi memperpanjang gangguan. Pada layanan produksi, restart sering menghapus bukti: buffer log terbaru bisa terpotong, status failed hilang, dan penghitung restart kembali ke nol. Karena itu, kumpulkan dulu seluruh jejak, baru pertimbangkan tindakan.
Membaca Status Layanan Tanpa Menebak
Tiga pertanyaan pertama ke systemctl status
Keluaran systemctl status padat tetapi menjawab tiga pertanyaan sekaligus: apakah unit aktif, sejak kapan, dan apa yang terakhir dilaporkan prosesnya. Bagian Active: memuat status dan waktu masuknya, Loaded: menyebut apakah unit ditemukan dan apakah aktif saat boot, sedangkan Main PID menunjukkan proses utama yang diawasi. Bagian log di bawahnya adalah potongan journal terakhir untuk unit tersebut, bukan seluruh riwayat, sehingga sering menyesatkan bila dibaca sendirian.
# Keluaran ilustratif, bukan dari mesin produksi
$ systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Drop-In: /etc/systemd/system/nginx.service.d
└─override.conf
Active: failed (Result: exit-code) since ... ; 3min ago
Process: 1841 ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; ...' (code=exited, status=1/FAILURE)
Main PID: 1841 (code=exited, status=1/FAILURE)
Baris Process: dengan code=exited, status=1/FAILURE pada tahap ExecStartPre memberi petunjuk kuat: proses utama belum sempat berjalan, dan pemeriksaan konfigurasi yang gagal. Ini berbeda secara mendasar dari kasus ketika proses berjalan lalu mati sendiri — pada kasus kedua, status biasanya menyebut sinyal atau exit code dari proses utama, bukan dari tahap persiapan.
systemctl show: jawaban yang bisa diolah mesin
Untuk audit yang perlu dicatat atau dibandingkan antarwaktu, keluaran manusiawi kurang praktis. Properti seperti NRestarts, Result, ExecMainStatus, dan ActiveEnterTimestamp jauh lebih jujur daripada kesan visual pada keluaran status.
Perintah systemctl show nginx.service -p Result -p NRestarts -p ExecMainStatus sudah cukup untuk merekam fakta inti. Tambahkan FragmentPath dan DropInPaths bila laporan perlu menyebut dari mana definisi unit dibaca, dan simpan keluarannya beserta stempel waktu agar temuan bisa diverifikasi ulang.
Untuk daftar menyeluruh, systemctl list-units --state=failed cukup dipakai sekali dan hasilnya disimpan. Perhatikan bahwa unit yang gagal tidak selalu berupa service. Timer yang terakhir terpicu tetapi gagal, socket yang tidak bisa mengikat port, atau mount yang tidak terselesaikan juga muncul sebagai unit bermasalah. Audit yang hanya memeriksa service akan melewatkan kelas masalah ini.
journalctl sebagai Arsip Kejadian
Menyaring berdasarkan unit, prioritas, dan waktu
journalctl membaca catatan journald yang menyimpan metadata terstruktur: unit asal, PID, UID, prioritas syslog, dan identitas boot. Penyaringan berdasarkan metadata inilah yang membuatnya jauh lebih akurat daripada membaca berkas teks lalu mencari kata kunci. Filter --since dan --until menerima format waktu yang dapat dibaca manusia maupun format absolut, dan filter --boot memisahkan kejadian antar-reboot — penting ketika masalah muncul hanya setelah mesin dinyalakan ulang.
# Log satu unit sejak satu jam terakhir, hanya peringatan dan yang lebih berat
journalctl -u nginx.service --since "1 hour ago" -p warning --no-pager
# Bandingkan dengan boot sebelumnya untuk melihat apakah pola berulang
journalctl -u nginx.service -b -1 -p err --no-pager
# Ikuti kejadian real-time tanpa mengubah apa pun
journalctl -u nginx.service -f
Prioritas syslog berjalan dari 0 (emergency) sampai 7 (debug). Filter -p warning menampilkan prioritas 0 sampai 4, bukan hanya warning. Ini penting saat melaporkan temuan: menyebut "tidak ada error" padahal yang diperiksa hanya tingkat tertentu adalah klaim yang terlalu luas. Sebutkan filter yang dipakai agar pembaca laporan bisa menilai cakupannya.
Melacak satu siklus hidup
Untuk layanan yang bermasalah, urutan kejadian sering lebih informatif daripada isi pesan tunggal. Saring jendela waktu yang sempit di sekitar waktu start yang tercatat pada ActiveEnterTimestamp, lalu baca berurutan tanpa filter prioritas. Pola yang khas: pesan konfigurasi terbaca, lalu peringatan sumber daya, lalu kegagalan izin, lalu proses keluar. Membaca potongan journal bawaan status saja biasanya hanya menampilkan bagian akhir dari urutan itu.
Pola Diagnosis Unit yang Gagal Start
Ketika unit berstatus failed, urutan pemeriksaan yang konsisten menghemat waktu: pertama, apakah unit valid menurut systemd; kedua, apakah perintah pada baris eksekusi bisa dijalankan sendiri; ketiga, apakah dependensinya siap. Perintah systemd-analyze verify memeriksa kesalahan sintaks dan referensi unit tanpa menjalankan layanan, sehingga aman dipakai pada sistem hidup. Setelah itu, jalankan perintah dari baris ExecStart secara manual dengan user dan direktori kerja yang sama seperti yang dideklarasikan unit — perbedaan hasil di sini langsung menunjukkan masalah lingkungan, bukan masalah aplikasi.
# 1. Validasi definisi unit tanpa menjalankannya
systemd-analyze verify /etc/systemd/system/app-worker.service
# 2. Bandingkan lingkungan yang dijanjikan unit dengan kenyataan
systemctl show app-worker.service -p User -p Group -p WorkingDirectory \
-p Environment -p EnvironmentFiles -p ExecStart
# 3. Lihat urutan dependensi dan unit yang menahannya
systemctl list-dependencies app-worker.service --no-pager
# 4. Periksa kegagalan terdokumentasi di sekitar waktu start
journalctl -u app-worker.service --since "15 min ago" --no-pager
Kesalahan yang sering muncul di lab lokal: unit dideklarasikan dengan User=app tetapi direktori kerja dimiliki root dengan mode yang tidak memberi izin baca; berkas environment dirujuk lewat path relatif; atau After= menyebut unit yang namanya salah ketik sehingga urutan start tidak pernah berlaku. Semua kasus ini tidak menghasilkan pesan "aplikasi rusak", melainkan pesan yang tampak remeh seperti permission denied atau no such file. Karena itu, baca pesan pertama, bukan pesan terakhir.
Layanan Hidup tetapi Tidak Melayani
Kelas masalah kedua lebih licin: Active: active (running), proses utama ada, tetapi permintaan tidak dilayani. systemd hanya tahu prosesnya hidup; ia tidak tahu apakah proses itu melakukan pekerjaannya. Di sini audit berpindah ke lapisan jaringan dan aplikasi: apakah port benar-benar terikat, pada alamat apa, dan oleh proses mana. ss menjawab pertanyaan itu dengan tepat karena menampilkan socket yang sedang mendengarkan beserta PID pemiliknya.
# Apakah port benar-benar terikat, dan pada alamat apa
ss -ltnp | grep -E ':(80|443|8080)\b'
# Apakah unit dibatasi oleh properti tertentu (mis. IPAddressAllow)
systemctl show nginx.service -p IPAddressAllow -p Restart -p RestartSec -p LimitNOFILE
# Cek apakah unit lain sudah memegang port yang sama
systemctl list-sockets --no-pager
Pola yang sering ditemui: layanan mendengarkan pada 127.0.0.1 padahal diharapkan menerima koneksi dari antarmuka lain, atau sebaliknya, terikat pada semua antarmuka ketika seharusnya terbatas. Ada juga kasus ketika unit lama masih memegang port setelah proses baru gagal mengambil alih, sehingga status terlihat sehat sementara lalu lintas dilayani oleh proses yang salah. Membandingkan PID pada ss dengan MainPID dari systemctl show memastikan keduanya merujuk proses yang sama.
Menjaga Audit Tetap Ringan dan Dapat Dipertanggungjawabkan
Catatan penting: journald membatasi laju pesan per layanan secara default agar disk tidak banjir. Bila audit dilakukan tepat setelah layanan menghasilkan ribuan pesan dalam waktu singkat, sebagian entri bisa ditandai sebagai suppressed dan tidak muncul pada pembacaan biasa. Periksa batas ini sebelum menyimpulkan bahwa suatu kejadian "tidak tercatat", dan pertimbangkan pencatatan log terpusat untuk sistem yang serius. Mengubah batas laju adalah perubahan konfigurasi, bukan bagian dari audit baca-saja.
Menyimpan jejak sebagai bukti
Audit yang tidak meninggalkan bukti sulit ditindaklanjuti. Simpan keluaran systemctl show dan potongan journal ke berkas dengan stempel waktu, lalu sebutkan perintah persis yang dipakai. journalctl juga bisa mengeluarkan format JSON (-o json) yang mempertahankan metadata lengkap untuk analisis lanjutan, misalnya menghitung frekuensi pesan per unit. Untuk organisasi, pengiriman journal ke sistem log terpusat membuat riwayat bertahan meski mesin di-rebuild — tetapi itu keputusan arsitektur, bukan langkah audit harian.
Contoh Lab Lokal dan Apa yang Belum Diuji
Pada lab lokal berupa satu VM dengan tiga unit uji — sebuah web server, sebuah worker antrean, dan satu timer pembersih — alur di atas cukup untuk menemukan dua jenis masalah berbeda dalam satu sesi. Kasus pertama adalah worker yang gagal start karena berkas environment tidak terbaca oleh user yang dideklarasikan; jejaknya terlihat pada baris ExecStartPre dan pesan izin di journal. Kasus kedua adalah web server yang aktif tetapi tidak menerima koneksi karena terikat hanya ke loopback; jejaknya hanya terlihat lewat ss, bukan lewat status unit. Kedua kasus diselesaikan tanpa restart berulang, karena bukti sudah dikumpulkan lebih dulu.
Yang belum diuji dan sebaiknya tidak diklaim: perilaku audit pada klaster dengan ratusan unit dan log terpusat, layanan yang dikelola orchestrator container di mana systemd hanya mengawasi proses pembungkus, unit dengan Restart=always yang menghasilkan siklus gagal berulang cepat, serta kebijakan rotasi journal yang sudah diubah dari default. Efek ProtectSystem, PrivateTmp, dan sandboxing lain terhadap aplikasi tertentu juga tidak diverifikasi di sini; bila unit memakai direktif tersebut, hasil pengujian manual di shell bisa berbeda dari hasil di dalam unit. Terakhir, tidak ada angka performa yang dilaporkan karena pengukuran waktu start dan beban journal sangat bergantung pada perangkat keras serta bentuk beban kerja, dan angka dari satu VM lab tidak layak digeneralisasi.
Rujukan resmi untuk detail setiap subperintah dan direktif adalah dokumentasi freedesktop: systemctl(1), journalctl(1), dan systemd.unit(5). Ketiganya menjadi acuan utama ketika perilaku pada distribusi tertentu tampak menyimpang dari kebiasaan: versi systemd yang lebih lama sering berbeda dalam dukungan direktif dan format keluaran.
Kesimpulannya sederhana. Audit layanan Linux bukan kegiatan mistis yang bergantung pada keberuntungan saat me-restart. Ia adalah urutan pemeriksaan yang dapat diulang: pastikan unit dan override-nya, rekam fakta dari systemctl show, telusuri journal dengan filter waktu dan prioritas yang eksplisit, lalu periksa lapisan socket ketika status sudah menyatakan aktif. Dengan urutan itu, setiap temuan punya bukti, setiap kesimpulan punya batas cakupan, dan tindakan perbaikan bisa dipilih dengan alasan yang jelas.
COMMENTS