Docker prune: Cara Mengosongkan Disk VPS
Disk VPS penuh karena Docker? Gunakan docker system df untuk menemukan image, container, cache build, atau volume yang memakan ruang sebelum prune.
Cari tahu apa yang menggunakan ruang disk sebelum menghapus apa pun
Docker menggunakan ruang disk pada VPS di 4 tempat: image, container yang berhenti, cache build, dan volume lokal. Jalankan docker system df terlebih dahulu untuk mengetahui bagian mana yang menggunakan ruang tersebut, lalu jalankan perintah prune paling spesifik yang dapat mengosongkannya. Urutan ini penting karena perintah terakhir dalam panduan ini, docker volume prune -a, menghapus data dan tidak dapat dibatalkan.
Mulai dari filesystem, bukan dari Docker.
df -h /
sudo du -xh --max-depth=1 /var/lib/docker | sort -hdf memberi tahu Anda seberapa parah kondisinya. du memberi tahu Anda lokasi penggunaannya. Flag -x membuat du tetap berada pada satu filesystem, sehingga tidak mengikuti mount ke volume terpisah dan menghitungnya 2 kali. Ada 5 direktori yang penting di sini: overlay2 menyimpan layer image dan container, volumes menyimpan data volume, containers menyimpan metadata container dan file log, buildkit menyimpan cache build, dan image menyimpan metadata layer.
Catatan tentang sudo dan wildcard shell karena hal ini sering membuang banyak waktu. /var/lib/docker dimiliki oleh root dan tidak dapat dibaca oleh user biasa Anda, sehingga ls /var/lib/docker menghasilkan Permission denied. Perintah seperti sudo du -sh /var/lib/docker/* juga gagal karena shell Anda memperluas * sebelum sudo dijalankan, sementara shell tidak dapat membaca direktori tersebut. Semua perintah di bawah menggunakan find atau --max-depth, bukan wildcard, karena alasan tersebut.
Sekarang, lihat dari sisi Docker sendiri.
docker system dfTYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 6 12.4GB 8.91GB (71%)
Containers 31 6 1.42GB 1.39GB (97%)
Local Volumes 14 5 6.03GB 4.11GB (68%)
Build Cache 212 0 9.87GB 9.87GBAngka tersebut berasal dari satu mesin dan tidak menunjukkan kondisi mesin Anda. Perhatikan polanya. TOTAL menghitung objek, ACTIVE menghitung objek yang sedang digunakan, dan RECLAIMABLE adalah perkiraan Docker tentang jumlah ruang yang dapat dibebaskan oleh prune dari baris tersebut.
Ada 2 hal tentang RECLAIMABLE yang sering membingungkan. Perintah ini menghitung shared image layer 1 kali untuk setiap image yang menggunakannya, sehingga baris image biasanya memperkirakan jumlah yang lebih besar daripada ruang yang benar-benar dapat dibebaskan. Perintah ini juga tidak pernah menyertakan file log container karena Docker tidak memperlakukan file log sebagai objek yang dapat direklamasi. Jika du melaporkan direktori yang jauh lebih besar daripada yang ditunjukkan oleh docker system df, penyebabnya adalah file log. Bagian tentang hal tersebut tersedia di bawah.
Tambahkan -v untuk melihat rincian setiap objek.
docker system df -vPerintah tersebut membagi ringkasan menjadi 1 bagian untuk setiap jenis objek. Bagian image menambahkan kolom SHARED SIZE dan UNIQUE SIZE, sehingga Anda dapat melihat penggunaan ruang sebenarnya dari 1 image. Bagian volume menambahkan jumlah LINKS, yaitu jumlah container yang terhubung ke volume tersebut. Ingat LINKS karena nilai 0 merupakan satu-satunya pengujian yang digunakan oleh perintah volume prune.
Dangling image dan image yang tidak digunakan
Kedua istilah ini tampak dapat dipertukarkan, tetapi sebenarnya berbeda. Filter berperilaku berbeda karena objek yang diproses juga berbeda.
Dangling image adalah image tanpa tag. Image ini ditampilkan sebagai <none> di docker images. Anda membuatnya setiap kali melakukan rebuild: docker build -t myapp:latest . memindahkan tag myapp:latest ke image baru, sedangkan image lama tetap menyimpan semua layer-nya tetapi kehilangan namanya. Tidak ada yang merujuknya, dan tidak ada proses yang membersihkannya secara otomatis.
Image yang tidak digunakan adalah image apa pun, baik memiliki tag maupun tidak, yang saat ini tidak dirujuk oleh container mana pun. postgres:16 yang Anda pull bulan lalu dan saat ini tidak sedang dijalankan termasuk image yang tidak digunakan, tetapi bukan dangling image.
docker image prune # dangling images only
docker image prune -a # every image no container refers toPerintah kedua terlebih dahulu menampilkan pertanyaan.
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N]Baca pertanyaan tersebut dengan teliti. "Associated to them" berarti objek container yang sudah ada, baik sedang berjalan maupun berhenti. Jika Anda menjalankan docker compose down, container tersebut akan dihapus. Akibatnya, setiap image yang digunakan oleh service tersebut menjadi tidak digunakan, dan -a menghapus semuanya. Tidak ada data yang hilang secara permanen, tetapi docker compose up -d berikutnya akan melakukan pull ulang atau rebuild semuanya. Pada VPS kecil, proses ini menggunakan bandwidth dan waktu build. Karena itu, sebelum melakukan prune, Anda perlu memahami hal yang dihapus oleh docker compose down dan hal yang tetap berjalan setelah stop.
Filter dapat mengecualikan image yang masih baru.
docker image prune -a --filter "until=240h"Perintah tersebut menghapus image yang tidak digunakan dan dibuat lebih dari 240 jam (10 hari) lalu, serta membiarkan image yang lebih baru. Nilai until menggunakan string durasi Go seperti 240h, atau timestamp absolut seperti 2026-08-01T00:00:00.
Apa itu cache build dan mengapa ukurannya terus bertambah tanpa batas
BuildKit adalah builder yang digunakan Docker secara default untuk docker build dan docker compose build sejak Docker Engine 23.0. BuildKit menyimpan hasil setiap langkah dari setiap Dockerfile yang dijalankannya, dan menyimpan cache tersebut di /var/lib/docker/buildkit. Cache ini membuat build kedua selesai dalam hitungan detik, sehingga cache berfungsi sebagaimana mestinya. Masalahnya, secara default tidak ada proses yang menghapus entri lama. Jika Anda melakukan build image yang sama sebanyak lima puluh kali dengan langkah COPY yang berubah setiap kali, Anda akan menyimpan lima puluh set layer.
Build cache tidak terlihat oleh docker image prune. Cache ini merupakan jenis objek terpisah dengan perintahnya sendiri.
docker builder prune # dangling cache
docker builder prune -a # all unused cache
docker builder prune --filter until=168h # cache untouched for 7 daysTidak satu pun dari perintah tersebut menyentuh image atau data Anda. Satu-satunya dampak saat menghapus build cache adalah build berikutnya berjalan lambat satu kali. Pada VPS yang rutin melakukan rebuild image, Build Cache sering menjadi baris terbesar dalam docker system df. Karena itu, cache ini merupakan objek besar yang paling aman untuk dihapus.
Perintah prune, dari yang aman hingga destruktif
Ikuti daftar ini dari atas ke bawah dan berhenti segera setelah df -h / kembali terlihat normal. Setiap perintah menampilkan baris Total reclaimed space: setelah selesai.
docker container prunemenghapus container yang telah berhenti. Writable layer-nya juga dihapus, sehingga semua data yang ditulis container di luar volume ikut terhapus. Volume tidak disentuh.docker image prunehanya menghapus image yang dangling. Ini adalah perintah image yang paling aman.docker builder prunemenghapus build cache yang dangling. Dampaknya adalah satu proses build yang lebih lambat.docker image prune -amenghapus setiap image yang tidak digunakan oleh container mana pun. Dampaknya adalah image harus di-pull ulang atau di-build ulang.docker system prunemenjalankan tiga langkah pertama sekaligus dan juga menambahkan network yang tidak digunakan.docker volume prunemenghapus anonymous volume yang tidak digunakan.docker volume prune -amenghapus volume yang tidak digunakan, termasuk volume bernama. Perintah inilah yang dapat menghapus database.
docker system prune menyatakan cakupannya sendiri sebelum dijalankan.
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- unused build cache
Are you sure you want to continue? [y/N]Volume sengaja tidak disertakan dalam daftar tersebut. Menambahkan --volumes memasukkan anonymous volume kembali ke dalam cakupan. Menambahkan -a memperluas langkah image, dari hanya image yang dangling menjadi semua image yang tidak digunakan. Menjalankan docker system prune -a --volumes -f secara penuh pada host production dapat menyebabkan kehilangan data saat mencoba mengosongkan ruang.
Mengapa pruning volume menghapus database
Bagian ini perlu dibaca dua kali.
Sebuah volume dianggap tidak digunakan jika tidak ada container yang terhubung ke volume tersebut. Hanya itu pemeriksaannya. Docker tidak memeriksa apakah volume kosong, apakah file compose masih mendeklarasikannya, atau apakah volume tersebut menyimpan satu-satunya salinan database Anda. LINKS 0 dalam docker system df -v berarti dapat di-prune, dan tidak berarti hal lain.
Sekarang, lakukan dua tindakan biasa secara berurutan. Anda menjalankan docker compose down untuk me-restart stack dengan bersih. Perintah tersebut menghapus container dan mempertahankan named volume, sesuai dengan dokumentasinya. Volume Postgres Anda sekarang tidak terhubung ke apa pun. Sepuluh menit kemudian, Anda menjalankan docker volume prune -a untuk mengosongkan ruang, dan database tersebut hilang. Kedua perintah berjalan dengan benar. Urutan tersebut yang menghancurkan data.
Sejak Docker Engine 23.0 (API version 1.42), perintah biasa memiliki cakupan yang lebih sempit daripada sebelumnya.
WARNING! This will remove anonymous local volumes not used by at least one container.Anonymous volume adalah volume yang dibuat Docker untuk Anda, biasanya karena image mendeklarasikan VOLUME dan Anda tidak memberinya nama. Volume seperti ini biasanya menyimpan data yang tidak Anda minta untuk dipertahankan. Named volume, yaitu volume yang Anda tulis dalam file compose, hanya dihapus jika Anda menambahkan -a. Versi Docker yang lebih lama menghapus keduanya dengan perintah biasa. Karena itu, jangan mengandalkan kebiasaan yang terbentuk pada server yang sejak itu telah Anda upgrade. Perbedaan ini baru masuk akal setelah Anda memahami perbedaan named volume dan bind mount, karena bind mount sama sekali bukan Docker volume dan tidak akan pernah disentuh oleh perintah prune.
Periksa sebelum menghapus. Ganti myapp_pgdata dengan nama volume yang sedang Anda periksa.
docker volume ls -f dangling=true
docker volume inspect myapp_pgdata
sudo ls -la /var/lib/docker/volumes/myapp_pgdata/_dataFilter dangling=true pada volume berarti tidak direferensikan, bukan kosong. Menampilkan _data menunjukkan isi yang sebenarnya. Jika Anda menemukan direktori pgdata atau mysql di dalamnya, berhenti dan buat salinan sebelum melanjutkan. Penghapusan yang sama juga terjadi melalui docker compose down -v, yang menghapus setiap volume yang dideklarasikan oleh file compose tanpa meminta konfirmasi terlebih dahulu.
Volume adalah satu-satunya hal pada Docker host yang tidak dapat dibuat ulang oleh proses rebuild. Karena itu, data volume harus dicadangkan menggunakan backup restic yang berjalan di luar server, sehingga flag yang salah ketik tidak dapat menjangkaunya.
Jika tidak ada yang terpangkas: file log container
Anda telah memangkas semuanya, docker system df hampir tidak menunjukkan apa pun yang dapat direklamasi, tetapi disk masih penuh. Periksa log.
sudo find /var/lib/docker/containers -name '*-json.log' -exec du -h {} + | sort -h | tail -10Setiap container menulis standard output dan standard error ke dalam file JSON di bawah /var/lib/docker/containers/. Pada instalasi default, max-size tidak ditetapkan, yang berarti ukurannya tidak terbatas. Akibatnya, satu container yang terus-menerus mengalami crash loop dapat menulis hingga partisi penuh. Tidak ada perintah prune yang menghapus file ini karena container yang membuatnya masih berjalan. Berdasarkan definisinya, file tersebut tidak dapat dipangkas.
Jangan hapus file tersebut. Menjalankan rm pada file log yang terbuka tidak membebaskan ruang karena daemon Docker masih memegang file descriptor yang terbuka. Kernel akan tetap mempertahankan blok tersebut sebagai teralokasi hingga handle itu ditutup. df tidak akan berubah sama sekali. Sebagai gantinya, lakukan truncate. Cara ini mempertahankan inode yang sama dan memungkinkan daemon melanjutkan penulisan.
sudo find /var/lib/docker/containers -name '*-json.log' -exec truncate -s 0 {} +
df -h /Ini hanya perbaikan sementara. docker logs untuk container tersebut kini tidak mengembalikan apa pun, dan file akan segera membesar lagi. Perbaikan yang sebenarnya adalah rotasi log, yang dibahas pada bagian berikutnya.
Ukur sebelum dan sesudah, setiap kali
Jangan menebak hasil prune. Ambil satu pengukuran, jalankan satu perintah, lalu ambil pengukuran lain.
df -h /
docker system df
docker builder prune -f --filter until=168h
docker image prune -f
docker system df
df -h /Bandingkan kedua output df. Hanya angka ini yang menentukan apakah server Anda tetap melayani permintaan. Selanjutnya, docker system df menunjukkan baris yang benar-benar berubah, dan setiap prune mencetak angka Total reclaimed space: miliknya sendiri.
Jika df tidak berubah tetapi docker system df menunjukkan bahwa ruang telah dibebaskan, berarti file handle yang masih terbuka menahan blok yang telah dihapus. Inilah masalah file log yang dijelaskan di atas. Jika keduanya berubah tetapi disk kembali penuh dalam satu hari, masalahnya adalah pertumbuhan data, bukan pembersihan. Solusinya adalah rotation dan scheduled job.
Cara mencegah disk kembali penuh
Batasi ukuran log. Buat atau edit /etc/docker/daemon.json.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Pengaturan tersebut membatasi setiap container hingga 30 MB log. Setiap nilai di bawah log-opts harus berupa string, termasuk nilai numerik. Periksa apakah file dapat diparsing sebelum melakukan restart, karena daemon.json yang tidak valid akan mencegah daemon start dan membuat semua container ikut berhenti.
python3 -m json.tool /etc/docker/daemon.json
sudo systemctl restart docker
docker info | grep -i 'logging driver'docker info sekarang seharusnya melaporkan Logging Driver: json-file. Batas tersebut muncul di bagian LogConfig pada docker inspect untuk container yang dibuat setelah restart. Ini adalah detail penting: pengaturan ini hanya berlaku untuk container baru. Container yang sudah ada tetap menggunakan konfigurasi saat dibuat, sehingga Anda harus membuatnya kembali.
docker compose up -d --force-recreateBatas yang sama dapat ditetapkan per service dalam file compose. Pilihan ini lebih tepat jika satu service yang banyak menghasilkan log memerlukan batas tersendiri.
services:
app:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"Jadwalkan prune yang terbatas. Jalankan setiap minggu dan batasi cakupannya pada image yang tidak digunakan serta cache build lama. Jangan pernah menempatkan -a atau --volumes dalam job terjadwal, karena job yang berjalan saat sebuah stack sedang berhenti akan menghapus image stack tersebut. Dengan --volumes, job itu juga dapat mulai menghapus data Anda.
sudo tee /etc/cron.weekly/docker-prune >/dev/null <<'EOF'
#!/bin/sh
docker image prune -f
docker builder prune -f --filter until=168h
EOF
sudo chmod +x /etc/cron.weekly/docker-prune
sudo /etc/cron.weekly/docker-pruneBaris terakhir menjalankan script sekali secara manual agar Anda dapat melihat output-nya sebelum script berjalan tanpa pengawasan. File tersebut harus dapat dieksekusi, dan namanya tidak boleh mengandung titik, karena run-parts melewati file yang tidak dapat dieksekusi serta file yang memiliki ekstensi.
Pasang alarm untuk ruang kosong. Menjalankan prune setelah disk penuh adalah tindakan pemulihan. Alert pada 80 persen adalah tindakan pencegahan.
usage=$(df --output=pcent / | tr -dc '0-9')
[ "$usage" -ge 80 ] && echo "root filesystem at ${usage} percent full"Masukkan konfigurasi tersebut ke cron dengan notifier yang sudah Anda gunakan. Ruang kosong hanya mencakup separuh masalah, jadi pasangkan alarm tersebut dengan monitoring kesehatan disk pada VPS, karena disk yang rusak dan disk yang penuh sama-sama dapat menghentikan container Anda, tetapi keduanya memerlukan penanganan yang berbeda.
Semua hal di atas mengasumsikan instalasi standar dengan root data di /var/lib/docker. Jika Anda memindahkannya menggunakan key data-root di daemon.json, ganti path tersebut dalam setiap perintah. Menata layout tersebut dengan benar pada server baru merupakan bagian dari menyiapkan Docker pada VPS, dan jauh lebih mudah menentukan lokasinya sebelum terdapat 40 GB container pada partisi yang salah.
FAQ
Apakah docker system prune menghapus volume saya?
Tidak. Perintah biasa menghapus container yang berhenti, network yang tidak digunakan, image tanpa tag, dan cache build yang tidak digunakan. Prompt konfirmasinya mencantumkan tepat kumpulan tersebut. Volume baru ikut diproses jika Anda menambahkan --volumes. Sejak Docker Engine 23.0, flag tersebut mencakup volume anonim, bukan volume bernama. Volume bernama dihapus oleh docker volume prune -a dan docker compose down -v. Kedua perintah tersebut harus digunakan dengan hati-hati.
Mengapa disk saya masih penuh setelah menjalankan docker prune?
Ada dua penyebab umum. Pertama, file log container di bawah /var/lib/docker/containers/. Tidak ada perintah prune yang menyentuh file tersebut, dan ukurannya terus bertambah tanpa batas sampai Anda menetapkan max-size. Kedua, ada file yang sudah dihapus tetapi masih terbuka karena ditahan oleh suatu proses. Jika Anda menghapus log dengan rm saat container masih berjalan, daemon tetap mempertahankan file descriptor tersebut dan kernel tidak membebaskan bloknya. Karena itu, df tidak menunjukkan perubahan. Bandingkan sudo du -xh --max-depth=1 /var/lib/docker dengan docker system df untuk mengetahui penyebabnya.
Apa perbedaan antara docker image prune dan docker image prune -a?
Perintah biasa hanya menghapus image tanpa tag, yaitu image yang kehilangan tag, hampir selalu karena proses build ulang. Bentuk -a menghapus setiap image yang tidak dirujuk oleh container yang ada, termasuk image bertag yang sengaja Anda pull. Setelah docker compose down, container sudah tidak ada, sehingga -a akan menghapus image milik stack tersebut. Tidak ada data yang hilang secara permanen karena start berikutnya akan melakukan pull atau build ulang. Namun, pada koneksi yang lambat, proses ini dapat memerlukan waktu lama.
Bagaimana cara mencegah log Docker memenuhi disk?
Tetapkan max-size dan max-file di bawah log-opts dalam /etc/docker/daemon.json, lalu restart daemon dengan sudo systemctl restart docker. Pengaturan tersebut hanya berlaku untuk container yang dibuat setelah restart itu. Karena itu, buat ulang container yang sedang berjalan dengan docker compose up -d --force-recreate. Anda dapat menetapkan dua opsi yang sama untuk setiap service dalam file compose di bawah key logging. Gunakan cara ini jika satu service menghasilkan log jauh lebih banyak daripada service lainnya.
Apakah aman menjalankan docker system prune dalam cron job?
docker system prune -f biasa aman pada host yang seluruh stack-nya selalu berjalan. Namun, perintah tersebut menghapus container yang berhenti. Dengan demikian, container yang sengaja Anda hentikan untuk dijalankan kembali nanti juga akan terhapus. Job terjadwal yang lebih aman adalah docker image prune -f ditambah docker builder prune -f --filter until=168h. Perintah tersebut membebaskan dua jenis data yang ukurannya paling cepat bertambah dan tidak dapat menyentuh volume. Jangan pernah menjadwalkan -a atau --volumes.