Cheat sheet menyelesaikan masalah kecepatan satu orang, tetapi repository yang dirawat lima developer selama tiga tahun menghadapi masalah yang berbeda: tanpa kesepakatan tertulis, setiap Dockerfile tumbuh dengan gaya penulisnya masing-masing — ada yang menulis instruksi dengan huruf kecil, ada yang menumpuk lima RUN padahal bisa satu, ada yang lupa .dockerignore sehingga context membesar diam-diam. Perbedaan gaya bukan sekadar estetika: urutan dan bentuk instruksi menentukan umur cache, ukuran image, dan keamanan runtime, sehingga Dockerfile yang tidak konsisten adalah Dockerfile yang mahal. Chapter ini merumuskan konvensi penulisan yang bisa diadopsi tim dalam satu halaman: aturan gaya, lima blok logis, label dan pin versi, .dockerignore baku, tiga aturan keras, anggaran ukuran, dan satu contoh refactor menyeluruh.
Aturan Gaya Penulisan #
Empat aturan berikut membuat Dockerfile mudah dibaca siapa pun tanpa membuka dokumentasi. Contoh penerapannya sekaligus memperlihatkan bentuk akhirnya:
# syntax=docker/dockerfile:1
# Blok metadata: base image yang hampir tidak pernah berubah
FROM node:22-alpine
# Blok dependensi: manifest dulu supaya cache awet
COPY package.json package-lock.json ./
RUN npm ci --omit=dev \
&& npm cache clean --force- Instruksi ditulis HURUF BESAR —
FROM,COPY,RUN— agar kontras dengan argumen dan nama berkas di sebelah kanannya. - Parser directive di baris pertama —
# syntax=docker/dockerfile:1memastikan builder memakai fitur Dockerfile terbaru secara konsisten lintas mesin. - Continuation backslash untuk aksi panjang — rangkaian perintah yang harus menjadi satu layer (instalasi plus pembersihan) disambung dengan
\, bukan dipecah menjadi beberapaRUN. - Komentar per blok, bukan per baris acak — komentar menjelaskan mengapa sebuah blok ada (misalnya “manifest dulu supaya cache awet”), bukan mengulangi isi perintahnya.
Lima Blok Logis Urutan Standar #
Setiap Dockerfile yang rapi dapat dibaca sebagai lima blok dari atas ke bawah. Urutan ini bukan selera — ia adalah urutan frekuensi berubah, sama seperti tabel pada Cheat Sheet Dockerfile, dan mengikuti aturan emas Chapter Build Cache: yang jarang berubah di atas.
| Blok | Isi khas | Frekuensi berubah |
|---|---|---|
| 1. Metadata | parser directive, judul komentar, FROM, LABEL | sangat jarang |
| 2. Lingkungan | WORKDIR, ENV, ARG, instalasi paket sistem | jarang |
| 3. Dependensi | COPY manifest, RUN instalasi dependensi | jarang |
| 4. Aplikasi | COPY kode sumber, langkah build, pengaturan hak akses | setiap commit |
| 5. Runtime | USER, EXPOSE, HEALTHCHECK, CMD | hampir tidak pernah |
LABEL dan Pin Versi Tiga Tingkat #
Metadata image mengikuti kunci standar org.opencontainers.image.* sehingga bisa dibaca oleh registry, alat scan, dan pipeline yang sama. Pin versi diterapkan bertingkat sesuai seberapa ketat reproduksi yang dibutuhkan:
LABEL org.opencontainers.image.title="katalog-web" \
org.opencontainers.image.description="API katalog toko" \
org.opencontainers.image.source="https://github.com/budi/toko" \
org.opencontainers.image.licenses="MIT"FROM node:22-alpine # tingkat 1: tag minor
FROM node:22-alpine@sha256:3f763443c2b783aef6301f03ffa73d0ddd3307c4f4976f8aec9593056ac7da8d # tingkat 2: digest
RUN apt-get install -y --no-install-recommends curl=8.14.1-* # tingkat 3: paket apt dipin- Tag minor (
node:22-alpine) — mudah dibaca dan mendapat perbaikan patch otomatis; cocok untuk pengembangan. - Digest (
@sha256:...) — image dibekukan persis bit demi bit; wajib untuk produksi dan build yang harus ter-reproduksi, pola yang kita bedah di chapter Image Digest. - Paket apt dipin (
curl=8.14.1-*) — sintaksnama=versimencegah versi paket bergeser diam-diam antar build walau base image tetap.
.dockerignore Minimal Baku #
Dua belas entri berikut menutup kebocoran context yang paling sering: folder VCS, rahasia, artefak build, dan berkas pengembang. Baris terakhir adalah negasi yang mengembalikan contoh environment agar tetap ikut terkirim.
.git
.github
.vscode
.idea
.env*
node_modules
__pycache__
*.pyc
dist
build
target
tests
!.env.exampleEntri .env* memblokir seluruh keluarga berkas environment sungguhan, lalu !.env.example membuat pengecualian untuk templatnya — pola yang kita pakai di project WordPress pada Section Proyek. Tanpa baris ini, docker build mengirim .env berisi rahasia123 ke daemon sebagai bagian dari context meskipun Dockerfile tidak pernah COPY berkas tersebut.
Tiga Aturan Keras #
Tiga aturan berikut bukan gaya — melanggarnya membuka celah nyata atau merusak perilaku runtime, jadi statusnya wajib di setiap Dockerfile produksi.
| Aturan | Wujud di Dockerfile | Alasan |
|---|---|---|
| Berjalan non-root | USER node atau USER 1000:1000 sebelum CMD | proses root di container punya daya jangkau berlebih terhadap volume dan host |
| Exec form | CMD ["node", "src/server.js"] | SIGTERM sampai ke aplikasi dan exit code terbaca akurat saat docker stop |
| Ada HEALTHCHECK | HEALTHCHECK ... CMD wget -qO- ... probe /healthz | daemon tahu container sakit sebelum pelanggan yang melapor |
Anggaran Ukuran Image per Jenis Aplikasi #
Angka berikut ilustratif dan berfungsi sebagai patokan cepat: bila image kita jauh melampaui anggarannya, ada sesuatu yang bocor — biasanya toolchain builder yang ikut terkirim atau cache paket yang lupa dibersihkan.
| Jenis aplikasi | Base image | Anggaran ukuran |
|---|---|---|
| Situs statis | nginx:1.29-alpine | sekitar 50MB |
| API Go multi-stage | alpine:3.20 | 10 sampai 20MB |
| API Node | node:22-alpine | 130 sampai 190MB |
| API Python | python:3.12-slim | 150 sampai 250MB |
| CMS siap pakai | wordpress:6.8-apache | 250MB ke atas |
Contoh Refactor Sebelum dan Sesudah #
Dockerfile buruk berikut asli keluaran “cukup jalan”: base penuh, COPY segalanya di awal, paket terpasang tanpa alasan, dan CMD bentuk shell. Mari kita lihat dulu wujud sebelumnya:
FROM node:22
COPY . .
RUN npm install
RUN apt-get update && apt-get install -y curl
ENV APP_ENV production
CMD node src/server.jsHasil refactornya mengikuti lima blok konvensi, dan panjangnya hanya bertambah beberapa baris:
# syntax=docker/dockerfile:1
# Blok 1: metadata
FROM node:22-alpine
LABEL org.opencontainers.image.title="katalog-web"
# Blok 2: lingkungan
WORKDIR /app
ENV NODE_ENV=production
# Blok 3: dependensi
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# Blok 4: aplikasi
COPY src/ ./src/
# Blok 5: runtime
USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD wget -qO- http://localhost:3000/healthz || exit 1
CMD ["node", "src/server.js"]Mari kita telaah lima perubahan yang paling berdampak pada hasil refactor di atas:
node:22menjadinode:22-alpine— runtime fungsi yang sama dengan ratusan megabita lebih ramping, sekaligus mengurangi jumlah paket yang bisa punya celah keamanan.COPY . .pindah ke bawah dan menyempit — kode sumber tidak lagi meruntuhkan layernpm ci; manifest disalin lebih dulu sehingga rebuild setelah commit hanya menyentuh dua layer terakhir.curlhilang dari image — probe kesehatan cukup memakaiwgetbawaan busybox; paket sistem yang tidak dipakai aplikasi tidak berhak tinggal di image produksi.npm installmenjadinpm ci --omit=dev— instalasi kini persis mengikuti lock file dan tanpa dependensi pengembangan, sehingga image sama di mesin siapa pun.CMDpindah ke exec form danUSER nodeditambahkan — sinyaldocker stopsampai ke proses Node, exit code akurat, dan aplikasi tidak lagi berjalan sebagai root;HEALTHCHECKmelengkapi ketiganya dengan status kesehatan yang bisa dipantau daemon.
Konvensi ini menjaga isi Dockerfile, tetapi Dockerfile hanya satu berkas di dalam repository: letaknya relatif terhadap kode, context, dan compose.yaml juga merupakan keputusan yang berdampak pada cache, kecepatan CI, dan keamanan. Keputusan penempatan itulah yang dibahas chapter berikutnya melalui tiga pola Struktur Project Container — aplikasi tunggal, monorepo, hingga project yang membawa infrastrukturnya sendiri.
Referensi #
- Best Practices Build — panduan resmi gaya penulisan dan urutan instruksi Dockerfile.
- Referensi Dockerfile — semantik setiap instruksi termasuk parser directive.
- Open Containers Initiative
— standar kunci label
org.opencontainers.image.*.