Sepanjang Section Docker Compose, kita menempa satu aplikasi latihan — katalog — dari dua service telanjang sampai menjadi stack yang lengkap: healthcheck menjunjung kejujuran status, configs dan secrets merapikan berkas konfigurasi dan kredensial, volume menjaga data dari down, dan urutan start dijaga gerbang depends_on. Aplikasi itu menjadi tempat latihan yang baik justru karena ukurannya kecil. Sekarang latihan selesai: mulai chapter ini kita meninggalkan katalog latihan dan merakit aplikasi yang lebih dekat ke dunia nyata — sebuah toko daring bernama Toko Kopi Nusantara — yang bertumbuh dari tiga service menjadi lima sepanjang section ini. Pertanyaan pertama bukan “bagaimana cara menjalankannya”, melainkan “bagaimana cara memecahnya”: komponen mana yang berdiri sebagai service sendiri, mana yang boleh dibuang kapan saja, dan mana yang harus dijaga dengan volume. Chapter ini menyusun peta arsitektur toko sebelum satu baris compose.yaml pun diisi.
Tiga Alasan Memecah Aplikasi Menjadi Service #
Kita bisa saja memasukkan seluruh toko ke dalam satu container — web server, aplikasi, database, cache semuanya dalam satu image. Docker tidak melarangnya, dan untuk aplikasi mainan itu memang paling sederhana. Tiga alasan membuat pendekatan itu tidak bertahan lama begitu aplikasi bertumbuh, dan ketiganya akan kita gunakan sebagai kompas sepanjang section ini.
Concern yang Terpisah #
Setiap bagian aplikasi berubah karena alasan yang berbeda. Halaman toko berubah karena desain baru, logika harga berubah karena aturan bisnis baru, dan skema database berubah karena jenis data baru — tiga irama perubahan yang tidak saling menunggu. Ketika semuanya hidup dalam satu container, satu perubahan kecil pada halaman memaksa kita membangun ulang, membagikan ulang, dan memulai ulang seluruh wadah — database ikut terganggu padahal tidak ada sangkut pautnya dengan warna tombol. Dengan service terpisah, perubahan pada satu concern menyentuh satu service saja, galat pada satu bagian tidak menjatuhkan bagian lain, dan tim yang berbeda bisa bekerja pada service yang berbeda tanpa saling menginjak berkas.
Scaling yang Independen #
Beban tidak pernah jatuh rata. Pada toko kita, setiap kunjungan memanggil halaman satu kali tetapi bisa memanggil endpoint produk berkali-kali, sehingga backend jauh lebih sibuk daripada frontend ketika trafik naik. Selama semuanya menjadi satu container, satu-satunya cara menambah kapasitas adalah mereplikasi seluruh aplikasi — database ikut terduplikasi dengan semua masalah konsistensinya. Dengan service terpisah, kita menskalakan hanya bagian yang panas: --scale backend=3 menambah dua replika aplikasi tanpa menyentuh database, persis pola yang kita kenal dari Chapter Service — dan kali ini kita akan melakukannya tanpa konflik port.
Teknologi yang Berbeda #
Toko kita membutuhkan empat teknologi yang lahir dari dunia berbeda: nginx yang ditulis dalam C untuk melayani berkas statis dan meneruskan permintaan, Node.js untuk logika aplikasi, PostgreSQL untuk menyimpan data dengan jaminan transaksi, dan Redis untuk menyimpan data panas di memori. Setiap teknologi membawa image, irama rilis, konfigurasi, dan kebutuhan tuning sendiri — memaksa keempatnya berbagi satu image berarti memilih satu basis OS untuk semua, menggabungkan siklus pembaruan yang tidak nyambung, dan menanggung permukaan serangan yang membengkak. Container justru lahir untuk memecah masalah ini: satu teknologi, satu image, satu service.
Peta Arsitektur Toko #
Kelima service toko dan arah percakapannya tergambar dalam satu diagram:
Mari kita telaah alur pada diagram tersebut:
- Klien hanya mengenal satu alamat — seluruh permintaan browser ditujukan ke proxy; klien tidak tahu ada berapa service di belakangnya.
- Jalur
/menuju frontend — permintaan halaman diteruskan ke service frontend yang hanya melayani berkas statis. - Jalur
/api/menuju backend — permintaan data diteruskan ke service backend, aplikasi Node.js yang mendengarkan port 3000 dan berbicara dengan db serta cache. - Backend adalah satu-satunya penghuni yang bicara ke db dan cache — frontend tidak pernah menyentuh database; pola ini menjaga kredensial dan logika data tetap di satu tempat.
- Komunikasi internal memakai nama service —
frontend,backend,db,cache— bukan alamat IP; nama-nama itu dipecahkan oleh DNS network sebagaimana kita buktikan pada Chapter Port dan Network.
Topologi jaringannya sengaja dibuat dua lapis. Proxy, frontend, dan backend menempel di network frontend-net; backend, db, dan cache menumpang di backend-net. Dengan dua network ini, frontend tidak punya jalur sama sekali menuju db — setiap pintu ke database harus melewati backend. Pola berlapis ini persis kelanjutan yang dijanjikan Chapter Port dan Network untuk stack yang telah bertumbuh.
Satu Service Satu Tanggung Jawab #
“Tiga alasan” di atas menjelaskan kenapa memecah, tetapi keputusan sehari-hari butuh alat yang lebih tajam: prinsip satu service satu tanggung jawab. Setiap kali ragu memecah atau menggabungkan, tanyakan satu pertanyaan: apakah bagian ini berubah, diskalakan, atau gagal karena alasan yang berbeda dari tetangganya? Bila ya, ia berhak atas service sendiri; bila tidak, menggabungkannya justru lebih sehat. Tabel berikut memperlihatkan bagaimana prinsip itu memutuskan pemecahan toko:
| Pertanyaan keputusan | Jawaban pada toko | Hasil |
|---|---|---|
| Apakah halaman berubah dengan irama berbeda dari logika? | ya — desain berganti mingguan, logika harga harian | frontend dan backend terpisah |
| Apakah satu pintu masuk mengurangi kompleksitas? | ya — satu port, satu tempat TLS | proxy berdiri sendiri |
Apakah data harus selamat dari down? | ya — data produk dan pesanan | db menjadi service dengan volume |
| Apakah data panas boleh dibangun ulang dari db? | ya — cache = salinan, bukan sumber | cache menjadi service sendiri |
| Apakah proxy dan frontend boleh digabung? | tidak — keduanya berubah karena alasan berbeda | tetap dua service |
Perhatikan bahwa prinsip yang sama juga bisa menyatukan: frontend dan proxy sama-sama berbasis nginx, tetapi keduanya tetap dipisah karena tanggung jawabnya — merutekan lalu lintas versus melayani berkas — berbeda.
Stateless dan Stateful #
Klasifikasi kedua yang menentukan nasib setiap service: stateless berarti container tidak menyimpan data yang membuatnya tidak boleh dibuang, sedangkan stateful berarti sebagian kebenaran aplikasi hidup di dalam container itu. Konsekuensinya praktis: service stateless boleh dihapus, dibuat ulang, dan direplikasi sembarangan; service stateful menuntut volume, backup, dan kehati-hatian sebelum down. Lima komponen toko terpetakan sebagai berikut:
| Komponen | Klasifikasi | Alasan | Volume |
|---|---|---|---|
| proxy | stateless | hanya merutekan permintaan, tidak menyimpan apa pun | tidak perlu |
| frontend | stateless | hanya membaca berkas statis dari image dan bind mount | tidak perlu |
| backend | stateless | data hidup di db dan cache, bukan di proses | tidak perlu |
| db | stateful | sumber kebenaran seluruh data toko | wajib — db-data |
| cache | stateful | isi menempel pada container meski boleh hilang | opsional |
Komunikasi Antar Service #
Service-service itu tidak saling menelepon lewat alamat IP tetap. Seluruh percakapan internal berjalan lewat network dengan nama service sebagai alamat — mekanisme embedded DNS yang kita bedah tuntas pada Chapter Container DNS. Konsekuensi desainnya satu dan tegas untuk seluruh section ini: kunci ports hanya dipakai proxy. Backend mendengarkan 3000, db mendengarkan 5432, cache mendengarkan 6379 — semuanya port internal container yang tidak pernah diterbitkan ke host, karena satu-satunya pelanggan mereka adalah service lain di network yang sama. Pelajaran Chapter Port dan Network tentang ports versus expose kini menjadi kebijakan arsitektur, bukan sekadar gaya penulisan.
Tabel berikut merangkum komponen-komponen yang akan kita rakit beserta chapter yang membedah masing-masing:
| Komponen | Image | Tanggung jawab | Dibedah di |
|---|---|---|---|
| proxy | nginx:1.29-alpine | satu pintu masuk, routing jalur | Reverse Proxy |
| frontend | nginx:1.29-alpine | halaman statis toko | Reverse Proxy |
| backend | build dari node:22-alpine | logika aplikasi dan API | Application dan Database |
| db | postgres:18-alpine | penyimpanan permanen | Application dan Database |
| cache | redis:7-alpine | data panas dan antrian ringan | Cache dan Queue |
| (opsional) queue broker | rabbitmq:4-management | antrian dengan jaminan kuat | Cache dan Queue |
Kerangka compose.yaml Toko #
Seluruh keputusan di atas bisa dirangkum menjadi kerangka berkas yang akan kita isi service demi service:
name: toko
services:
proxy:
# satu pintu publik — diisi Chapter Reverse Proxy
frontend:
# halaman statis — diisi Chapter Reverse Proxy
backend:
# aplikasi Node.js — diisi Chapter Application dan Database
db:
# PostgreSQL stateful — diisi Chapter Application dan Database
cache:
# Redis — diisi Chapter Cache dan Queue
networks:
frontend-net:
backend-net:Mari kita telaah kerangka tersebut:
name: toko— nama project yang menjadi prefix seluruh identitas: network akan lahir sebagaitoko_frontend-netdantoko_backend-net, container sebagaitoko-proxy-1dan kawan-kawannya, volume sebagaitoko_db-data.- Lima kunci service yang masih kosong — berkas ini sengaja belum bisa dijalankan;
docker compose upakan menolak service tanpa image atau build. Ia adalah peta, bukan mesin. - Dua network top-level — blok
networksdi bawah deklarasi service menegaskan pertahanan berlapis yang kita rancang di bagian Peta Arsitektur.
Kerangka inilah janji yang akan kita lunasi sepanjang section ini: proxy dan frontend menyala di Chapter Reverse Proxy, backend dan db menyambung di Chapter Application dan Database, cache dan antrian menempel di Chapter Cache dan Queue, lalu nama dan ketahanan komunikasinya kita bedah di Chapter Service Discovery. Langkah pertama paling natural adalah menyatukan pintu masuk: tanpa proxy, toko kita harus membuka dua port publik dengan segala konsekuensinya. Chapter Reverse Proxy membuktikan kenapa satu pintu jauh lebih murah dari dua.
Referensi #
- Docker Compose — cara Compose mendefinisikan aplikasi multi-service dalam satu berkas.
- Docker networking — komunikasi antar container dan embedded DNS di balik nama service.
- Compose Specification — model aplikasi: services, networks, dan volumes sebagai satu kesatuan.