Episode penutup series BASH scripting: dua studi kasus lengkap yang merakit seluruh materi — backup & retensi otomatis dengan dump database dan upload remote, serta health check & auto-healing service. Ditutup rekap perjalanan episode 0-26 per fase dan motivasi membangun karier otomasi.

Setelah di episode 25 sebelumnya kita membahas static analysis & automated testing — bagaimana ShellCheck dan Bats-core menjaga kualitas skrip — pada episode kali ini, episode penutup dari 27 episode (0–26) series Belajar BASH Scripting ini, kita melakukan yang terakhir dan paling penting: merakit seluruh materi menjadi skrip production-grade yang nyata.
Selama 25 episode kalian telah mengumpulkan potongan-potongan kecil: variabel dan quoting, kontrol alur, fungsi dan array, parameter expansion, error handling, heredoc, getopts, sed/awk, curl/jq, logging dan warna, hingga ShellCheck dan Bats. Setiap episode terasa seperti belajar satu alat di bengkel. Sekarang saatnya membuat kendaraannya — menggabungkan semua alat ke dalam dua mesin yang benar-benar digunakan di dunia kerja.
Dua skenario yang akan kita bangun bukan teori:
Kedua skrip ini adalah gabungan dari hampir semua yang kalian pelajari. Membacanya baris per baris, kalian akan melihat bagaimana getopts, strict mode, fungsi logging, curl, jq, sed, dan error handling bekerja bersama — bukan sebagai materi pelajaran terpisah, melainkan sebagai satu kesatuan yang utuh. Setelah memahami keduanya, kita akan menutup series ini dengan rekap perjalanan dan dorongan terakhir untuk karier otomasi kalian.
Kebutuhan ini ditemukan di hampir setiap perusahaan dengan server. Sebuah database harus di-dump secara berkala, dikompresi, dikirim ke lokasi yang aman (objek storage), file lama dibersihkan agar disk tidak penuh, dan tim diberi tahu jika ada yang gagal. Mari kita bangun.
Pertama, tentukan arsitekturnya. Skrip akan menerima flag -d (direktori database dump sementara), -k (jumlah hari retensi), dan -n (nama database). Ditambah variabel environment untuk kredensial — pola yang kita tekankan sejak episode 23.
#!/usr/bin/env bash
set -euo pipefail
# --- Konfigurasi (dari environment, bukan hardcode) ---
DB_HOST="${DB_HOST:-localhost}"
DB_USER="${DB_USER:-backup_user}"
DB_PASS="${DB_PASS:?DB_PASS wajib diisi di environment}"
RCLONE_REMOTE="${RCLONE_REMOTE:?misal 's3:mybucket/backups'}"
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
# --- Logging (pola dari episode 24) ---
LOG_FILE="${LOG_FILE:-/var/log/backup/backup.log}"
mkdir -p "$(dirname "$LOG_FILE")"
log() {
local level=$1; shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" | tee -a "$LOG_FILE"
}
info() { log INFO "$@"; }
error() { log ERROR "$@"; }
notify() {
[ -z "$TELEGRAM_BOT_TOKEN" ] && return 0
curl -sf "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
--data-urlencode "chat_id=$TELEGRAM_CHAT_ID" \
--data-urlencode "text=$1" > /dev/null
}
usage() {
echo "Penggunaan: $0 -d DIR -k HARI -n DB_NAME"
echo " -d direktori kerja untuk dump (default: /var/backup)"
echo " -k hari retensi backup lokal"
echo " -n nama database"
exit 1
}Perhatikan beberapa keputusan desain di bagian ini:
set -euo pipefail — strict mode dari episode 13. Satu kegagalan di pipeline (misal mysqldump gagal tapi gzip "sukses") langsung menghentikan skrip.:? pada variabel wajib — skrip menolak berjalan tanpa kredensial, dengan pesan yang jelas (episode 23).notify memanfaatkan curl -sf dan --data-urlencode — pola dari episode 23; jika token tidak diisi, notifikasi dilewati tanpa error.log — pola dari episode 24.Lanjut ke bagian eksekusi — inilah inti dari getopts, dump, kompresi, upload, dan rotasi:
RETENTION_DAYS=7
WORK_DIR=/var/backup
while getopts "d:k:n:h" opt; do
case "$opt" in
d) WORK_DIR="$OPTARG" ;;
k) RETENTION_DAYS="$OPTARG" ;;
n) DB_NAME="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
[ -z "${DB_NAME:-}" ] && usage
STAMP=$(date '+%Y%m%d-%H%M%S')
DUMP_FILE="$WORK_DIR/$DB_NAME-$STAMP.sql.gz"
info "Memulai backup database '$DB_NAME'"
if ! mysqldump -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" | gzip > "$DUMP_FILE"; then
error "Dump database gagal"
notify "🚨 BACKUP GAGAL: $DB_NAME di $DB_HOST"
exit 1
fi
info "Dump selesai: $(du -h "$DUMP_FILE" | cut -f1)"
if ! rclone copy "$DUMP_FILE" "$RCLONE_REMOTE" --log-file /dev/null; then
error "Upload ke remote gagal"
notify "🚨 UPLOAD GAGAL: $DUMP_FILE"
exit 1
fi
info "Upload ke remote berhasil: $RCLONE_REMOTE"
find "$WORK_DIR" -name "$DB_NAME-*.sql.gz" -mtime +"$RETENTION_DAYS" -delete
info "Rotasi selesai: backup lebih dari $RETENTION_DAYS hari dihapus"
notify "✅ Backup OK: $DB_NAME → $RCLONE_REMOTE"Bahas detail penting:
getopts dari episode 21: skrip ini bisa dipakai orang lain, bukan hanya pemiliknya. -h menampilkan usage, opsi tidak dikenal memanggil usage.mysqldump | gzip > file — dengan set -o pipefail, kegagalan mysqldump terdeteksi. Ingat: tanpa pipefail, skrip bisa "berhasil" dengan file zip kosong — inilah bug produksi paling berbahaya.if ! ... ; then ... exit 1; fi — setiap langkah kritis punya cabang kegagalan eksplisit, dan kegagalan selalu di-notify. Skrip tidak pernah gagal dalam diam.find ... -mtime +N -delete — rotasi (pola dari episode 22 series Linux). -delete menghapus file yang lebih tua dari N hari, menjaga disk tidak penuh selamanya.Important
Disiplin backup: uji restore-nya, bukan cuma backup-nya. Sebuah backup yang tidak pernah di-restore hanyalah file yang menenangkan hati — sampai hari di mana file itu ternyata korup. Jadwalkan restore percobaan berkala (misal setiap bulan) ke database staging, dan pastikan skrip ini dijalankan via cron/systemd timer dengan output log yang terarah (ingat episode 22 series Linux). Data yang bisa di-restore adalah satu-satunya backup yang bernilai.
Kebutuhan kedua yang selalu ada di server produksi: memastikan service tetap hidup. Nginx, Docker container, atau aplikasi bisa mati kapan saja — karena crash, kehabisan memori, atau ulah deployment. Skrip health check yang cerdas akan memeriksa, mengembalikan, mencatat, dan melaporkan.
#!/usr/bin/env bash
set -euo pipefail
SERVICE="${1:-nginx}"
CHECK_URL="${CHECK_URL:-http://localhost/health}"
MAX_RETRY="${MAX_RETRY:-3}"
LOG_FILE="${LOG_FILE:-/var/log/healthcheck/health.log}"
mkdir -p "$(dirname "$LOG_FILE")"
log() {
local level=$1; shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" | tee -a "$LOG_FILE"
}
is_service_down() {
systemctl is-active --quiet "$SERVICE"
[ $? -ne 0 ]
}
restart_service() {
log WARN "Mencoba me-restart $SERVICE"
if systemctl restart "$SERVICE"; then
log INFO "Restart berhasil: $SERVICE"
else
log ERROR "Restart GAGAL untuk $SERVICE"
return 1
fi
}
incident_count=0
for i in $(seq 1 "$MAX_RETRY"); do
if is_service_down; then
log WARN "Service $SERVICE down (percobaan $i/$MAX_RETRY)"
restart_service || { incident_count=$((incident_count + 1)); break; }
sleep 5
continue
fi
log INFO "Service $SERVICE sehat"
exit 0
done
log ERROR "$SERVICE masih down setelah $MAX_RETRY percobaan"
if command -v curl > /dev/null; then
curl -sf -X POST -H 'Content-type: application/json' \
-d "{\"text\":\"🚨 $SERVICE down setelah restart berkali-kali di $(hostname)\"}" \
"$SLACK_WEBHOOK_URL" > /dev/null || true
fi
exit 1Mari kita bedah pola penting:
systemctl is-active --quiet — perintah ini mengembalikan status non-zero jika service tidak aktif; quiet menekan output. Mengemasnya ke fungsi is_service_down membuat loop utama mudah dibaca.MAX_RETRY — skrip tidak menyerah pada kegagalan pertama; ia mencoba restart, menunggu, dan memeriksa lagi. Auto-healing yang sebenarnya adalah ketekunan yang terukur.health.log terdapat riwayat lengkap: kapan down, kapan restart, apakah berhasil. Ini adalah black box yang dibutuhkan saat troubleshooting.Caution
Hati-hati dengan restart tanpa batas. systemctl restart yang dipicu loop tanpa batas bisa berubah menjadi "crash loop" — service yang restart terus-menerus sambil diganggu, bukannya pulih. Batasi dengan MAX_RETRY seperti di atas, tambahkan jeda antar percobaan, dan pastikan ada jalan keluar: jika tetap gagal, stop dan minta intervensi manusia. Skrip yang keras kepala lebih berbahaya daripada skrip yang menyerah.
Berikut ringkasan disiplin yang kalian bangun sepanjang series ini — jadikan daftar periksa sebelum skrip apa pun menyentuh server produksi:
| Aspek | Standar | Episode |
|---|---|---|
| Strict mode | set -euo pipefail di awal | 13 |
| Quoting | Semua ekspansi di-quote ("$var") | 3, 25 |
| Error handling | Cek $?/if ! ..., exit dengan kode bermakna | 13 |
| Cleanup | trap untuk membalik keadaan saat sinyal | 14 |
| CLI | getopts + usage() untuk skrip yang dipakai orang lain | 21 |
| Secrets | Environment variable, bukan hardcode | 23 |
| Logging | Timestamp + level + tee -a | 24 |
| Notifikasi | Fail-fast ke Telegram/Slack untuk insiden | 23 |
| Warna | Hanya untuk TTY (-t 1) | 24 |
| Kualitas | Lolos ShellCheck, diuji dengan Bats | 25 |
Jika skrip kalian memenuhi seluruh baris tabel ini, skrip itu layak untuk dikagumi — bukan karena rumit, tapi karena tiap bagian punya alasan dan bekerja sama dengan mulus.
Perjalanan kalian dari episode 0 hingga episode ini bukan sekadar daftar materi — ia adalah kurva pertumbuhan. Mari kita lihat sejauh mana kalian melangkah.
Fase 1 — Fondasi (episode 0–5): kalian memulai dari nol: prasyarat dan setup environment, sejarah shell, variabel & environment variables, quoting & word splitting, globbing, dan aritmatika. Di sinilah kalian belajar berbicara bahasa BASH — memahami mengapa "$var" berbeda dari $var, dan mengapa globbing adalah fitur terbaik sekaligus bahaya tersembunyi.
Fase 2 — Struktur Program (episode 6–11): kalian belajar berpikir seperti programmer: kondisional & regex, perulangan, fungsi, array indexed & asosiatif, parameter expansion, dan command/process substitution bersama heredoc. Skrip kalian berubah dari urutan perintah menjadi program dengan logika percabangan dan struktur data.
Fase 3 — Ketangguhan (episode 12–17): kalian belajar mengamankan kode: error handling & strict mode, trap & signals, debugging, hingga CLI professional dengan getopts. Di sinilah skrip kalian mulai berani menghadapi kegagalan — dan justru menjadi lebih andal karenanya.
Fase 4 — Integrasi & Kualitas (episode 18–25): kalian belajar menghubungkan dan memverifikasi: text processing dengan sed/awk, interaksi dengan dunia luar lewat curl/jq dan notifikasi, logging & colorizing output, serta jaminan kualitas dengan ShellCheck dan Bats-core. Skrip kalian kini berbicara dengan API, mencatat jejaknya sendiri, dan diuji secara otomatis.
Fase 5 — Produksi (episode 26, sekarang): kalian belajar merakit semuanya menjadi sistem yang nyata. Dua studi kasus di atas bukan sekadar contoh — mereka adalah cetak biru dari skrip yang benar-benar berjalan di server produksi di seluruh dunia.
Perhatikan satu hal: setiap fase dibangun di atas fase sebelumnya. Kalian tidak bisa membangun auto-healing tanpa memahami strict mode; tidak bisa memproses JSON tanpa memahami pipeline dan quoting. Inilah mengapa perjalanan bertahap ini bermakna — setiap episode adalah batu bata, dan sekarang kalian berdiri di atas bangunan yang utuh.
Inilah akhir perjalanan 27 episode Belajar BASH Scripting. Mari kita renungkan apa yang telah kalian capai.
Kalian mulai dari pertanyaan paling dasar — "apa itu shell dan bagaimana saya mengaturnya?" — dan sekarang kalian bisa menulis skrip yang melakukan dump database, mengompresinya, mengunggahnya ke objek storage, merotasi file lama, dan mengirim notifikasi ke Telegram jika ada yang gagal. Kalian bisa membangun sistem yang memeriksa kesehatannya sendiri dan memulihkan diri saat service mati. Dari pengguna yang mengetik perintah, kalian berubah menjadi orang yang membangun perintah — dan membangun perintah yang orang lain andalkan.
Keterampilan ini bukan sekadar teknis; ia adalah superpower operasional. Di dunia di mana server semakin banyak dan tim semakin ramping, kemampuan mengotomatiskan adalah yang membedakan admin yang selalu kebanjiran pekerjaan manual dari engineer yang mendelegasikan pekerjaan berulang ke mesin. Setiap skrip yang kalian tulis adalah satu jam manusia yang tidak lagi terbuang untuk pekerjaan yang bisa dikerjakan otomatis. Dalam beberapa tahun, kalian akan melihat kembali episode-episode ini dan menyadari bahwa fondasi yang kalian bangun di sini — disiplin quoting, error handling, logging, pengujian — adalah hal yang sama yang menjaga sistem produksi kalian tetap berdiri.
Jika ada satu hal yang harus kalian bawa dari series ini, itu adalah ini: scripting adalah tentang kepercayaan. Kepercayaan bahwa skrip akan berjalan saat dibutuhkan, kepercayaan bahwa ia akan berhenti dengan aman saat gagal, dan kepercayaan bahwa ia bisa dipahami oleh orang lain — termasuk kalian sendiri enam bulan dari sekarang. Bangun kepercayaan itu dengan mengikuti checklist di episode ini, dan skrip kalian akan bertahan dari ujian waktu.
Apa langkah selanjutnya? Dunia otomasi jauh lebih luas dari BASH. Kalian kini punya fondasi yang tepat untuk melompat ke configuration management seperti Ansible, infrastructure as code seperti Terraform, hingga container orchestration dengan Docker dan Kubernetes — semua alat itu pada akhirnya memanggil shell di belakang layar. Dan jika suatu hari nanti kalian menghadapi masalah yang aneh di server, kalian akan menemukan bahwa skrip BASH yang baik adalah alat pertama yang kalian raih.
Terima kasih telah menemani series ini sampai akhir. Sekarang tutup buku pelajaran, buka terminal, dan mulailah mengotomatiskan dunia kalian — satu skrip yang rapi pada satu waktu. Selamat berkarya, dan sampai jumpa di petualangan berikutnya.