Metadata dan sejarah image pada chapter sebelumnya menutup dengan satu pertanyaan praktis yang belum terjawab: bagaimana membawa sebuah image ke mesin lain ketika registry sama sekali tidak bisa dihubungi. Server produksi di jaringan terisolasi, ruang uji laboratorium tanpa akses internet, sampai kebijakan kantor yang hanya mengizinkan pemindahan berkas lewat USB — semua skenario itu tidak bisa dilayani oleh docker pull. Docker menyediakan jalur kedua untuk kebutuhan semacam itu: sepasang perintah docker save dan docker load yang mengemas image menjadi berkas arsip biasa, seanggun tag di registry tetapi sepraktis berkas yang bisa digenggam. Chapter ini mempraktikkan pasangan tersebut pada image yang sudah kita kenal, membedah isi arsipnya sampai ke blob-nya, lalu menegaskan batasnya dengan sepasang perintah yang sering tertukar: docker export dan docker import.
Menyimpan Image ke Berkas Arsip #
Objek latihan kita adalah nginx:1.29-alpine — image 47.9MB yang sempat kita hapus pada Chapter Menghapus Image demi melihat wajah baris Untagged dan Deleted. Kita tarik kembali varian tersebut terlebih dahulu, persis seperti pull pertama kita:
$ docker pull nginx:1.29-alpineOutput yang Dihasilkan:
1.29-alpine: Pulling from library/nginx
d4c8b2f7a9e1: Pull complete
3f6b1c9e2a7d: Pull complete
...
Digest: sha256:6d9f2c8a4e7b1d5f3c9a2e8b7d4f1c6a9e3b5d7f2c8a4e1b6d9f3c7a5e2b8d1f
Status: Downloaded newer image for nginx:1.29-alpine
docker.io/library/nginx:1.29-alpineBaris-baris layer di tengah dipotong — lima layer unduhannya sama persis dengan pull pertama. Sekarang kita kemas image ini menjadi satu berkas:
$ docker save -o nginx.tar nginx:1.29-alpinePerintah ini tidak mencetak apa pun saat berhasil — keheningan yang sudah kita kenal sebagai tanda sukses. Bukti keberhasilannya hidup di berkas yang baru lahir di folder kerja:
$ ls -lh nginx.tarOutput yang Dihasilkan:
-rw-r--r-- 1 budi budi 48M Oct 14 09:41 nginx.tarMari kita telaah dua perintah di atas:
-o nginx.tar— flag--outputmenentukan nama berkas tujuan; tanpa flag ini, arsip dialirkan ke standard output, perilaku yang justru kita manfaatkan pada bagian kompresi nanti.nginx:1.29-alpinesebagai argumen — referensi image yang akan disimpan; satu perintahdocker saveboleh menyebut banyak referensi sekaligus, dan image tetap utuh di penyimpanan lokal —savemenyalin, bukan memindahkan.- 48M pada kolom ukuran — angka yang sepadan dengan SIZE 47.9MB pada tabel
docker images; arsip memuat seluruh layer image, dan di mesin dengan containerd image store bawaan Engine 29, isi arsip mengikuti tata letak OCI yang sama dengan yang dipakai registry.
Memuat Kembali tanpa Registry #
Berkas nginx.tar kini bisa dibawa ke mana pun — USB, server berkas, atau SSH. Sebelum membuktikan daya gunanya, kita ciptakan dulu keadaan yang merebutkannya: hapus image dari penyimpanan lokal, lengkap dengan seluruh layernya:
$ docker rmi nginx:1.29-alpineOutput yang Dihasilkan:
Untagged: nginx:1.29-alpine
Untagged: nginx@sha256:6d9f2c8a4e7b1d5f3c9a2e8b7d4f1c6a9e3b5d7f2c8a4e1b6d9f3c7a5e2b8d1f
Deleted: sha256:5b1e8c3a9f7d...
...Mesin kita kembali tak mengenal image itu. Saatnya memuat dari arsip — tanpa registry, tanpa jaringan, tanpa autentikasi:
$ docker load -i nginx.tarOutput yang Dihasilkan:
Loaded image: nginx:1.29-alpineMari kita telaah baris tunggal tersebut beserta konsekuensinya:
-i nginx.tar— flag--inputmembaca arsip dari berkas; bentuk panjangdocker load < nginx.tarjuga sah dan berguna di dalam skrip.Loaded image: nginx:1.29-alpine— tag asal dilaporkan utuh; satu baris seperti ini muncul untuk setiap image yang dimuat, sehingga arsip multi-image mudah dibaca hasilnya.- IMAGE ID yang sama —
docker imageskembali menampilkan5b1e8c3a9f7dlama; arsip membawa konfigurasi image yang sama sehingga identitasnya tidak berubah, dan mesin yang sudah menyimpan layer bersama tidak akan menyimpan salinan kedua.
Perintah yang sama persis bekerja di mesin lain. Siti cukup menerima berkas nginx.tar — lewat USB di skenario kantor kita — lalu menjalankan docker load -i nginx.tar; baris Loaded image: nginx:1.29-alpine yang sama akan muncul di terminalnya, dan image siap dijalankan tanpa Docker Hub pernah dilibatkan.
Menyimpan Banyak Image Sekaligus #
Satu arsip boleh memuat banyak image — cukup sebutkan seluruh referensinya setelah flag output:
$ docker save -o bundle.tar nginx:1.29-alpine alpine:3.20$ ls -lh bundle.tarOutput yang Dihasilkan:
-rw-r--r-- 1 budi budi 48M Oct 14 09:52 bundle.tar$ docker load -i bundle.tarOutput yang Dihasilkan:
Loaded image: alpine:3.20
Loaded image: nginx:1.29-alpineMari kita telaah perilaku arsip campuran ini:
- Ukuran bundle tetap 48M — padahal dua image ditampung. Layer dasar alpine yang dipakai bersama oleh
nginx:1.29-alpinedanalpine:3.20hanya ditulis sekali di dalam arsip — aturan berbagi layer dari Chapter Konsep Image Layer terbawa sampai ke berkas arsip. - Dua baris
Loaded image:— setiap tag dilaporkan terpisah; urutan barisnya mengikuti susunan internal arsip, bukan urutan argumen kita. - Pasangan save-load berbasis referensi, bukan container — yang disimpan adalah image utuh beserta sejarah buildnya; container yang pernah berjalan dari image itu tidak ikut, dan writable layer-nya memang bukan milik image.
Kompresi dan Pemipaan #
Karena docker save tanpa -o mengalirkan arsip ke standard output, berkas hasilnya bisa langsung dipipakan ke alat kompresi:
$ docker save nginx:1.29-alpine | gzip > nginx.tar.gz$ ls -lh nginx.tar.gzOutput yang Dihasilkan:
-rw-r--r-- 1 budi budi 47M Oct 14 09:55 nginx.tar.gzHasil 47M dari 48M memang tampak kecil — dan itu jujur. Blob layer di dalam arsip OCI memang sudah tersimpan terkompresi, sehingga kompresi kedua di luar hanya meraih sisa metafora kecil. Nilai pola pipa ini bukan pada angka kompresinya, melainkan pada komposisinya: arsip tidak pernah mendarat sebagai berkas perantara di disk. Bentuk paling bergunanya bahkan melompat langsung ke mesin tujuan:
$ docker save nginx:1.29-alpine | gzip | ssh [email protected] docker loadSatu baris tersebut mengemas, mengompresi, mengirim lewat SSH, dan memuat di mesin Siti — tanpa satu pun berkas sementara di kedua sisi. Di sisi penerima, docker load membaca arsip ter-gzip langsung tanpa perlu di-ekstrak lebih dulu.
Membedah Isi Arsip #
Berkas .tar bisa dibuka seperti arsip tar biasa, dan isinya menjelaskan bagaimana image “dibungkus”:
$ tar -tf nginx.tarOutput yang Dihasilkan:
oci-layout
index.json
manifest.json
blobs/
blobs/sha256/
blobs/sha256/6d9f2c8a4e7b1d5f3c9a2e8b7d4f1c6a9e3b5d7f2c8a4e1b6d9f3c7a5e2b8d1f
blobs/sha256/5b1e8c3a9f7d628601351dcc926f01844ebcf5190d9a18a16365f8395d00f6d1
blobs/sha256/508a98663e79dcd9a2195f49df9da5f3219621d495c48ab3da39ef5ce8cbd001
...Tiga baris blob terakhir dipotong — lima layer image mengisi sisa daftar. Salah satu berkas kecil di dalamnya adalah peta bagi docker load:
$ tar -xOf nginx.tar manifest.jsonOutput yang Dihasilkan:
[
{
"Config": "blobs/sha256/5b1e8c3a9f7d628601351dcc926f01844ebcf5190d9a18a16365f8395d00f6d1",
"RepoTags": [
"nginx:1.29-alpine"
],
"Layers": [
"blobs/sha256/508a98663e79dcd9a2195f49df9da5f3219621d495c48ab3da39ef5ce8cbd001",
"blobs/sha256/cc47fb74efcb6767bc48270f7a0a8e07500f5bdb85d6d056f5432976e65f5c7c",
"blobs/sha256/8a7966a2cbe2915c3abf199f6054bf8145658a9c18ff8325a3954f360d3f147f",
"blobs/sha256/a7786f83bcace3f8c1577294ed38cb640904e82e7ec12145b56df6376627c15b",
"blobs/sha256/7e5434d8121c9d0ba4486c5373f016f2d2bc31bd93e40811efeb94410a3eb839"
]
}
]Tabel berikut memetakan peran tiap penghuni arsip:
| Isi arsip | Peran | Keterangan |
|---|---|---|
manifest.json | peta bagi docker load | mencantumkan RepoTags, blob konfigurasi, dan daftar blob layer |
index.json dan oci-layout | penanda tata letak OCI | menyatakan arsip mengikuti standar tata letak image yang sama dengan registry |
blobs/sha256/ konfigurasi | metadata image | isi field .Config yang kita bedah pada Chapter Image Inspect dan History — ENV, CMD, ENTRYPOINT |
blobs/sha256/ manifest image | daftar isi image | blob dengan digest 6d9f2c8a... — digest yang sama dengan output pull kita |
blobs/sha256/ layer | isi filesystem per layer | lima blob terkompresi; nama berkasnya adalah digest isi — content-addressable |
Dua hal layak digarisbawahi dari tabel itu. Pertama, digest yang tertera pada blob manifest adalah karakter demi karakter digest yang pernah tercetak pada docker pull — arsip ini benar-benar membawa identitas mesin yang sama dengan registry. Kedua, docker load bekerja murah karena strukturnya: ia cukup membaca peta, memverifikasi digest tiap blob, dan menyalinnya ke penyimpanan lokal — tidak ada proses build apa pun di dalamnya.
save versus push #
Dua jalur distribusi yang kita kuasai sekarang patut duduk berdampingan dalam satu tabel:
| Aspek | docker save dan docker load | docker push dan docker pull |
|---|---|---|
| Butuh registry | tidak — berkas arsip adalah satu-satunya perantara | ya — registry menyimpan dan menyebarkan image |
| Butuh jaringan | tidak, setelah arsip berada di tangan | ya, ke registry dan dari registry |
| Identitas yang dibawa | tag dan IMAGE ID | tag dan digest — kepastian mesin dari Chapter Image Digest |
| Skala penyebaran | satu arsip untuk satu tujuan | banyak mesin menarik bersamaan |
| Riwayat dan versi | dikelola manual — nama berkas adalah satu-satunya catatan | dikelola registry — tag, digest, dan halaman riwayatnya |
| Cocok untuk | mesin terisolasi, transfer fisik, audit berkas tunggal | tim, publikasi, dan segala hal yang berulang |
Aturan praktisnya sederhana: registry tetap jalur utama, dan save–load adalah jalur luar biasa untuk keadaan luar biasa. Detail operasional push dan pull kelak kita praktikkan tuntas pada Section Registry dan Distribusi.
docker export dan import Bukan save dan load #
Docker punya sepasang perintah lain yang tampak serupa namun bekerja pada objek yang berbeda: docker export mengambil container, bukan image, dan menghasilkan filesystem yang pipih tanpa sejarah. Kita peragakan pada container web yang masih menyala:
$ docker export -o web-flat.tar web$ ls -lh web-flat.tarOutput yang Dihasilkan:
-rw-r--r-- 1 budi budi 187M Oct 14 10:03 web-flat.tarAngka 187M sepadan dengan image nginx varian Debian, ditambah writable layer container yang ikut terbawa. Sekarang kita coba membangkitkan image dari arsip pipih ini:
$ docker import web-flat.tar web-flat:1.0Output yang Dihasilkan:
sha256:53b39d621bdb94d08db529a2fdfba8e4d38b9ef48ea2ac01375dce19d641b7fbImage lahir dengan ID baru. Namun begitu dijalankan, keanehannya muncul seketika:
$ docker run --rm web-flat:1.0Output yang Dihasilkan:
docker: Error response from daemon: No command specified.Perbaikannya tersedia lewat flag --change yang menyuntikkan metadata saat import dilakukan:
$ docker import --change 'CMD ["nginx", "-g", "daemon off;"]' web-flat.tar web-flat:1.1Output yang Dihasilkan:
sha256:81afc607e8790660b72aaebb89471f3d40f65ee4e642dd08e5e7d1ee2c2ea9afPerintah docker run dari image ini kini berhasil — tetapi setiap metadata yang hilang harus ditulis ulang satu per satu, persis pekerjaan yang sudah diselesaikan oleh penulis image asalnya. Tabel berikut menegaskan pembagian tugas keduanya:
| Aspek | docker save dan docker load | docker export dan docker import |
|---|---|---|
| Objek sumber | image | container yang sedang berjalan atau berhenti |
| Isi arsip | layer-layer image plus konfigurasi dan sejarah build | filesystem pipih hasil gabungan layer dan writable layer |
| Metadata ENV, CMD, ENTRYPOINT | ikut utuh | hilang — disuntik ulang lewat --change |
| Struktur layer | bertahan — layer bersama tetap dibagikan | lenyap — menjadi satu gumpalan berkas |
| Ukuran arsip | sepadan SIZE image | sepadan filesystem + writable layer |
| Cocok untuk | distribusi image antar mesin | memindahkan kondisi berkas sebuah container |
Kedua arsip percobaan kita bereskan sebelum chapter ditutup — web-flat:1.0 dan web-flat:1.1 tidak akan dipakai lagi:
$ docker rmi web-flat:1.0 web-flat:1.1
$ rm web-flat.tarOutput yang Dihasilkan:
Untagged: web-flat:1.0
Untagged: web-flat:1.1
...Arsip nginx.tar, nginx.tar.gz, dan bundle.tar sengaja kita biarkan di folder kerja sebagai bahan cerita — dan di sinilah satu urusan rumah tangga baru menunggu: arsip-arsip itu, image yang dimuat ulangnya, build cache dari sesi-sesi build, dan sisa eksperimen menumpuk bersama di disk. Berapa besar sesungguhnya wilayah yang dikuasai Docker di mesin kita, dan bagaimana membereskannya dengan aman, adalah pekerjaan chapter penutup section ini — docker system df dan keluarga perintah prune.
Referensi #
- docker image save — CLI Reference — sintaks penyimpanan image ke arsip, termasuk multi-image dan pemipaan.
- docker image load — CLI Reference — memuat arsip ke penyimpanan lokal beserta perilaku tag.
- docker container export — CLI Reference — mengekspor filesystem container dan bedanya dengan save.
- docker image import — CLI Reference
— mengimpor arsip pipih beserta flag
--change.