Konvensi penulisan mengurus isi Dockerfile, tetapi satu pertanyaan selalu muncul begitu repository dibuka: berkas ini seharusnya berada di mana? Letak Dockerfile menentukan ukuran context yang dikirim ke daemon, letak compose.yaml menentukan dari mana perintah docker compose dijalankan, dan folder yang tidak dibaca siapa pun berubah menjadi arsitektur implisit yang hanya dipahami penulisnya. Struktur folder adalah keputusan teknis, bukan urusan kerapian. Chapter ini menyajikan tiga pola struktur yang menutup mayoritas kasus — aplikasi tunggal, monorepo multi-service, dan project yang membawa infrastrukturnya sendiri — lalu empat aturan penempatan yang berlaku untuk ketiganya.
Aplikasi Tunggal #
Satu aplikasi, satu Dockerfile, satu compose.yaml — semuanya di akar repository. Pola ini paling sederhana dan sebaiknya tetap dipakai selama repository memang hanya berisi satu aplikasi.
myapp/
├── Dockerfile # membangun image aplikasi
├── .dockerignore # menjaga context tetap kecil
├── compose.yaml # stack harian: aplikasi plus database
├── .env.example # templat variabel, disalin menjadi .env
├── package.json
├── package-lock.json
└── src/
└── server.jsDockerfile berada di akar sehingga docker build -t myapp:dev . berjalan tanpa flag tambahan, dan context berukuran hampir sama dengan ukuran repository itu sendiri. Aturan praktisnya: begitu folder src/ mulai memuat lebih dari satu aplikasi yang saling berbeda lifecycle-nya, saatnya pindah ke pola berikutnya.
Monorepo #
Tim yang menumbuhkan beberapa service dalam satu repository memakai pola services: setiap service membawa Dockerfile dan .dockerignore miliknya sendiri, sementara satu compose.yaml di akar menyatukan seluruh stack.
toko/
├── compose.yaml # stack lengkap: web, api, db, cache
├── .env.example
├── shared/
│ └── kontrak-api.json # skema kontrak yang dipakai lintas service
├── services/
│ ├── web/
│ │ ├── Dockerfile # membangun service web saja
│ │ ├── .dockerignore # context web terpisah dari context api
│ │ ├── package.json
│ │ └── src/
│ │ └── server.js
│ └── api/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml # stack mini untuk mengembangkan api terpisah
│ ├── go.mod
│ └── main.goDeveloper yang mengerjakan api saja tidak wajib menyalakan seluruh stack: compose.yaml lokal di services/api cukup menjalankan api plus database, dan bila butuh stack penuh, satu perintah docker compose up -d dari akar monorepo memuat semuanya. Compose juga menerima path eksplisit dengan flag -f, misalnya docker compose -f services/api/compose.yaml up -d, sehingga skrip CI bisa memilih service mana yang dibangun tanpa berpindah direktori.
Project dan Infrastruktur #
Project yang sudah beroperasi biasanya menambahkan perangkat di sekitar aplikasi: konfigurasi proxy, berkas override produksi, dan skrip operasional. Pola ketiga memisahkan kode aplikasi dari infrastruktur pendukungnya.
katalog/
├── compose.yaml # stack harian developer
├── Dockerfile
├── .dockerignore
├── nginx/
│ └── nginx.conf # konfigurasi proxy yang di-bind-mount ke container
├── deploy/
│ ├── compose.prod.yaml # override produksi: restart, limit resource, TLS
│ └── daemon.json # konfigurasi daemon untuk server produksi
├── scripts/
│ ├── backup.sh # backup volume database terjadwal
│ └── restore.sh # dipakai saat disaster drill bulanan
└── src/Folder deploy/ dan scripts/ berada di luar build context aplikasi berkat .dockerignore, jadi skrip operasional tidak pernah ikut terkirim ke daemon saat build. Pemisahan ini membuat repository tetap satu sumber kebenaran sekaligus tetap ramping sebagai image.
Context Build Monorepo: Dua Opsi #
Dockerfile hanya bisa COPY berkas yang berada di dalam build context, dan keputusan context pada monorepo punya dua kubu. Kedua opsi berikut menghasilkan image yang sama, tetapi konsekuensinya berbeda:
services:
web:
build:
context: . # Opsi A: context akar monorepo
dockerfile: services/web/Dockerfileservices:
web:
build: ./services/web # Opsi B: context subfolder service| Aspek | Opsi A: context akar | Opsi B: context subfolder |
|---|---|---|
| Ukuran context | besar; wajib .dockerignore ketat di akar | kecil secara bawaan |
Akses shared/ | bisa — COPY shared/ berfungsi langsung | tidak bisa — context tidak boleh menjangkau folder di atasnya |
.dockerignore | satu berkas mengatur semua service | satu berkas per service, lebih presisi |
| Umur cache di CI | goyah — perubahan folder lain ikut mengubah context | stabil — cache service hanya dipengaruhi foldernya sendiri |
Opsi A dipilih saat service saling berbagi berkas seperti shared/kontrak-api.json; Opsi B dipilih saat service benar-benar mandiri dan kita ingin cache serta context seminimal mungkin. Section CI/CD Course memakai pola Opsi B untuk service backend toko — seluruh kode service hidup dalam satu folder sehingga context: ./backend cukup — sedangkan struktur shared/ pada diagram di atas adalah contoh tuntutan yang memaksa Opsi A.
Empat Aturan Penempatan #
Empat aturan berikut berlaku untuk ketiga pola struktur di atas, dan urutannya juga urutan pemeriksaan saat code review.
- Dockerfile dekat kode yang ia bangun. Developer yang mengubah
services/api/main.goharus menemukanservices/api/Dockerfiledi sebelahnya tanpa mencari — jarak jauh antara kode dan resep buildnya adalah tempat kesalahan build disembunyikan. - Build context sekecil mungkin. Context dikirim utuh ke daemon pada setiap build, jadi
node_modules,.git, dan artefak build harus diblokir.dockerignorepada level context yang dipakai. .envtidak pernah masuk git. Repository hanya boleh memuat.env.examplesebagai templat; pengecekan satu baris berikut membuktikannya:
$ git ls-files | grep -E '(^|/)\.env'Output yang Dihasilkan:
.env.example- README adalah runbook, bukan brosur. Minimal empat hal wajib tertulis: cara menjalankan stack, daftar variabel wajib beserta contoh nilainya, cara menjalankan test, dan cara backup-restore data.
Struktur yang rapi membuat kesalahan lebih jarang terjadi, tetapi dunia nyata tetap menyajikan galeri kecelakaan yang sudah akrab: daemon yang mendadak mati, container yang berhenti tanpa pesan, port yang bentrok, disk yang penuh diam-diam. Semua kecelakaan itu punya pola diagnosis yang bisa dihafal, dan chapter berikutnya merangkum sepuluh yang paling sering menjadi Troubleshooting Umum dalam bentuk resep langkah demi langkah.
Referensi #
- Build Context
— mekanisme context dan batas
COPYdi dalamnya. - Compose How-Tos — pola menjalankan project dengan beberapa berkas compose.
- Referensi Compose CLI
— flag
-fdan seluruh opsi baris perintah Compose.