FTP (File Transfer Protocol) is great. Protokol ini memudahkan kita untuk memindahkan file dari satu client (komputer) ke client lain.

Karena mudah, kita biasanya terlena dan malah memudahkan sesuatu—yang mungkin—sebenarnya tidak mudah.

Proses deployment adalah salah satu kultur dalam engineering, ini berperan penting dalam "men-deliver" apa yang dibuat oleh seorang engineer/developer/programmer ke pengguna akhir.

Pengguna akhir mungkin tidak peduli dengan proses deployment yang organisasi kamu lakukan, tapi mereka peduli dengan error yang terjadi terhadap aplikasi yang mereka gunakan. Mereka peduli dengan kestabilan aplikasi yang mereka gunakan.

Dan karena kepedulian itu, inilah mengapa tulisan ini ada.

Sebelum masuk ke panduan, izinkan gue untuk bercerita tentang Why I rise my middle finger to people who deploy their application with FTP.

The problem

Langsung aja ke pokok permasalahan:

  • Bagaimana kamu melakukan versioning terhadap aplikasi?
  • Bagaimana kamu melakukan rollback terhadap versi terakhir jika terjadi error yang sangat fatal?
  • Bagaimana kamu membuat proses deployment yang kamu lakukan bisa membuat kamu tidur nyenyak?

Jujur and no offense, biasanya yang deploy pakai ftp/scp adalah orang-orang yang membuat aplikasi menggunakan PHP. Karena, sederhana:

  • PHP (bisa) tidak membutuhkan build stage
  • Runtime aplikasi PHP biasanya berada di level Web Server
  • Berkas PHP adalah berkas dinamis
  • Just create the PHP file and it will become the route, without any ceremony.

Gue enggak bermaksud untuk menyalahkan orang-orang yang ngoding PHP, tapi mau gimana lagi ya karena mostly yg deploy pakai FTP ya orang yang nulis kode PHP (including me, only ~3 years fortunately).

Tulisan ini bertujuan untuk melakukan proses deployment selain menggunakan FTP/SCP, karena, bukankah seharusnya begitu?

Deployment, the basic

Pada dasarnya proses deployment adalah proses "mem-production-kan" kode development kita. Yang artinya, hasil kode yang kita buat di mesin kita bisa diakses oleh publik/pengguna akhir.

Btw, kita tidak akan membahas teknik deployment yang advance seperti blue-green deployment salah satunya.

Proses deployment bisa kita analogikan dengan proses penerbitkan buku:

  • Penulis membuat draft buku
  • Draft tersebut di-review oleh editor
  • Jika sudah siap, draft tersebut akan dicetak menggunakan label cetakan N
  • Lalu hasil cetakan tersebut bisa mulai didistribusi dan dibaca oleh pembeli

Tidak jauh beda dengan proses deployment:

  • Programmer/Developer menulis kode
  • Kode tersebut di-review oleh Code Reviewer/CI/dsb
  • Jika sudah siap, kode tersebut di-rilis beserta dengan versi nya
  • Lalu pengguna akhir bisa menggunakan program yang sudah dirilis tersebut

Make sense, ya?

Artifact, the basic

Tidak perlu keliru dengan arti artefak yang ada di pelajaran sejarah.

Yang intinya, artefak adalah "sesuatu" yang dibuat/dimodifikasi oleh manusia yang dapat dipindahkan.

Dalam pemrograman, ada banyak macam artefak yang bisa dibuat. Entah itu berbentuk executable binary, archived files (tar, zip, dsb), images (Docker Image, Helm Chart, dsb) ataupun jenis lain seperti .jar, .apk, .ipa, .app, dsb yang membutuhkan runtime vm untuk menjalankannya.

Artefak itulah yang akan digunakan oleh pengguna akhir. Mereka tidak perlu peduli bahasa program apa yang ditulis, framework yang digunakan, dsb. Yang mereka peduli adalah "sesuatu" yang bisa mereka gunakan, dari kode yang kamu buat.

Dan sesuatu itu adalah program. Aplikasi. Software.

Application Runtime, the basic

Untuk bisa menggunakan sebuah "artifak", kita membutuhkan "mesin" untuk menjalankannya.

Kita akan membahas sedikit tentang ini berdasarkan artifak yang (akan) kamu buat.

Executable binary biasanya bergantung langsung dengan target mesin yang kamu gunakan. Kita tidak membahas ini, karena tulisan ini khusus untuk web development.

Archived files biasanya bergantung dengan "automation" yang kamu lakukan. Ini cara paling low-level, karena kamu sendiri yang harus mengaturnya (atau bisa menggunakan "automation tool" yang ada).

Image biasanya bergantung dengan "platform" yang kamu gunakan. Jika itu Docker Images, berarti application runtime bergantung dengan Docker.

Yang terakhir, itu hampir sama dengan executable binary namun bergantung dengan VM yang digunakan (lower-level). Jika .apk, berarti bergantung ke Dalvik VM (eh masih enggak sih?), jika .jar berarti ke JVM, dsb.

