Belajar Docker untuk Pemula: Image, Container, dan Dockerfile
Belajar Docker dari Dockerfile nyata: apa itu image dan container, cara kerja layer dan build cache, serta urutan instruksi agar build tetap cepat.
Oleh Matthews WongDitinjau pada
Poin utama
Docker image adalah tumpukan layer read-only yang dibangun dari instruksi di Dockerfile; container adalah salinan image yang sedang berjalan dengan satu layer tipis yang bisa ditulisi di atasnya. Docker menyimpan cache tiap layer, jadi urutan instruksi dari yang paling jarang ke paling sering berubah itulah yang membuat rebuild tetap cepat.
Setelah pelajaran ini, Anda bisa
- Menjelaskan perbedaan image, layer, dan container.
- Memperkirakan langkah build Docker mana yang diambil dari cache setelah Anda mengubah file.
- Menyusun Dockerfile dan .dockerignore agar build cepat dan secret tidak ikut masuk.
Ikuti diagramnya langkah demi langkah
Tekan Putar, atau melangkah dengan panah. Setiap langkah juga ditulis di bawah diagram.
Bagaimana Docker image dibangun, layer demi layer
Build context dikirim ke docker build, tiap instruksi Dockerfile menambah satu layer ke image, perubahan file hanya membangun ulang layer sesudahnya, dan menjalankan image menambah satu layer yang bisa ditulisi.
Tombol: ← → langkah · Home / End · K putar atau jeda
Dockerfile adalah daftar instruksi. Sebagian besar instruksi menambah satu layer read-only ke image, dan layer-layer itu bertumpuk dari bawah ke atas.
docker build mengirim build context lebih dulu. .dockerignore menahan node_modules, .git, dan .env, jadi semuanya tidak mungkin masuk ke image.
FROM memulai dari image yang sudah ada. Layer-layernya dipakai ulang apa adanya; tidak ada yang disalin atau diubah.
FROM node:20-alpine AS depsSalin file dependensinya saja, lalu install. Layer ini hanya berubah kalau package-lock.json berubah, dan cache mount menyimpan paket yang sudah diunduh antar build.
COPY package.json package-lock.json ./ RUN --mount=type=cache,target=/root/.npm npm ciSekarang salin source code lalu build. Source sering berubah, jadi instruksi ini diletakkan paling akhir.
COPY . . RUN npm run buildTebak langkah berikutnya Anda mengubah satu file source lalu build lagi. Apa yang dijalankan ulang? (Semua instruksi, mulai dari FROM · COPY . . dan semua sesudahnya · Hanya RUN npm ci)Ubah satu file lalu build lagi. Layer base dan install diambil dari cache; COPY . . dan semua layer sesudahnya dijalankan ulang.
Tebak langkah berikutnya Apa yang ditambahkan saat image dijalankan? (Satu layer tipis yang bisa ditulisi · Salinan tulis dari setiap layer)Saat image dijalankan, satu layer tipis yang bisa ditulisi ditambahkan di atas. Layer image tetap utuh, jadi banyak container bisa memakainya bersama.
Apa perbedaan Docker image dan container?
Image adalah template read-only: tumpukan layer, di mana setiap layer berisi perubahan filesystem dari satu instruksi Dockerfile. Setelah dibuat, layer tidak pernah berubah. Container adalah hasil saat image dijalankan: Docker menaruh satu layer tipis yang bisa ditulisi di atasnya, dan semua yang ditulis proses yang berjalan masuk ke sana.
Baca selengkapnya (1)Tutup
Pembagian itulah yang membuat sepuluh container dari satu image hampir tidak menambah ruang disk: semuanya berbagi layer read-only yang sama, dan masing-masing hanya menyimpan layer tulisnya sendiri. Itu juga alasan semua yang ditulis container hilang saat container dihapus, kecuali Anda memasang volume.
Kenapa urutan Dockerfile menentukan cepat lambatnya rebuild?
Docker menyimpan cache setiap layer. Pada build berikutnya, layer dipakai ulang jika instruksi dan input-nya tidak berubah. Tetapi invalidasi hanya mengalir ke bawah: begitu satu layer berubah, semua layer sesudahnya ikut dibangun ulang, walaupun instruksinya sama persis.
Baca selengkapnya (1)Tutup
Jadi aturannya: urutkan instruksi dari yang paling jarang ke yang paling sering berubah. Dependensi jarang berubah dan paling lama diinstall, jadi salin package.json dan package-lock.json saja lalu jalankan install sebelum menyalin sisa source. Perubahan satu baris kode kemudian memakai ulang layer install dan selesai dalam hitungan detik.
Apa yang dilindungi oleh .dockerignore?
Sebelum build, docker build mengirim build context: kumpulan file yang bisa diakses build, biasanya folder proyek. Apa pun di dalamnya bisa tersalin ke image oleh instruksi COPY . . yang ceroboh. File .dockerignore mengeluarkan path dari context, jadi node_modules, .git, dan file .env tidak pernah sampai ke builder.
Baca selengkapnya (1)Tutup
File yang sama punya jebakan. Pola seperti *.md hanya cocok dengan file Markdown di root context; file di subfolder tetap ikut. Pengecualian diawali tanda !, dan baris terakhir yang cocok yang menang, jadi pengecualian yang ditulis sebelum aturan yang ingin ditimpanya tidak berpengaruh apa-apa.
Kenapa npm ci, dan apa gunanya cache mount?
npm ci menginstall persis seperti yang tertulis di package-lock.json, jadi setiap build mendapat pohon dependensi yang sama. npm install bisa memperbarui lockfile dan membuat hasil build bergeser. Di Dockerfile, yang Anda butuhkan adalah yang bisa direproduksi.
Baca selengkapnya (1)Tutup
Cache mount, ditulis RUN --mount=type=cache, memberi satu instruksi itu folder persisten yang berada di luar layer image. Arahkan ke cache unduhan npm, maka perubahan lockfile tetap menjalankan ulang npm ci, tetapi npm memakai ulang paket yang sudah diunduh, bukan mengambil semua tarball dari awal.
Konfigurasi nyata di balik pelajaran ini
Kutipan dari repositori yang membangun dan men-deploy situs ini, apa adanya.
# syntax=docker/dockerfile:1
# The syntax directive is what enables `--mount=type=cache` below.
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
# Cache npm's download directory, not node_modules. This survives within a build
# even when the layer above is invalidated, so a lockfile change re-links from
# cache instead of re-downloading every tarball. Still `npm ci`, so the lockfile
# stays authoritative.
RUN --mount=type=cache,target=/root/.npm npm ciStage pertama image situs ini. Hanya dua file dependensi yang disalin sebelum install, jadi mengubah satu halaman tidak pernah menjalankan ulang npm ci. Cache mount diarahkan ke folder unduhan npm, bukan node_modules: perubahan lockfile tetap menginstall dengan bersih, hanya tidak mengunduh ulang semuanya. Baris 1 yang mengaktifkan sintaks --mount.
node_modules
.git
.env
.env.*
.DS_Store
npm-debug.log*
*.logBaris-baris pertama .dockerignore situs ini. Dependensi lokal, riwayat git, dan semua file .env dikeluarkan dari build context, jadi COPY . . di Dockerfile tidak akan pernah menyalin secret ke dalam image.
# NOT excluded, deliberately — each of these looks like dead weight and is not:
# public/ 78 MB, but the runner stage copies it into the final image
# messages/ 12 MB, compiled into the server bundle by next-intl
# scripts/ 10 MB, because `prebuild` runs generate-blog-sources.mjs --check,
# check-placements.mjs and check-imports.mjsSisi lain dari aturannya. Folder-folder ini terlihat berat, dan mengeluarkannya justru membuat build gagal atau situs rusak. Sebelum mengabaikan sesuatu yang besar, periksa dulu apakah build membacanya.
Kesalahan yang benar-benar membuang waktu
COPY . . sebelum install
Menyalin seluruh proyek sebelum npm ci mengikat layer install ke setiap file source, jadi perubahan satu baris menginstall ulang semua dependensi. Salin manifest, install, baru salin sisanya.
Secret ikut terpanggang ke dalam layer
Tanpa .dockerignore, file .env ikut masuk lewat COPY . . dan tetap tersimpan di layer itu selamanya. Menghapusnya di instruksi berikutnya tidak menolong: layer sebelumnya masih menyimpannya. Keluarkan secret dari context dan berikan saat runtime.
Mengira cache mount bertahan di CI
Di runner CI yang baru, cache mount mulai kosong, dan cache GitHub Actions tidak menyimpannya secara default. Situs ini mengakalinya untuk cache kompilasi Next dengan pengecualian di .dockerignore, !.next/cache, sehingga cache yang dipulihkan ikut terkirim bersama build context.
Yang akan saya ubah di sini: base image
Situs ini masih dibangun di atas node:20-alpine, dan Node 20 sudah end of life sejak 30 April 2026. Base image berhenti mendapat perbaikan keamanan saat runtime-nya berhenti, jadi perubahan nyata berikutnya untuk Dockerfile ini adalah pindah ke versi Node yang masih didukung.
| Image | Container | |
|---|---|---|
| Apa itu | Tumpukan layer read-only | Salinan image yang sedang berjalan |
| Bisa berubah? | Tidak: Anda membangun image baru | Ya, di layer tulisnya |
| Dibuat dengan | docker build | docker run |
| Saat dihapus | Layer hilang jika tidak ada image yang memakainya | Layer tulisnya ikut hilang |
Lakukan di komputer Anda sendiri
Anda hanya butuh Docker dan Node terpasang. Buat folder berisi server kecil, build dua kali, lalu perhatikan langkah mana yang diambil dari cache.
Buat package.json dan src/server.js, lalu jalankan npm install sekali untuk membuat package-lock.json.
{ "name": "devops-lab", "version": "1.0.0", "private": true } // src/server.js require("node:http") .createServer((req, res) => res.end("hello\n")) .listen(3000, "0.0.0.0");Tulis Dockerfile yang menginstall dependensi sebelum menyalin source, dan .dockerignore yang mengeluarkan node_modules.
# syntax=docker/dockerfile:1 FROM node:22-alpine WORKDIR /app COPY package.json package-lock.json ./ RUN --mount=type=cache,target=/root/.npm npm ci COPY . . CMD ["node", "src/server.js"] # .dockerignore node_modules .gitBuild, ubah server-nya, lalu build lagi. Langkah npm ci menampilkan CACHED; COPY . . dijalankan ulang.
docker build -t devops-lab:v1 . echo "// tweak" >> src/server.js docker build -t devops-lab:v1 .Tampilkan daftar layer beserta ukurannya, lalu jalankan container dan buka http://localhost:8080.
docker history devops-lab:v1 docker run --rm -p 8080:3000 devops-lab:v1
Tiga pertanyaan sebelum lanjut
Pilih jawaban untuk melihat kenapa benar atau salah. Tidak ada yang disimpan atau dinilai, jadi tebak saja dengan bebas.
Jawab dalam hati, lalu cek
1.Anda mengubah satu baris di sebuah komponen. Instruksi Dockerfile mana yang dijalankan ulang?Lihat jawabannya
Jawaban:COPY . . dan semua instruksi sesudahnya. Invalidasi hanya mengalir ke bawah, dan layer install hanya bergantung pada package.json dan package-lock.json.
2.Kenapa package.json dan package-lock.json disalin sebelum COPY . .?Lihat jawabannya
Jawaban:Agar layer install yang lambat hanya bergantung pada file yang paling jarang berubah. Panduan Docker sendiri menyarankan langkah yang sering berubah diletakkan di akhir Dockerfile.
3..dockerignore situs ini berisi *.md. Apakah itu mengecualikan docs/guide.md?Lihat jawabannya
Jawaban:Tidak. *.md hanya cocok dengan file Markdown di root context; file di subfolder tetap ikut. Situs ini mengecualikan folder docs di barisnya sendiri.
Bahasan mendalam terkait di situs ini
Sumber
Sumber primer yang diperiksa pada tanggal riset. Ikuti tautannya untuk versi terbaru.