Perintah Docker bisa dicari di lembar contekan CLI, tetapi Dockerfile tidak: ia harus ditulis dari nol untuk setiap aplikasi, dan satu-satunya cara menulisnya cepat adalah berangkat dari pola yang sudah teruji. Kabar baiknya, hampir semua Dockerfile di dunia hanyalah variasi dari tiga kerangka — aplikasi skrip seperti Node dan Python yang menyalin dependensinya ke image, dan aplikasi terkompilasi seperti Go yang hanya membawa binary hasil stage builder. Chapter ini menyediakan ketiga kerangka itu dalam bentuk siap salin dengan komentar pada setiap baris, ditambah tabel urutan instruksi standar dan empat pola kecil yang menutup mayoritas kebutuhan lain. Salin template yang sesuai, sesuaikan path dan port, lalu biarkan komentar baris-per-baris menjadi pengingat alasan di balik setiap keputusan.
Tiga Template Siap Salin #
Ketiga template berikut sudah menerapkan seluruh aturan inti Course: manifest dependensi disalin sebelum kode sumber, proses berjalan sebagai non-root, aplikasi menghadirkan endpoint /healthz, dan CMD memakai exec form agar sinyal SIGTERM sampai ke aplikasi. Ukuran dan base image mengikuti kesepakatan Course — alpine:3.20 seberat 7.8MB sebagai runtime, node:22-alpine untuk aplikasi Node, golang:1.24-alpine untuk builder Go, dan python:3.12-slim untuk aplikasi Python.
Aplikasi Node #
Template untuk aplikasi Node 22: dependensi dari lock file, user bawaan node, dan probe wget bawaan busybox.
FROM node:22-alpine # base kecil untuk runtime Node 22
WORKDIR /app # satu direktori kerja untuk semua instruksi berikutnya
COPY package.json package-lock.json ./ # manifest dulu supaya layer dependensi awet ter-cache
RUN npm ci --omit=dev # instal dependensi produksi persis seperti lock file
COPY src/ ./src/ # kode sumber paling sering berubah: selalu paling bawah
USER node # turun dari root ke user bawaan image node
EXPOSE 3000 # dokumentasi port yang didengar aplikasi
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD wget -qO- http://localhost:3000/healthz || exit 1 # probe kesehatan lewat wget busybox
CMD ["node", "src/server.js"] # exec form: sinyal SIGTERM sampai ke proses NodeAplikasi Go Multi-Stage #
Template dua stage: toolchain Go penuh hanya hidup di stage builder, image akhir hanya berisi binary statis di atas Alpine.
FROM golang:1.24-alpine AS builder # stage 1: kompilasi dengan toolchain lengkap
WORKDIR /src # direktori kerja di dalam stage builder
COPY go.mod go.sum ./ # manifest modul dulu: cache download terjaga lama
RUN go mod download # unduh dependensi sekali per perubahan manifest
COPY . . # seluruh kode sumber menyusul di bawahnya
RUN CGO_ENABLED=0 go build -o /out/app . # binary statis tanpa libc: siap jalan di image kosong
FROM alpine:3.20 # stage 2: runtime 7.8MB tanpa toolchain Go
COPY --from=builder /out/app /usr/local/bin/app # ambil hanya binary hasil stage builder
USER 1000:1000 # UID numerik: tidak bergantung pada /etc/passwd image
EXPOSE 8080 # port aplikasi menunggu koneksi
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost:8080/healthz || exit 1 # probe kesehatan aplikasi
CMD ["app"] # binary sudah berada di PATHAplikasi Python #
Template untuk Python 3.12 di atas base slim: user dibuat sendiri, dan probe memakai urllib dari pustaka standar karena slim tidak membawa wget maupun curl.
FROM python:3.12-slim # Debian minimal: ringan tapi glibc penuh
WORKDIR /app # satu direktori kerja untuk aplikasi
RUN groupadd -r app && useradd -r -g app app # siapkan grup dan user sistem khusus aplikasi
COPY requirements.txt ./ # manifest dependensi dulu, sama seperti pola Node
RUN pip install --no-cache-dir -r requirements.txt # instal tanpa meninggalkan cache pip di layer
COPY src/ ./src/ # kode sumber menyusul setelah dependensi
USER app # jalankan aplikasi sebagai user non-root
EXPOSE 8000 # port yang didengar aplikasi
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD python -c "import urllib.request as u, sys; sys.exit(0 if u.urlopen('http://localhost:8000/healthz').status == 200 else 1)" # probe murni pustaka standar
CMD ["python", "-m", "src.main"] # sesuaikan entry point dengan struktur aplikasi kitaUrutan Sebelas Instruksi Standar #
Urutan instruksi bukan selera gaya — ia menentukan umur cache. Chapter Build Cache membuktikan bahwa setiap instruksi membawa cache key sendiri, sehingga satu perubahan pada COPY kode meruntuhkan seluruh instruksi di bawahnya. Tabel berikut menyusun sebelas instruksi standar dari atas ke bawah beserta frekuensi berubahnya: semakin jarang berubah, semakin tinggi posisinya harus berada.
| Instruksi | Peran dalam image | Frekuensi berubah |
|---|---|---|
FROM | memilih base image dan platform | sangat jarang |
WORKDIR | direktori kerja absolut | jarang |
COPY manifest | package.json, go.mod, requirements.txt | jarang |
RUN dependensi | npm ci, go mod download, pip install | jarang, ter-cache lama |
COPY kode sumber | seluruh kode aplikasi | setiap commit |
ENV | variabel lingkungan runtime | jarang |
ARG | nilai yang disuntik saat build | sesekali |
USER | identitas proses akhir | hampir tidak pernah |
EXPOSE | dokumentasi port | hampir tidak pernah |
HEALTHCHECK | probe kesehatan aplikasi | jarang |
CMD | perintah default container | jarang |
Aturan baca tabelnya satu kalimat: bila dua instruksi tertukar posisi dan yang sering berubah berada di atas, kita membayar rebuild penuh untuk perubahan satu baris kode.
Empat Pola Umum #
Empat potongan berikut bukan template utuh, melainkan blok kecil yang sering disambungkan ke template mana pun sesuai kebutuhan aplikasi.
Salin Manifest Dulu #
Pola COPY dua tahap: manifest dependensi masuk image sebelum kode, sehingga RUN instalasi tetap ter-cache selama manifest tidak berubah.
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src/ ./src/Kerangka Multi-Stage #
Kerangka minimal dua stage untuk bahasa terkompilasi: builder membawa toolchain, stage akhir hanya membawa hasilnya.
FROM golang:1.24-alpine AS builder
RUN CGO_ENABLED=0 go build -o /out/app .
FROM alpine:3.20
COPY --from=builder /out/app /usr/local/bin/appNon-Root Sejak Baris Terakhir #
Dua cara turun dari root: user bawaan image resmi bila ada, atau UID numerik bila tidak ada.
USER node # image resmi node menyediakan user siap pakai
USER 1000:1000 # image tanpa user khusus: tulis UID:GID secara numerikapt Bersih dalam Satu RUN #
Satu blok RUN untuk update, instalasi, dan pembersihan daftar paket — tiga aksi dalam satu layer supaya berkas indeks tidak ikut terkunci di dalam image.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*Dockerfile mendefinisikan satu image, tetapi aplikasi nyata hampir selalu berupa susunan beberapa container: aplikasi, database, cache, dan proxy yang saling terhubung. Susunan itu hidup di compose.yaml — berkas yang juga punya pola berulang: service dengan build dan healthcheck, depends_on dengan kondisi, network terpisah frontend dan backend, serta profil untuk alat debug. Chapter berikutnya merangkum semuanya dalam Cheat Sheet Docker Compose berisi template lengkap plus tabel perintah harian dan kunci yang paling sering dipakai.
Referensi #
- Referensi Dockerfile — perilaku resmi setiap instruksi beserta bentuk exec form.
- Best Practices Build — panduan resmi urutan instruksi dan pola Dockerfile.
- Multi-Stage Build
— mekanisme stage dan
COPY --from.