Jika kita men-deploy menggunakan FTP, kita tidak berurusan dengan 4 poin diatas. Karena:

  • Runtime berada di web server, dan gak perlu melakukan proses "restart"
  • Proses deployment dilakukan secara manual
  • Build process dilakukan secara manual juga, kalau ada
  • Tidak perlu melakukan proses release

Sejauh ini—yang saya tau—hanya PHP yang runtime nya berada di web server (including via php-fpm, right?). Dan ya, biasanya dependensi level aplikasi pun langsung "bergantung" dengan mesin/server yang digunakan.

Karena 2 hal tersebut lah, sangat make sense mengapa deploy menggunakan FTP adalah hal yang bijak mudah.

Sebelum masuk ke topik, mari kita bahas sedikit tentang "lingkungan" yang kamu gunakan.

Bare metal-ish vs Platform

Sebenarnya subheading diatas kurang relevan, karena kita tidak benar-benar menggunakan Bare Metal™ disini.

Agar tidak memperibet topik seputar cloud, semoga penambahan kata ish menjadi sedikit make sense untuk perbedaan menggunakan VPS (Virtual Private Server) dan PaaS (Platform as a Service).

Masih ingat tentang application runtime diatas? Ya, topik ini sangat bergantung dengan topik tersebut.

Anggap kita sebelumnya menggunakan FTP, ada 2 kemungkinan dalam kasus tersebut terkait lingkungan yang kita gunakan:

  • Di server murni
  • Diatas platform (biasanya web hosting alias cPanel, Plesk, dsb)

Perbedaan paling mencolok antara 2 poin diatas adalah: Abstraksi. Dengan menggunakan platform (dan gaya FTP), kamu tidak perlu berurusan dengan konfigurasi seputar FTP server, Web Server, dsb.

Kembali ke topik, dilingkungan mana aplikasi mu berjalan? Di server sendiri (oke, maksudnya VPS)? Atau di platform orang lain (VPS orang lain singkatnya)?

Contoh di platform orang lain adalah seperti di Netlify, Zeit Now, Heroku, Amazon Lightsail, dsb.

Jika kamu menggunakan platform orang lain, kamu harus mengikuti "cara" mereka dalam menjalankan aplikasimu ke platform mereka.

Jika kamu menggunakan PaaS yang mendukung self-hosted, berarti kamu harus mengikuti cara tentang bagaimana platform yang kamu gunakan tersebut menjalankan aplikasimu. Di servermu.

Agar tidak terlalu panjang, kita akan fokus ke cara yang paling mudah (dan lower-level) sampai ke cara yang lumayan ribet dan higher-level:

  • Via archived files + git
  • Via Docker
  • Via Zeit Now (PaaS)

Deploy menggunakan git

Jika kamu sedikit berani, kamu bisa menggunakan cara ini. Cara ini sedikit sederhana, automation biasanya bergantung dengan Git Hook.

Caranya ada 2:

  • Via cara tradisional git clone yang pastinya error-prone
  • Via archived files (via tag)

Karena saya tidak merekomendasikan cara ini, mari kita bahas gambaran besarnya saja.

Git clone

Remote repo ataupun server menerima hook post-receive, lalu lakukan magic disitu. Biasanya via mengeksekusi file deploy.sh.

Archived files

Kalau ini cocok untuk yang jenisnya tidak membutuhkan build process seperti untuk situs statis ataupun situs yang menggunakan PHP tanpa composer.

Biasanya, remote repo (seperti GitHub) memberikan archived files untuk tag yang dirilis (git tag). Lalu server tinggal ambil archived files dengan versi yang dimaksud (via hook juga biasanya), unpack, selesai.

Kotor banget, ya? Hahaha.

Deploy ke Docker

Untuk indie developer sampai startup, saya merekomendasikan menggunakan Docker. Selain karena penggunaannya sedikit simple, juga sudah teruji dan digunakan oleh i n d u s t r y  l e a d e r s.

Sebenarnya Docker bukanlah "platform" untuk melakukan deployment pada aplikasi kita. Melainkan, tentang bagaimana aplikasi tersebut dijalankan.

Alias, dibagian application runtime environment yang tadi kita bahas.

Asiknya, Docker menjalankan aplikasi tersebut berdasarkan "docker image".

Jadi, karena Docker adalah sebuah platform untuk melakukan "containerization" alias program terbungkus dan terisolasi dari OS langsung, jadi dependensi-dependensi yang dibutuhkan oleh aplikasi hanya terpasang di container tersebut.

Nah, Docker memiliki Registry untuk membuat distribusi artifak/docker images lebih mudah.

Jika npm/composer/cargo adalah registry biasanya hanya untuk mendistribusi library, container registry berguna untuk mendistribusikan sebuah aplikasi (termasuk dependensi yang berada di level OS).

