Membangun ulang image dari awal pada setiap perubahan kode akan mengulang pekerjaan yang sebenarnya belum berubah, misalnya pemasangan dependensi. Docker menyimpan hasil tiap instruksi pada cache, penyimpanan hasil build atau pembangunan image sebelumnya, dan menggunakannya kembali apabila tidak ada yang berubah. Topik ini membahas syarat cache digunakan, urutan instruksi yang membuat cache tetap terpakai pada build berikutnya, pembersihan yang benar dalam satu RUN, dan pengelolaan cache build. Contohnya kembali memakai Dockerfile aplikasi catatan.
Syarat cache digunakan#
Cache diperiksa per instruksi, dari atas ke bawah. Sebuah instruksi menggunakan cache apabila tiga hal terpenuhi, yaitu hasil instruksi di atasnya belum berubah, teks instruksinya sama dengan sebelumnya, dan untuk COPY serta ADD, checksum berkas yang disalin juga masih sama. Apabila satu instruksi kedaluwarsa, seluruh instruksi di bawahnya ikut dieksekusi ulang, sebab hasilnya dibangun di atas layer, lapisan penyusun image, yang sudah tidak sama. Untuk RUN, pemeriksaan hanya melihat teks perintahnya, sehingga perintah yang sama selalu menggunakan cache walau berkas di luar context telah berubah.
Syarat inilah yang membuat Dockerfile yang sama dapat menghasilkan durasi build yang berbeda-beda. Build pertama selalu mengeksekusi seluruh instruksi, sedangkan build berikutnya melompati instruksi yang syaratnya masih terpenuhi dan hanya mengerjakan bagian yang benar-benar berubah.
Pada keluaran docker build, instruksi yang melewati cache ditandai kata CACHED pada barisnya, sehingga bagian yang benar-benar dikerjakan ulang langsung terbaca. Memeriksa baris tersebut setelah setiap suntingan kode adalah cara termudah menguji apakah urutan Dockerfile sudah memanfaatkan cache atau masih memaksa pekerjaan berulang.
Urutan instruksi yang menjaga cache#
Urutan instruksi menentukan berapa banyak pekerjaan yang lolos dari cache. Instruksi yang jarang berubah ditulis lebih dahulu, sedangkan kode aplikasi yang sering berubah ditulis paling akhir. Apabila aplikasi catatan berkembang dan mulai menggunakan dependensi pihak ketiga yang tercatat pada requirements.txt, urutan pada contoh berikut membuat pemasangan dependensi dieksekusi ulang pada setiap perubahan kode.
FROM python:3.12-slim
WORKDIR /aplikasi
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python3", "app.py"]Karena COPY . . menyalin app.py sebelum dependensi dipasang, setiap suntingan app.py mengubah checksum layer COPY tersebut, sehingga RUN pip install di bawahnya ikut kedaluwarsa dan dependensi dipasang ulang. Urutan berikut membalik keadaannya.
FROM python:3.12-slim
WORKDIR /aplikasi
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python3", "app.py"]Dengan memisahkan requirements.txt dari app.py, suntingan kode hanya membuat COPY app.py dan instruksi setelahnya kedaluwarsa, sedangkan layer dependensi tetap terpakai dari cache. Pemasangan dependensi yang berat hanya berulang apabila daftar dependensinya sendiri berubah. Prinsip yang sama sudah terlihat pada Dockerfile aplikasi catatan di topik Anatomi Dockerfile, yaitu COPY app.py diletakkan paling akhir sebelum CMD.
Pembersihan dalam satu RUN#
Setiap RUN menyimpan hasil akhirnya sebagai layer, termasuk berkas sementara yang tidak dibersihkan. Pembersihan yang dilakukan pada RUN terpisah tidak mengecilkan image, karena berkas yang dihapus tetap tersimpan pada layer sebelumnya dan penghapusan hanya menambah layer baru. Cache apt adalah contoh yang lazim, sehingga pemasangan paket dan penghapusannya dirangkai dalam satu instruksi.
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc \
&& rm -rf /var/lib/apt/lists/*Rangkaian && mengeksekusi ketiga langkah dalam satu layer, sehingga daftar paket yang diunduh tidak pernah masuk ke layer mana pun dalam image. Pola ini berlaku untuk pengunduhan apa pun yang meninggalkan berkas sementara, misalnya arsip tar yang diunduh, diekstrak, lalu dihapus.
Mengelola cache build#
Cache yang tersisa setelah Dockerfile berubah juga perlu dikelola. Opsi --no-cache memaksa seluruh instruksi dieksekusi ulang dari awal, berguna ketika hasil build diragukan. Perintah docker builder prune membersihkan cache yang tidak terpakai dari builder, komponen yang mengeksekusi build, sedangkan cache yang masih terpakai tetap dibiarkan.
# tidak-dijalankan: daemon Docker tidak tersedia di sandbox
# membangun ulang tanpa menggunakan cache sama sekali
docker build --no-cache -t aplikasi-catatan .
# membersihkan cache build yang tidak terpakai
docker builder prune -fUkuran cache yang dipakai dan tersisa dapat diperiksa dengan docker system df, yang merangkum pemakaian disk oleh image, container, volume, dan cache build pada satu tabel. Pemantauan ini membantu membedakan cache yang mempercepat pekerjaan dari cache yang hanya menumpuk setelah Dockerfile berkali-kali berubah.
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txtPada pola tersebut, opsi --no-cache-dir sengaja tidak disertakan agar pip menyimpan unduhannya pada direktori yang ditempelkan. Cache mount adalah fitur BuildKit dan berbeda dari cache layer, karena isinya tidak menjadi bagian image mana pun.
Kesalahan umum#
- Menulis
COPY . .sebelum pemasangan dependensi. Setiap perubahan berkas mana pun membuat cache dependensi kedaluwarsa. Perbaikannya, salinrequirements.txtterlebih dahulu, pasang dependensinya, lalu salin kode aplikasi. - Membersihkan berkas pada
RUNterpisah. Penghapusan tidak mengecilkan layer sebelumnya, sehingga ukuran image tetap besar. Perbaikannya, rangkai pemasangan dan pembersihan dalam satuRUN. - Menganggap cache
RUNmengikuti isi berkas. CacheRUNhanya mengikuti teks perintahnya, sehingga perintah yang mengunduh sesuatu tidak diulang walau isi berkas di tujuan unduhannya sudah berubah. Perbaikannya, gunakan--no-cachepada build yang membutuhkan kesegaran.
Ringkasan#
- Cache diperiksa per instruksi dan berlaku apabila hasil instruksi di atasnya, teks instruksinya, dan checksum berkas yang disalin semuanya tidak berubah.
- Instruksi yang jarang berubah ditulis dahulu dan kode aplikasi ditulis terakhir, sehingga perubahan kode tidak memicu pemasangan dependensi ulang.
- Pembersihan berkas sementara dirangkai dalam satu
RUN, sedangkan opsi--no-cachedan cache mount BuildKit mengelola kesegaran cache.
Referensi#
- Docker build cache — Docker Docs — Menjelaskan cara cache build bekerja per layer dan kapan cache kedaluwarsa.
- Dockerfile reference — Docker Docs
— Menetapkan kapan cache instruksi
RUNkedaluwarsa. - Building best practices — Docker Docs — Menyarankan pengurutan instruksi untuk memanfaatkan cache build.