Bab 34 menutup Bagian VIII dengan checklist keamanan yang merangkum lima lapisan defense in depth sejak Bab 30. Bagian IX yang dimulai dari bab ini mengambil arah yang berbeda. Alih-alih menambah lapisan pertahanan baru, kita mengangkat satu kebiasaan yang sebenarnya sudah berulang kali dipraktikkan sepanjang series ini tanpa pernah dibahas secara utuh, yaitu shell scripting untuk automasi server. Bab 5 memperkenalkan systemd timer sebagai pengganti cron sambil berjanji membahasnya lebih dalam di sini. Bab 23 menulis script bash yang mengotomasi backup empat database sekaligus, lengkap dengan baris set -euo pipefail yang penjelasan mendalamnya sengaja ditunda sampai bab ini. Bab ini menepati kedua janji tersebut sekaligus membuka Bagian IX, gerbang menuju Infrastructure as Code yang akan berlanjut ke Ansible di Bab 36 dan cloud-init di Bab 37.
Skenarionya familier bagi Sysadmin mana pun yang pernah mengelola server produksi. Sebuah script cleanup yang ditulis buru-buru berjalan dua kali sekaligus lewat cron karena eksekusi sebelumnya belum selesai, lalu menghapus file yang justru sedang ditulis proses lain. Script backup yang "kelihatan" berhasil padahal salah satu tahapnya gagal diam-diam, karena tidak ada satu baris pun yang menghentikan eksekusi begitu terjadi error. Kedua insiden ini punya akar masalah yang sama: script ditulis seolah selalu dijalankan manusia yang mengawasi outputnya, padahal tujuannya justru berjalan tanpa pengawasan lewat cron atau systemd timer.
Kita akan mulai dengan menyegarkan cepat konvensi script shell yang aman untuk automasi, dilanjutkan menulis tiga script administrasi yang lazim dibutuhkan sehari-hari yaitu backup file konfigurasi, cleanup log, dan health check server. Bagian inti bab ini membedah error handling dan logging secara mendalam, termasuk trap dan flock yang belum pernah disinggung sebelumnya. Kita menutup bab dengan menjadwalkan seluruh script tersebut lewat cron dan systemd timer, sekaligus kapan sebaiknya memilih salah satu di antara keduanya.
35.1 Review Shell Scripting untuk Automasi Server
Series prasyarat Linux 101 sudah mengenalkan dasar shell scripting, jadi bagian ini bukan pengulangan penuh. Fokusnya menyegarkan konvensi yang relevan ketika sebuah script tidak lagi dijalankan manual oleh manusia di depan terminal, melainkan dipicu otomatis oleh cron atau systemd timer tanpa ada siapa pun yang mengawasi outputnya secara langsung.
35.1.1 Konvensi Script yang Aman untuk Dijalankan Otomatis
Beberapa kebiasaan yang mungkin terasa opsional saat menulis script untuk dijalankan manual justru jadi wajib begitu script itu dijadwalkan otomatis. Shebang #!/bin/bash di baris pertama menentukan interpreter yang dipakai, dan sebaiknya eksplisit memakai bash alih-alih sh karena fitur seperti array dan [[ ]] yang akan kita pakai di bab ini adalah ekstensi bash, bukan bagian dari POSIX shell standar. Path harus ditulis absolut, bukan relatif, karena cron dan systemd menjalankan script dari non-interactive shell yang tidak membaca ~/.bashrc maupun PATH yang biasa aktif di sesi SSH interaktif kita. Variable yang menampung path sebaiknya selalu dikutip dengan tanda kutip ganda seperti "$VAR", karena path yang mengandung spasi akan pecah jadi beberapa argumen terpisah tanpa tanda kutip tersebut. Terakhir, exit code punya arti penting di konteks automasi: 0 menandakan sukses, angka selain itu menandakan gagal, dan systemd maupun cron mengandalkan angka ini untuk mendeteksi apakah sebuah job benar-benar berhasil, bukan dari ada tidaknya output di layar yang toh tidak ada yang membacanya secara langsung.
Langkah Praktik
- Buat direktori tempat menyimpan seluruh script automasi yang akan ditulis sepanjang bab ini.
sudo mkdir -p /usr/local/bin - Buat file template yang menjadi dasar seluruh script pada bagian berikutnya.
sudo nano /usr/local/bin/template.sh - Isi dengan struktur minimal berikut.
Baris#!/bin/bash # # Template dasar script automasi set -euo pipefail log() { echo "[$(date '+%F %T')] $*" } main() { log "Script dimulai" log "Script selesai" } main "$@"set -euo pipefaildan fungsilog()sengaja belum dijelaskan detail di sini; keduanya dibedah tuntas di Bagian 35.3. - Ubah izin file agar dapat dieksekusi, lalu jalankan.
sudo chmod +x /usr/local/bin/template.sh /usr/local/bin/template.sh
Verifikasi dan Troubleshooting
- Periksa exit code setelah script selesai berjalan; angka
0menandakan sukses.echo $? - Error
Permission deniedsaat menjalankan script hampir selalu berarti langkahchmod +xterlewat. - Jika script memanggil binary yang terpasang di lokasi tidak umum seperti
/snap/bin, jangan mengandalkanPATHdefault. Tulis path lengkapnya langsung di dalam script, kebiasaan yang menjadi sangat relevan begitu kita masuk ke penjadwalan cron di Bagian 35.4.1.
35.2 Script untuk Task Administrasi Umum
Tiga skenario berikut adalah task administrasi yang paling sering ditulis ulang oleh Sysadmin di berbagai server: backup file di luar database, pembersihan file yang menumpuk, dan pengecekan kesehatan server secara berkala. Ketiganya memakai struktur template dari Bagian 35.1.1 sebagai basis.
35.2.1 Backup Otomatis File dan Direktori Konfigurasi
Bab 23 sudah membahas backup khusus database lewat pg_dump, mysqldump, dan tool sejenisnya. File konfigurasi di /etc serta direktori webroot memerlukan pendekatan berbeda, karena isinya bukan dump database melainkan kumpulan file dan direktori biasa yang lebih cocok dikemas dengan tar.
Langkah Praktik
- Buat script backup konfigurasi.
sudo nano /usr/local/bin/backup-config.sh - Isi dengan script berikut, sesuaikan
SOURCE_DIRSdengan direktori yang relevan di server ini.
Pola retention dengan#!/bin/bash set -euo pipefail BACKUP_DIR="/var/backups/config" SOURCE_DIRS=("/etc" "/var/www") RETENTION_DAYS=14 TIMESTAMP=$(date +%Y%m%d-%H%M%S) mkdir -p "$BACKUP_DIR" chmod 700 "$BACKUP_DIR" tar czf "$BACKUP_DIR/config-$TIMESTAMP.tar.gz" "${SOURCE_DIRS[@]}" chmod 600 "$BACKUP_DIR/config-$TIMESTAMP.tar.gz" find "$BACKUP_DIR" -type f -name "config-*.tar.gz" -mtime +"$RETENTION_DAYS" -delete echo "Backup selesai: config-$TIMESTAMP.tar.gz"find -mtime +N -deleteini persis seperti yang sudah dipraktikkan di Bagian 23.6.2, hanya diterapkan ke filetar.gzalih-alih dump database. Dua barischmoddi atas bukan sekadar formalitas:/etcyang ikut di-backup memuat/etc/shadowberisi hash password seluruh user, sehingga arsip hasil backup ini sama sensitifnya dengan file aslinya. Tanpa pembatasan izin eksplisit, filetar.gzyang baru dibuat mengikuti umask default sistem yang pada banyak server masih menghasilkan izin644, alias bisa dibaca semua user lokal, sebuah pelanggaran nyata terhadap prinsip least privilege yang sudah kita bahas di Bagian 34.2. - Ubah izin file agar dapat dieksekusi, lalu uji jalankan.
sudo chmod +x /usr/local/bin/backup-config.sh sudo /usr/local/bin/backup-config.sh
Verifikasi dan Troubleshooting
- Pastikan file arsip baru muncul dengan izin yang sudah dibatasi, dan isinya benar.
Kolom izin padals -lh /var/backups/config tar tzf /var/backups/config/config-*.tar.gz | headls -lhsemestinya menampilkan-rw-------untuk filetar.gz-nya, hasil darichmod 600pada script. - GNU tar biasanya juga mencetak baris peringatan
tar: Removing leading '/' from member nameske layar saat mengemas path absolut seperti/etc. Ini bukan tanda kegagalan, hanya pemberitahuan bahwa tar menyimpan path secara relatif di dalam arsip, kebiasaan standar yang justru membuat hasil restore-nya lebih aman karena tidak otomatis menimpa/etcyang asli begitu saja saat diekstrak. - Catatan penting dari lapangan soal
tar: exit code1bukan selalu berarti backup gagal total. GNU tar mengembalikan1ketika ada file yang berubah persis saat sedang dibaca, misalnya log aplikasi yang terus ditulis proses lain, sementara exit code2baru menandakan kegagalan fatal seperti direktori sumber tidak ditemukan. Karenaset -emenganggap exit code selain0sebagai kegagalan, hal ini bisa membuat script berhenti untuk peringatan yang sebenarnya tidak fatal. Poin ini dibedah lebih jauh di Bagian 35.3.1. - Jika muncul
Permission deniedsaat membaca isi/etc, jalankan script dengansudoseperti pada langkah praktik, karena sebagian file di dalamnya memang sengaja dibatasi hanya bisa dibaca root.
35.2.2 Cleanup Log dan File Temporer
logrotate yang dibahas tuntas di Bab 39 menangani rotasi log standar dengan baik, tetapi tidak semua file perlu dirotasi. File temporer aplikasi, hasil export sementara, atau log kustom yang formatnya tidak dikenali logrotate tetap memerlukan script pembersihan sendiri.
Langkah Praktik
- Buat script cleanup dengan dukungan mode dry-run, yaitu mode simulasi yang hanya menampilkan file yang akan dihapus tanpa benar-benar menghapusnya.
sudo nano /usr/local/bin/cleanup-temp.sh - Isi dengan script berikut.
Argumen#!/bin/bash set -euo pipefail TARGET_DIR="/var/log/myapp" MAX_AGE_DAYS=30 MODE="${1:-}" if [[ "$MODE" == "--dry-run" ]]; then echo "Mode dry-run, tidak ada file yang dihapus" find "$TARGET_DIR" -type f -mtime +"$MAX_AGE_DAYS" -print else find "$TARGET_DIR" -type f -mtime +"$MAX_AGE_DAYS" -delete echo "File lebih dari $MAX_AGE_DAYS hari di $TARGET_DIR sudah dihapus" fi$1ditangkap lewat"${1:-}", bukan"$1"polos, karenaset -upada barisset -euo pipefailmembuat bash berhenti dengan error begitu argumen ini tidak diisi sama sekali. Sintaks${1:-}memberi nilai default berupa string kosong jika argumennya memang tidak ada. - Ubah izin file agar dapat dieksekusi, lalu selalu uji lebih dulu dengan dry-run sebelum menjalankan versi yang benar-benar menghapus file.
sudo chmod +x /usr/local/bin/cleanup-temp.sh sudo /usr/local/bin/cleanup-temp.sh --dry-run - Setelah daftar file pada langkah dry-run sudah dipastikan benar, jalankan tanpa argumen untuk menghapus sungguhan.
sudo /usr/local/bin/cleanup-temp.sh
Verifikasi dan Troubleshooting
- Kebiasaan menjalankan dry-run lebih dulu ini sengaja ditekankan karena pengalaman lapangan yang berulang: banyak insiden salah hapus file produksi berawal dari script cleanup yang langsung dijalankan tanpa pernah diperiksa dulu daftar targetnya.
- Jika direktori target belum ada,
findakan melempar errorNo such file or directory. PastikanTARGET_DIRsudah disesuaikan dengan direktori nyata di server ini sebelum dijalankan. - Untuk kebutuhan pembersihan generik pada direktori
/tmp, systemd sendiri sudah menyediakan mekanisme bawaan lewatsystemd-tmpfilesyang dikonfigurasi di/etc/tmpfiles.d/. Script kustom seperti di atas tetap lebih cocok dipakai ketika logika pembersihannya spesifik untuk satu aplikasi, misalnya perlu memeriksa pola nama file tertentu sebelum menghapus.
35.2.3 Health Check Server Sederhana
Sebelum masuk ke tool monitoring modern seperti Netdata dan Prometheus di Bab 38, script health check sederhana sudah cukup untuk mendeteksi dua masalah paling umum di server produksi, yaitu disk yang hampir penuh dan service kritikal yang berhenti tanpa terdeteksi.
Langkah Praktik
- Buat script health check.
sudo nano /usr/local/bin/health-check.sh - Isi dengan script berikut, sesuaikan daftar
SERVICESdengan service yang benar-benar berjalan di server ini.
Perintah#!/bin/bash set -euo pipefail DISK_THRESHOLD=85 SERVICES=("nginx" "postgresql") check_disk() { local usage usage=$(df --output=pcent / | tail -1 | tr -dc '0-9') if (( usage >= DISK_THRESHOLD )); then logger -t health-check -p user.crit "Disk root sudah $usage%, di atas ambang batas $DISK_THRESHOLD%" echo "PERINGATAN: disk root $usage%" fi } check_services() { for svc in "${SERVICES[@]}"; do if ! systemctl is-active --quiet "$svc"; then logger -t health-check -p user.crit "Service $svc tidak aktif" echo "PERINGATAN: service $svc tidak aktif" fi done } check_disk check_services echo "Health check selesai"loggermengirim pesan langsung ke systemd journal dengan taghealth-checkdan prioritascrit, sehingga hasil pengecekan tetap tercatat rapi walau tidak ada satu barisechopun yang sempat terbaca oleh manusia secara langsung. - Ubah izin file agar dapat dieksekusi, lalu uji jalankan.
sudo chmod +x /usr/local/bin/health-check.sh sudo /usr/local/bin/health-check.sh
Verifikasi dan Troubleshooting
- Cari catatan yang sudah dikirim
loggerke journal berdasarkan tag-nya.journalctl -t health-check -n 20 - Uji jalur peringatan service dengan menghentikan sementara salah satu service dari daftar
SERVICES, jalankan lagi script tersebut, lalu aktifkan kembali service tersebut setelah pengujian selesai agar server tidak tertinggal dalam kondisi mati. - Perlu disampaikan secara jujur soal batasan script ini: script ini hanya mencatat kondisi kritis ke journal, bukan mengirim notifikasi aktif lewat email atau chat. Alerting yang benar-benar mendorong notifikasi ke Sysadmin dibahas lebih lengkap lewat tool khusus di Bagian 38.4, karena membangun jalur notifikasi yang andal (email, webhook, atau integrasi chat) memerlukan infrastruktur tambahan di luar cakupan satu script sederhana.
- Dua pengecekan di atas sengaja dijaga minimal agar mudah dipahami. Di lapangan, fungsi serupa biasa diperluas dengan pengecekan memory lewat
free -matau beban sistem lewatuptime, mengikuti polacheck_disk()dancheck_services()yang sama persis: bandingkan angka terhadap ambang batas, lalu catat lewatloggerjika terlampaui.
35.3 Error Handling dan Logging di Script
Ketiga script pada Bagian 35.2 semuanya memakai set -euo pipefail tanpa penjelasan mendalam, mengikuti kebiasaan yang sama seperti script backup database di Bagian 23.6.2. Bagian ini akhirnya membedah tuntas apa yang sebenarnya terjadi di balik baris itu, ditambah dua kebiasaan lain yang sama pentingnya untuk script yang berjalan tanpa pengawasan yaitu trap dan flock.
35.3.1 set -euo pipefail Secara Mendalam
Baris set -euo pipefail sebenarnya adalah tiga opsi bash yang digabung jadi satu, dan masing-masing menutup celah yang berbeda.
-emenghentikan script begitu ada perintah yang keluar dengan exit code selain0. Tanpa opsi ini, bash secara default akan terus lanjut ke baris berikutnya meski satu perintah di tengah gagal, seolah tidak terjadi apa-apa. Perlu dicatat,-epunya pengecualian yang sering membingungkan: perintah yang jadi bagian dari kondisiif/while, bagian dari daftar&&atau||, atau didahului tanda!, tidak menghentikan script meski gagal, karena bash menganggap kegagalannya memang sengaja diperiksa secara eksplisit di titik itu. Barisif ! systemctl is-active --quiet "$svc"di Bagian 35.2.3 memanfaatkan pengecualian ini secara sengaja.-umenghentikan script begitu ada variable yang belum pernah didefinisikan tapi dipakai. PesanMONGO_USER: unbound variableyang muncul di Bagian 23.6.2 adalah contoh nyata opsi ini bekerja, dan pola"${1:-}"di Bagian 35.2.2 adalah cara aman menangkap argumen opsional tanpa memicu error tersebut.-o pipefailmengubah cara bash menilai keberhasilan sebuah pipeline. Tanpa opsi ini, exit code sebuah pipeline hanya diambil dari perintah paling kanan, sehinggamysqldump | gzippada Bagian 23.6.2 akan tetap dianggap sukses meskimysqldumpdi sisi kiri sebenarnya gagal total, selamagzipsendiri tidak ikut gagal.pipefailmembuat exit code pipeline mengikuti perintah manapun di dalamnya yang gagal, bukan hanya yang terakhir.
Ketiganya bekerja sama membuat script menerapkan prinsip fail fast, yaitu berhenti secepat mungkin begitu ada yang tidak beres, alih-alih melanjutkan eksekusi dengan asumsi keliru bahwa semuanya baik-baik saja. Prinsip ini krusial untuk script yang dijalankan otomatis tanpa pengawasan, karena tidak ada manusia yang membaca output-nya secara langsung untuk menyadari sesuatu sudah salah di tengah jalan. Satu pengecualian yang jujur perlu diketahui, seperti kasus exit code 1 dari tar di Bagian 35.2.1, adalah beberapa tool memang memakai exit code non-nol untuk peringatan yang sebenarnya tidak fatal. Untuk kasus semacam itu, tambahkan penanganan eksplisit alih-alih membiarkan set -e menghentikan script secara tidak semestinya, misalnya dengan memeriksa exit code secara manual lewat $? dan hanya menghentikan script jika nilainya benar-benar di atas ambang yang dianggap fatal.
35.3.2 trap untuk Cleanup dan Penanganan Error
trap adalah builtin bash yang menjalankan sebuah perintah begitu script menerima sinyal tertentu. Dua sinyal yang paling relevan untuk automasi adalah EXIT, yang selalu terpicu begitu script berhenti apa pun penyebabnya, dan ERR, yang khusus terpicu saat sebuah perintah gagal dan diikuti opsi -e dari Bagian 35.3.1. Kombinasi keduanya memastikan proses cleanup tetap berjalan dan detail error tetap tercatat, bahkan ketika script berhenti mendadak di tengah jalan.
Langkah Praktik
- Modifikasi
template.shdari Bagian 35.1.1 untuk menambahkan penanganan trap.sudo nano /usr/local/bin/template.sh - Tambahkan fungsi dan trap berikut tepat di bawah
set -euo pipefail.
VariableTMP_FILE=$(mktemp) cleanup() { log "Menghapus file temporer: $TMP_FILE" rm -f "$TMP_FILE" } trap cleanup EXIT error_handler() { logger -t template-script -p user.err "Gagal di baris $1 saat menjalankan: $2" } trap 'error_handler $LINENO "$BASH_COMMAND"' ERR$LINENOberisi nomor baris tempat error terjadi, sedangkan$BASH_COMMANDberisi perintah persis yang sedang dijalankan saat itu. Keduanya hanya valid dipakai di dalam trapERR, bukan di sembarang bagian script. - Uji trap dengan sengaja menyisipkan perintah yang pasti gagal, misalnya
false, lalu jalankan.echo 'false' >> /usr/local/bin/template.sh sudo /usr/local/bin/template.sh; echo "exit code: $?"
Verifikasi dan Troubleshooting
- Pastikan pesan error tercatat di journal lengkap dengan nomor baris.
journalctl -t template-script -n 5 - Perhatikan baris log
Menghapus file temporer: /tmp/tmp.xxxxxxxxxxyang tercetak di output langkah sebelumnya, lalu salin path lengkapnya untuk konfirmasi file itu sudah benar-benar hilang, meski script berhenti karena error, tanda trapEXITtetap berjalan.
Path aslinya acak setiap kali script dijalankan karena dibuat olehls /tmp/tmp.xxxxxxxxxx 2>&1mktemp, jadi gantitmp.xxxxxxxxxxdengan nama file persis yang muncul di output pada perangkat masing-masing. - Hapus baris
falsepercobaan setelah pengujian selesai, karena baris itu sengaja disisipkan hanya untuk memicu kegagalan. - Jangan menaruh perintah yang berpotensi gagal di dalam fungsi
cleanup()itu sendiri. TrapEXIThanya berjalan sekali, dan jika perintah di dalamnya ikut gagal, proses cleanup bisa berhenti di tengah jalan tanpa ada trap lain yang menangkapnya.
35.3.3 Logging Terstruktur dan Mencegah Job Tumpang Tindih dengan flock
Dua kebiasaan terakhir ini sering luput dari script yang ditulis terburu-buru, padahal keduanya adalah sumber insiden yang cukup umum ditemui di lapangan. Logging yang hanya mengandalkan echo polos akan hilang begitu saja ketika script dijalankan lewat cron tanpa redirect eksplisit, dan tanpa mekanisme lock file, job yang jadwalnya tumpang tindih dengan eksekusi sebelumnya yang belum selesai bisa berjalan bersamaan, menciptakan race condition di mana dua proses berebut menulis ke resource yang sama.
Langkah Praktik
- Tambahkan mekanisme lock di awal
health-check.shdari Bagian 35.2.3, tepat di bawahset -euo pipefail.sudo nano /usr/local/bin/health-check.sh - Sisipkan baris berikut.
LOCK_FILE="/run/lock/health-check.lock" exec 200>"$LOCK_FILE" if ! flock -n 200; then echo "Instance lain sedang berjalan, keluar" exit 1 fiexec 200>"$LOCK_FILE"membuka file lock lewat file descriptor nomor200, nomor yang sengaja dipilih tinggi untuk menghindari bentrok dengan descriptor standar (0,1,2) yang sudah dipakai bash sendiri.flock -n 200mencoba mengunci descriptor tersebut tanpa menunggu (-nuntuk non-blocking); jika gagal karena instance lain sudah memegang lock yang sama, script langsung keluar dengan exit code1. Lock ini otomatis terlepas begitu script selesai, tanpa perlu dihapus manual. - Uji dengan menjalankan script dua kali hampir bersamaan di dua terminal berbeda, atau simulasikan lewat perintah berikut.
sudo /usr/local/bin/health-check.sh & sudo /usr/local/bin/health-check.sh wait
Verifikasi dan Troubleshooting
- Salah satu dari dua eksekusi pada langkah pengujian semestinya menampilkan pesan
Instance lain sedang berjalan, keluardan keluar dengan exit code1, sementara yang satunya berjalan normal sampai selesai. - Terapkan pola
flockyang sama kebackup-config.shdancleanup-temp.shdari Bagian 35.2, terutama untuk server dengan volume data besar di mana proses backup berpotensi berjalan lebih lama dari interval jadwalnya sendiri. - Untuk logging terstruktur yang konsisten, kombinasikan fungsi
log()dari Bagian 35.1.1 denganloggerseperti padahealth-check.sh:echountuk output yang terbaca saat pengujian manual,loggeruntuk pencatatan permanen ke journal yang nantinya bisa disentralisasi lewat rsyslog di Bab 39.
35.4 Menjadwalkan Script dengan Cron dan Systemd Timer
Bab 5 dan Bab 23 sudah mempraktikkan systemd timer secara langsung untuk menjadwalkan job. Bagian ini melengkapi sisi yang belum pernah dibahas, yaitu cron, sekaligus menutup bab dengan panduan memilih di antara keduanya.
35.4.1 Cron dan Crontab
Cron sudah jadi standar penjadwalan job di sistem Unix selama puluhan tahun, dan paket cron pada umumnya sudah terpasang secara default di Ubuntu Server 26.04 LTS. crontab -e membuka editor untuk mengubah jadwal milik user yang sedang login, dengan format lima kolom waktu diikuti perintah: menit, jam, tanggal, bulan, dan hari dalam minggu, masing-masing bisa diisi angka spesifik, tanda * untuk "setiap", atau step seperti */15 untuk "setiap 15 satuan". Cron juga mendukung string pintasan seperti @reboot, @daily, dan @hourly untuk jadwal yang umum, tanpa perlu menulis lima kolom lengkap.
Langkah Praktik
- Pasang paket
cronjika belum terpasang; perintah ini aman dijalankan meski paketnya sudah ada, apt hanya akan melaporkan versi terbaru sudah terpasang.sudo apt install cron systemctl status cron - Buka crontab milik user root.
health-check.shperlu berjalan sebagai root supayasystemctl is-activepada Bagian 35.2.3 bisa memeriksa seluruh service secara konsisten dan lock file di/run/lockdari Bagian 35.3.3 bisa dibuat tanpa error izin, sejalan dengan cara script ini diuji manual lewatsudosepanjang bab ini.sudo crontab -e - Tambahkan baris berikut untuk menjalankan health check setiap 15 menit, dengan output dialihkan eksplisit ke file log.
Redirect*/15 * * * * /usr/local/bin/health-check.sh >> /var/log/health-check-cron.log 2>&12>&1ini penting karena environment cron tidak terhubung ke terminal mana pun. Tanpa redirect eksplisit, cron sebenarnya tetap menangkap output tersebut lalu mencoba mengirimkannya lewat email ke alamat yang diisikan di variableMAILTOpada crontab, atau ke user pemilik crontab jikaMAILTOtidak diisi. Pada praktiknya, pengiriman ini sering gagal diam-diam kalau server belum punya MTA seperti Postfix terpasang, sehingga output yang tidak di-redirect eksplisit maupun ditanganiloggerberisiko hilang begitu saja tanpa jejak. - Simpan lalu konfirmasikan jadwal sudah tercatat.
sudo crontab -l
Verifikasi dan Troubleshooting
- Tunggu hingga jadwal berikutnya tiba, lalu periksa log eksekusi cron itu sendiri lewat tag
CRONyang otomatis dikirim ke journal.journalctl -t CRON -n 20 - Periksa juga isi file log yang sudah ditentukan di langkah ketiga.
cat /var/log/health-check-cron.log - Job yang berjalan normal lewat terminal tapi gagal lewat cron biasanya disebabkan
PATHyang jauh lebih terbatas di environment cron dibanding sesi shell interaktif. Pastikan setiap binary yang dipanggil dari dalam script sudah ditulis dengan path absolut, sesuai kebiasaan yang sudah ditekankan di Bagian 35.1.1. - Selain crontab per-user, entri terjadwal juga bisa ditulis langsung di
/etc/cron.d/untuk kebutuhan sistem-wide. Formatnya sama seperti crontab biasa, hanya ditambah satu kolom nama user di antara kolom waktu dan perintah.
35.4.2 Memilih antara Cron dan Systemd Timer
Kedua tool sama-sama valid, dan perbedaannya lebih soal fitur yang dibutuhkan daripada mana yang "lebih baik" secara mutlak.
| Aspek | Cron | Systemd Timer |
|---|---|---|
| Logging | Perlu redirect manual ke file atau logger | Otomatis masuk journalctl lewat unit service-nya |
| Job yang terlewat saat server mati | Tidak dijalankan ulang kecuali dibantu anacron tambahan | Persistent=true otomatis menjalankan begitu server menyala kembali |
| Dependency antar service | Tidak didukung langsung | Bisa memakai After=, Requires= seperti Bagian 5.4 |
| Jumlah file konfigurasi | Satu baris di crontab | Dua unit file terpisah (.timer dan .service) |
| Portabilitas | Tersedia luas di hampir semua sistem mirip Unix | Hanya tersedia di sistem berbasis systemd |
Pada Ubuntu Server modern, systemd timer jadi pilihan default yang masuk akal untuk job penting di production, terutama yang butuh jaminan tetap jalan meski server sempat mati saat jadwalnya tiba, seperti backup database di Bagian 23.7. Cron tetap relevan untuk automasi cepat dan sederhana, terutama saat mengikuti dokumentasi resmi sebuah tool pihak ketiga yang sudah menyediakan contoh entri cron siap pakai, atau ketika script yang sama perlu dijalankan juga di sistem non-systemd. Sebagai tambahan, systemd timer juga mendukung penjadwalan relatif lewat directive OnBootSec dan OnUnitActiveSec, berguna untuk job yang cukup dijalankan beberapa menit setelah boot atau beberapa jam sejak eksekusi terakhirnya, tanpa perlu terikat jam pasti seperti OnCalendar yang sudah dipraktikkan sejak Bagian 5.3.1.
Verifikasi dan Troubleshooting
- Lihat seluruh job terjadwal yang aktif di server ini, baik lewat cron maupun systemd timer, sebagai langkah audit sebelum menutup bab ini.
sudo crontab -l systemctl list-timers - Hindari menjadwalkan job yang sama lewat cron dan systemd timer sekaligus. Duplikasi semacam ini sering luput diperhatikan di server yang sudah dikelola bergantian oleh beberapa Sysadmin, dan berpotensi memicu race condition yang sama seperti dibahas di Bagian 35.3.3, meski masing-masing script sudah dilindungi
flock.
Sampai di sini, kita punya fondasi automasi yang solid untuk satu server: script yang ditulis dengan konvensi aman, tiga contoh task administrasi siap pakai, error handling yang tidak lagi gagal diam-diam, serta dua pilihan scheduler untuk menjalankannya tanpa campur tangan manual. Batasannya juga mulai terasa di titik ini. Setiap script di atas hanya berlaku untuk satu server, dan menyalin baris demi baris ke server lain begitu jumlah server bertambah jelas bukan pendekatan yang bisa bertahan lama. Bab 36 membuka jawabannya lewat Ansible, tool Infrastructure as Code yang menjalankan konfigurasi serupa ke banyak server sekaligus dari satu control node, dimulai dari konsepnya sebelum masuk ke instalasi dan playbook pertama.