Kita akan membahas sedikit seputar proses deployment menggunakan Docker, tapi tidak spesifik tentang teknisnya yang mana antara lain seperti ini:

  • Aplikasi di "build" menjadi docker image
  • Docker image tersebut diberi tag yang merepresentasikan versi (jika tidak secara eksplisit dilakukan, maka akan diberi tag latest)
  • Image tersebut di "push" ke registry, bisa Docker Hub; Gitlab Registry, Artifactory, dll.
  • Image yang sudah di push tersebut akan di "pull" di server kita
  • Lalu Docker tinggal "menunjuk" aplikasi tersebut ke image terbaru

Untuk spesifiknya—plus dengan contoh kasus—bisa baca tulisan berjudul Membuat Staging server menggunakan Docker + Traefik + Gitlab CI disini.

Proses deployment menjadi lebih rapih, terprediksi, dan ehm tidak ngasal.

Deploy ke PaaS

Ada kelebihan & kekurangan ketika kita memutuskan untuk men-deploy aplikasi kita ke PaaS.

Keuntungannya:

  • Tidak perlu berurusan dengan server secara prinsip
  • Biasanya memberikan pilihan fitur auto-scale
  • Harga relatif murah (maintenance, infra, dsb)
  • Mempersingkat workflow
  • Banyak fitur yang benar-benar menyimpan waktu

Dan kekurangannya:

  • Vendor lock-in
  • Tidak memiliki hak akses/kontrol penuh
  • Sangat bergantung dengan platform

Kapan pakai PaaS atau tidak, itu tergantung kebutuhan kita. Biasanya, adalah ketika kita tidak ingin banyak invest (waktu & uang) untuk hal-hal yang berkaitan dengan server.

Pada contoh ini, kita menggunakan Zeit Now. Zeit Now atau Now adalah PaaS (or can we call it a FaaS?) yang mana akan menjadikan aplikasimu sebagai Serverless Function.

Kita tidak perlu pusing-pusing memikirkan perbedaan PaaS dan FaaS karena pada prinsipnya sama-sama tentang cara aplikasi kita di deploy dan berjalan.

Perbedaan singkatnya, bila PaaS biasanya dijadikan (Docker) container, bila FaaS menjadi "function" (binary). Yang artinya, PaaS "memakan sumber daya" selama container tersebut berjalan, sedangkan FaaS hanya ketika "function" tersebut dieksekusi.

Kayaknya gue salah ngambil contoh provider deh.

Tapi gak apa-apa, mari kita lanjut.

Untuk bisa men-deploy aplikasi kita ke Now, kita perlu mengikuti "cara" Now. Yakni, dengan membuat file now.json.

Hal yang perlu diperhatikan adalah bahasa program dan framework yang kamu gunakan. Apakah layanan tersebut mendukung bahasa program atau framework yang kamu gunakan? Jika tidak, move on. Cari lain.

Now mendukung bahasa program Node.js, Go, dan Python. Jika aplikasimu tidak menggunakan bahasa program tersebut, bisa pertimbangan untuk menggunakan platform lain (khususnya yang unopinionated, seperti yang mendukung deployment via Docker).

Anggap kamu menggunakan Node.js, konfigurasi minimal nya adalah 1 file JavaScript sebagai entry-point di direktori api dan binary now yang bisa di-install disini.

Mari kita buat serverless function pertama kita:

// projects/api/time.js

module.exports = (req, res) => {
  const now = new Date().toString()

  res.status(200).send(`Now is ${now}!`)
}

Jika kamu sudah memiliki akun Now, kamu bisa eksekusi now di root project directory kamu, maka Now akan memberikan URL nya. Contoh.

Sederhana, mudah, dan hey, mana bagian konfigurasi di server yang harus kita lakukan?

Penutup

Tulisan ini bertujuan untuk membuat proses deployment lebih rapih, ter-prediksi, dan tidak rawan terjadi fatal error.

Mungkin contoh yang dibeberkan sedikit kurang jelas: Selain karena membahas banyak cara, juga untuk bagian PaaS biasanya platform yang akan kamu gunakan sudah memiliki dokumentasi yang lengkap dan jelas.

Saya pribadi menggunakan Docker, proses build s/d deploy dilakukan di CI server, dan server hanya menerima image terbaru tanpa harus menyimpan sumber kode di server secara langsung.

Jika ingin rollback—dibantu dengan ChatOps (perlu kita bahas nanti?)—tinggal jalankan command, maka server (ehm, docker) akan mem-point versi terakhir ke versi sebelumnya yang sudah stabil (plus ditenagai traefik).

Proses versioning, dilakukan di release dengan melakukan tagging terhadap docker image.

Untuk bisa tidur nyenyak, sebelum di deploy CI akan melakukan beberapa test, dan setelah di production™, dilakukan monitoring dan akan mengirim "alert" in case something is wrong (datadog? prometheus grafana? healthcheck?).

Aku selalu merekomendasikan untuk menggunakan VPS daripada PaaS, sebagaimana sudah aku bahas disini. Jika kamu ingin mempelajari lebih lanjut seputar deployment menggunakan non-ftp, bisa baca-baca referensi berikut:

Terima kasih!