Topik ini mengerjakan tahap kedua proyek, yaitu menempatkan aplikasi nyata di atas server yang sudah disiapkan. Aplikasinya adalah catatan berbasis berkas beserta layanan pencatat status yang menuliskan kondisi aplikasi ke log, lengkap dengan berkas unit systemd dan keputusan firewallnya. Seluruh bagian aplikasi dan layanannya dibangun serta dijalankan nyata di lingkungan latihan, sedangkan pemasangan systemctl dan ufw ditampilkan sebagai pola perintah server yang siap diulang pada VPS hasil penyiapan.
Aplikasi catatan berbasis berkas#
Catatan disimpan sebagai satu berkas teks dengan satu catatan per baris, sehingga seluruh kondisi aplikasi terbaca dengan perintah baca berkas biasa. Skrip catatan.sh menyediakan dua subperintah, yaitu tambah untuk menulis baris baru dan daftar untuk menampilkan isi berkas secara bernomor. Lokasi pustaka, yaitu folder tempat catatan disimpan, tidak ditulis tetap di dalam skrip, melainkan dibaca dari variabel lingkungan PUSTAKA dengan nilai default di bawah /tmp agar dapat langsung dicoba:
#!/usr/bin/env bash
# catatan.sh: aplikasi catatan berbasis berkas
# Pemakaian: catatan.sh tambah "teks catatan" | catatan.sh daftar
set -euo pipefail
PUSTAKA="${PUSTAKA:-/tmp/kerja-deploy-layanan/pustaka}"
BERKAS="$PUSTAKA/catatan.txt"
case "${1:-}" in
tambah)
teks="${2:-}"
if [ -z "$teks" ]; then
echo "Error: teks catatan kosong." >&2
exit 1
fi
mkdir -p "$PUSTAKA"
echo "$teks" >> "$BERKAS"
nomor="$(wc -l < "$BERKAS")"
echo "catatan #$nomor tersimpan"
;;
daftar)
if [ ! -f "$BERKAS" ]; then
echo "pustaka masih kosong"
else
awk '{print NR") " $0}' "$BERKAS"
fi
;;
*)
echo "Pemakaian: catatan.sh tambah \"teks\" | catatan.sh daftar"
;;
esacPemakaian: catatan.sh tambah "teks" | catatan.sh daftarDipanggil tanpa argumen, skrip hanya menampilkan cara pemakaiannya dan tidak menjalankan apa pun, sebagaimana keluaran di atas. Blok berikut menambahkan dua catatan lalu menampilkannya. Percabangan case di dalam skrip memilih subperintah, sedangkan nomor catatan dihitung dari jumlah baris berkas:
# folder kerja bersih untuk pustaka aplikasi
rm -rf /tmp/kerja-deploy-layanan
./catatan.sh tambah "beli kopi"
./catatan.sh tambah "rapat pukul sepuluh"
# daftar catatan yang tersimpan
./catatan.sh daftarcatatan #1 tersimpan
catatan #2 tersimpan
1) beli kopi
2) rapat pukul sepuluhDua hal terlihat dari keluaran tersebut. Direktori pustaka dibuat sendiri oleh skrip lewat mkdir -p saat catatan pertama ditulis, dan daftar menampilkan dua baris sesuai isi berkasnya. Format satu baris per catatan memang sengaja sederhana, tetapi polanya sama dengan aplikasi server sungguhan, yaitu data terpisah dari kode dan lokasinya dikendalikan variabel lingkungan.
Layanan pencatat status#
Layanan pencatat status adalah program yang berjalan terus dan setiap interval menulis satu baris kondisi aplikasi ke berkas log. Setiap barisnya memuat waktu pencatatan, status, dan jumlah catatan terkini, sehingga riwayat aplikasi dapat direkonstruksi dari lognya semata. Skrip pencatat-status.sh berikut mengerjakannya. Argumen --layanan menandai bahwa skrip benar-benar dijalankan sebagai layanan, sedangkan tanpa argumen itu skrip hanya menampilkan pemakaiannya:
#!/usr/bin/env bash
# pencatat-status.sh: layanan kecil pencatat status aplikasi catatan
# Pemakaian: pencatat-status.sh --layanan (unit systemd, atau uji dengan BATAS)
set -euo pipefail
PUSTAKA="${PUSTAKA:-/tmp/kerja-deploy-layanan/pustaka}"
JEDA="${JEDA:-1}"
BATAS="${BATAS:-0}"
if [ "${1:-}" = "--layanan" ]; then
LOG="$PUSTAKA/log/status.log"
mkdir -p "$(dirname "$LOG")"
i=0
while :; do
if [ -f "$PUSTAKA/catatan.txt" ]; then
ISI="$(wc -l < "$PUSTAKA/catatan.txt")"
else
ISI=0
fi
echo "$(date '+%Y-%m-%d %H:%M:%S') status=OK catatan=$ISI" >> "$LOG"
i=$((i + 1))
if [ "$BATAS" -gt 0 ] && [ "$i" -ge "$BATAS" ]; then
break
fi
sleep "$JEDA"
done
echo "pencatat-status selesai setelah $i pembacaan"
else
echo "Pemakaian: pencatat-status.sh --layanan"
fiPemakaian: pencatat-status.sh --layananUji berikut membuktikan mode layanan itu benar-benar berjalan, yaitu dipanggil dengan batas tiga pembacaan, lalu lognya dibaca:
# mode layanan dijalankan tiga kali pembacaan
BATAS=3 JEDA=1 ./pencatat-status.sh --layananpencatat-status selesai setelah 3 pembacaan# isi log tanpa kolom waktu, karena nilainya berbeda setiap eksekusi
cut -d' ' -f3- /tmp/kerja-deploy-layanan/pustaka/log/status.logstatus=OK catatan=2
status=OK catatan=2
status=OK catatan=2Kolom waktu sengaja dipotong oleh cut karena nilainya adalah tanggal dan jam nyata ketika baris ditulis, berbeda pada setiap eksekusi, sedangkan dua kolom sisanya selalu sama untuk keadaan yang sama. Perulangan while di dalam skrip menjalankan tiga pekerjaan pada setiap putarannya, yaitu menghitung baris catatan, menulis baris log, lalu tidur selama JEDA. Setelah pembacaan ketiga, satu catatan baru ditambahkan dan layanan dijalankan lagi, sehingga lognya ikut membesar:
# catatan ketiga, lalu dua pembacaan berikutnya
./catatan.sh tambah "tinjau laporan"
BATAS=2 JEDA=1 ./pencatat-status.sh --layanan
# jumlah seluruh baris log
grep -c 'status=OK' /tmp/kerja-deploy-layanan/pustaka/log/status.logcatatan #3 tersimpan
pencatat-status selesai setelah 2 pembacaan
5Nilai catatan pada baris log naik dari dua menjadi tiga setelah catatan baru masuk, dan penghitung grep memastikan kelima barisnya seluruhnya berstatus OK. Log yang tumbuh seperti ini adalah cara termurah untuk memeriksa bahwa layanan benar-benar berjalan, baik di lingkungan latihan maupun di server.
Berkas unit catatan-layanan#
Berkas unit mengikat skrip pencatat-status.sh ke systemd, sehingga layanannya hidup sejak boot, dihidupkan ulang saat error, dan lognya tercatat di jurnal. Bentuknya seperti berikut:
[Unit]
Description=Layanan pencatat status aplikasi catatan
[Service]
Type=simple
Environment=PUSTAKA=/var/lib/catatan
Environment=JEDA=60
ExecStart=/usr/local/bin/pencatat-status.sh --layanan
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetSetiap barisnya berperan sebagai berikut:
- Bagian
[Unit]hanya memuatDescription=, yaitu keterangan yang tampil padasystemctl statusdan daftar unit. Type=simplemenyatakan layanan dianggap berjalan begitu prosesnya hidup, cocok untuk skrip yang tidak melepas diri ke latar belakang, berbeda dariType=oneshotuntuk tugas sekali jalan.- Dua baris
Environment=mengganti konfigurasi skrip tanpa menyuntingnya, yaitu pustaka dipindah ke/var/lib/catatandan interval diperbesar menjadi 60 detik. ExecStart=memanggil skrip dengan jalur absolut beserta argumen--layanan, sehingga yang dijalankan systemd adalah mode layanannya, bukan pesan pemakaiannya.Restart=on-failuredenganRestartSec=5meminta systemd menghidupkan ulang layanan yang berakhir karena error, dengan jeda lima detik.- Bagian
[Install]menautkan unit kemulti-user.targetsaat di-enable, yaitu target standar server tanpa antarmuka grafis.
Pemeriksaan systemd-analyze verify berlaku sama untuk berkas ini sebelum dipasang, sebagaimana berkas unit lain. Penyebut /var/lib/catatan dipilih karena /var adalah wilayah data yang tumbuh saat server berjalan, sesuai pembagian hierarki sistem berkas.
Pemasangan dan keputusan firewall#
Pemasangan mengikuti urutan tetap, yaitu menyalin skrip ke /usr/local/bin, menyiapkan direktori pustakanya, menyalin berkas unit, memuat ulang daftar unit, lalu mengaktifkan layanannya:
# tidak-dijalankan
# pemasangan menuntut hak root dan systemd yang berjalan
sudo cp pencatat-status.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/pencatat-status.sh
sudo mkdir -p /var/lib/catatan
sudo cp catatan-layanan.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now catatan-layanan.serviceSetelah aktif, keadaan layanannya diperiksa dengan systemctl status, dan baris log terbaca dari jurnal tanpa perlu mencari berkas lognya. Baris enable --now menggabungkan dua pekerjaan, yaitu menautkan unit agar aktif saat boot dan menjalankannya saat itu juga, sehingga layanan langsung tampak pada status tanpa perintah start terpisah:
# tidak-dijalankan
# log layanan tercatat di jurnal systemd
systemctl status catatan-layanan.service --no-pager
journalctl -u catatan-layanan.service -n 20Keputusan firewallnya mengikuti arsitektur proyek ini, yaitu aplikasi catatan tidak mendengarkan port publik, sehingga tidak ada aturan ufw baru yang diperlukan dan satu-satunya jalur masuk tetap SSH. Apabila aplikasi yang dideploy mendengarkan port, misalnya 8080, aturannya ditambahkan sebelum firewall diaktifkan:
# tidak-dijalankan
# untuk aplikasi yang mendengarkan port: izinkan portnya sebelum enable
sudo ufw allow 8080/tcp
# verifikasi keadaan firewall setiap kali layanan baru dipasang
sudo ufw status verbosePola yang ditegaskan di bagian ini adalah memeriksa daftar port yang mendengarkan sebelum dan sesudah deploy, sehingga tidak ada port baru yang terbuka tanpa diketahui. Perintah ss -tln menampilkan daftar tersebut, dan pemeriksaannya diulang setelah layanan diaktifkan. Layanan tanpa port publik seperti aplikasi catatan ini memang tidak menambah permukaan serangan, dan firewall yang tidak berubah adalah hasil deploy yang wajar untuknya.
Kesalahan umum#
- Menjalankan
./pencatat-status.sh --layanantanpa BATAS di terminal lalu mengira terminal macet. Mode layanannya memang dirancang berjalan tanpa akhir, sehingga uji manual selalu menyertakan BATAS atau dihentikan lewat Ctrl-C. - Menyalin skrip ke
/usr/local/bintanpa izin eksekusi. systemd menemukan berkasnya tetapi gagal mengeksekusinya, dan layanan berakhir dengan status 203 berulang kali sesuai aturan Restart. - Memanggil
systemctl startsebelumdaemon-reload. systemd belum mengenali unit baru yang barusan disalin, sehingga perintahnya berakhir dengan pesan unit tidak ditemukan. - Mengira aplikasi otomatis terjangkau dari luar setelah enable. systemd hanya menjalankan prosesnya, sedangkan jangkauan ditentukan firewall, dan aplikasi tanpa port publik memang tidak dibukakan aturan apa pun.
Ringkasan#
- Aplikasi catatan menyimpan datanya sebagai satu berkas teks, dengan lokasi dikendalikan variabel lingkungan PUSTAKA.
- pencatat-status.sh menulis satu baris log setiap interval, argumen
--layananmenandai mode layanannya, dan variabel BATAS membatasi pembacaan saat uji. - Berkas unit memakai
Type=simple, mengonfigurasi skrip lewatEnvironment=, dan menetapkanRestart=on-failureagar error tidak mematikan layanan secara permanen. - Aplikasi tanpa port publik tidak menambah aturan ufw, sedangkan port baru selalu diizinkan sebelum firewall diaktifkan.
Referensi#
- systemd.service(5) — freedesktop.org
— Opsi
Type=,ExecStart=,Restart=, danRestartSec=pada bagian[Service]. - systemd.exec(5) — freedesktop.org
— Direktif
Environment=dan lingkungan eksekusi layanan. - ufw(8) — Ubuntu Manpages
— Perintah
allow,enable, danstatuspada ufw.