Arsip backup/data-web.tar.gz yang kita simpan di penutup Chapter Backup dan Restore Volume kini menunggu sebagai bagasi, dan bagasi memang dibuat untuk berjalan. Backup menjawab bencana; migrasi menjawab rencana — server lama yang mau dipensiunkan, VPS baru yang lebih murah, atau keputusan sederhana seperti mengganti nama volume yang dipakai production. Anehnya, migrasi inilah momen ketika banyak tim kehilangan berkas: image dipindahkan tapi volumenya tidak, data dikopi dengan cp yang kehilangan metadata kepemilikan, atau bind mount lama ditinggalkan karena tidak tahu cara mengubahnya menjadi volume. Chapter ini merangkai tiga strategi pemindahan yang saling melengkapi — arsip yang berjalan kaki lewat scp, salinan langsung antar volume lewat pipa tar, dan konversi bind mount menjadi volume — semuanya memakai bahan yang sudah kita kuasai dari dua chapter sebelumnya.

Skenario: Pindah dari host-a ke host-b #

Skenarionya khas dunia nyata. Situs internal yang dilayani volume data-web selama ini hidup di server lama yang mulai tua — kita sebut saja mesin kita berperan sebagai host-a. Perusahaan menyewa VPS baru dengan hostname host-b.example.com, dan Budi ditugaskan memindahkan situs lengkap dengan imagenya tanpa satu berkas pun tertinggal. Kunci SSH Budi tersimpan sebagai ~/.ssh/kunci-vps, dan akunnya di kedua mesin sudah tergabung dalam grup docker — syarat akses daemon yang kita bahas pada Chapter Mengatur Akses Docker di Section *Instalasi dan Konfigurasi`.

Strategi 1: Berkas Jalan Kaki dengan save dan scp #

Strategi pertama adalah yang paling mudah diaudit: seluruh kepemilikan pindahan diubah menjadi dua berkas biasa, berkas itu dikirim lewat scp, lalu dituangkan kembali di host tujuan. Bagasi volume sudah siap dari chapter sebelumnya, tinggal image yang perlu dibungkus:

bash
$ docker save nginx:1.29-alpine -o nginx-129-alpine.tar
$ ls -lh nginx-129-alpine.tar

Output yang Dihasilkan:

text
-rw------- 1 budi budi 49M Okt 13 16:24 nginx-129-alpine.tar

Image publik seperti nginx sebenarnya bisa ditarik ulang dari Docker Hub di host baru; pola docker save ini justru menunjukkan satu-satunya jalan bagi image privat milik tim yang tidak pernah di-push ke registry mana pun. Kedua berkas berangkat bersama:

bash
$ ssh [email protected] mkdir -p /tmp/migrasi
$ scp backup/data-web.tar.gz nginx-129-alpine.tar [email protected]:/tmp/migrasi/

Output yang Dihasilkan:

text
data-web.tar.gz                                100%  612     1.1MB/s   00:00
nginx-129-alpine.tar                           100%   49MB  11.2MB/s   00:04

Dari titik ini semua perintah dijalankan di host-b. Budi memuat image dan menyiapkan volume kosong:

bash
$ docker load -i /tmp/migrasi/nginx-129-alpine.tar

Output yang Dihasilkan:

text
Loaded image: nginx:1.29-alpine
bash
$ docker volume create data-web

Output yang Dihasilkan:

text
data-web

Pemulihan volume dilakukan dengan pola helper restore yang sudah kita latih, kali ini dengan sumber arsip dari /tmp/migrasi:

bash
$ docker run --rm -v data-web:/data -v /tmp/migrasi:/backup:ro alpine:3.20 tar xzf /backup/data-web.tar.gz -C /data

Output yang Dihasilkan:

text
Unable to find image 'alpine:3.20' locally
3.20: Pulling from library/alpine
...
Digest: sha256:2676beef0bef...
Status: Downloaded newer image for alpine:3.20

Helper image-nya sendiri belum ada di host baru, jadi Docker menariknya lebih dulu — image publik memang selalu tinggal satu docker run saja. Akhirnya situs dinyalakan di host baru dan diuji:

bash
$ docker run -d --name web -p 8080:80 -v data-web:/usr/share/nginx/html nginx:1.29-alpine

Output yang Dihasilkan:

text
8a4cf4e9028debec8b3e3b1588fef38c9e9a57a0aa4c442bdd56932a4709900d
bash
$ curl localhost:8080/halo.txt

Output yang Dihasilkan:

text
halo

Mari kita telaah perjalanan Strategi 1 sebagai satu rangkaian:

  1. docker save ... -o berkas.tar — image dibongkar menjadi berkas tar berisi seluruh layer; berkas ini bisa disimpan, diverifikasi checksum-nya, dan dipindahkan seperti berkas besar biasa.
  2. scp mengangkut dua berkas sekaligus — arsip volume 612 byte dan image 49MB berbagi satu koneksi; kecepatan transfer 11.2MB/s pada output adalah ilustratif untuk VPS dengan uplink memadai.
  3. docker load membangunkan image — output satu baris Loaded image: nginx:1.29-alpine menandakan seluruh layer sudah kembali berdiri di penyimpanan image host-b.
  4. Pemulihan memakai pola yang sama — helper alpine memasang volume tujuan read-write dan arsip read-only; tidak ada satu pun mekanisme baru yang perlu dipelajari, inilah untungnya disiplin pola dari Chapter Backup dan Restore Volume.
  5. curl menutup migrasi — halo.txt menjawab dari host baru berarti image, volume, dan konfigurasi mount semuanya sampai utuh.

Strategi 2: Salinan Langsung Antar Volume #

Strategi 1 menghasilkan berkas perantara di disk. Untuk pekerjaan yang sering diulang, perantara itu bisa dihilangkan sama sekali: tar sanggup menulis arsip ke stdout, dan stdout bisa dialirkan lewat pipa langsung ke tar pembaca di sisi lain.

Pipa tar di Host yang Sama #

Kembali ke host-a, kita siapkan volume sumber dari arsip yang masih tersedia, lalu menyalin isinya ke volume baru tanpa satu berkas perantara pun:

bash
$ docker volume create data-lama
$ docker run --rm -v data-lama:/data -v "$(pwd)/backup:/backup:ro" alpine:3.20 tar xzf /backup/data-web.tar.gz -C /data
$ docker volume create data-baru
$ docker run --rm \
    -v data-lama:/src:ro \
    -v data-baru:/dst \
    alpine:3.20 \
    sh -c "cd /src && tar cf - . | (cd /dst && tar xf -)"

Perintah penyalinan selesai dalam sekejap tanpa output. Verifikasinya kita lakukan dengan dua mata — daftar berkas dengan pemilik numerik, lalu isi berkasnya:

bash
$ docker run --rm -v data-baru:/data alpine:3.20 ls -ln /data

Output yang Dihasilkan:

text
total 16
-rw-r--r--    1 0        0               384 Oct 13 16:33 50x.html
-rw-r--r--    1 0        0                 5 Oct 13 16:33 halo.txt
-rw-r--r--    1 0        0               615 Oct 13 16:33 index.html
-rw-r--r--    1 0        0                29 Oct 13 16:33 nota.txt
bash
$ docker run --rm -v data-baru:/data alpine:3.20 cat /data/halo.txt

Output yang Dihasilkan:

text
halo

Mari kita telaah mesin di balik satu baris pipa itu:

  1. cd /src && tar cf - . — tar cf - menulis arsip ke stdout alih-alih ke berkas; tanda - adalah konvensi “stream”, dan . setelah pindah direktori memastikan isi yang diarsipkan relative dan utuh.
  2. | (cd /dst && tar xf -) — tanda kurung melahirkan subshell sehingga cd /dst tidak mengubah direktori kerja shell luar; tar xf - membaca arsip dari stdin dan mengekstraknya tepat di /dst.
  3. -v data-lama:/src:ro — sumber dikunci read-only, kebiasaan lama kita; volume tujuan /dst sengaja dibiarkan read-write karena di situlah arsip akan dituang.
  4. Kolom 0 0 pada ls -ln — pemilik dan grup numerik seluruh berkas adalah 0 0; tar memang mempertahankan kepemilikan asli saat menyalin, dan angka-angka inilah yang akan menjadi pokok cerita Chapter Permission dan Ownership Volume.

Pipa tar Lintas Host via ssh #

Pipa yang sama bisa diperpanjang melewati batas host: ssh mengeksekusi docker di host jauh, dan stream arsip mengalir terenkripsi melalui koneksi itu. Sebagai contoh, Budi menarik salinan data-web yang kini hidup di host-b kembali ke laptop sebagai volume bernama data-web-jauh:

bash
$ docker volume create data-web-jauh
$ ssh -i ~/.ssh/kunci-vps [email protected] \
    "docker run --rm -i -v data-web:/src:ro alpine:3.20 tar cf - -C /src ." \
    | docker run --rm -i -v data-web-jauh:/dst alpine:3.20 tar xf - -C /dst

Perintah ini perlu dibedah dengan hati-hati karena banyak yang terjadi dalam satu baris:

  1. Tanda kutip pada perintah jauh — docker run ... tar cf - ... berada di dalam kutip ganda sehingga dieksekusi utuh oleh shell host-b; tanpa kutip, kata-katanya akan diurai oleh shell lokal lebih dulu dan hasilnya kacau.
  2. -i di kedua sisi — flag interaktif membuat stdin container tetap terbuka; tanpa -i, container pembaca langsung melihat EOF di stdin dan mengekstrak arsip kosong tanpa satu keluhan pun — kegagalan paling sunyi dalam dunia migrasi.
  3. tar cf - -C /src . — arsip dibangun di host-b dari volume data-web, ditulis ke stdout, lalu diangkut ssh sebagai aliran byte terenkripsi ke laptop.
  4. tar xf - -C /dst di ujung pipa — helper lokal menerima stream dari stdin dan menuangkannya ke volume data-web-jauh; arah sebaliknya tinggal menukar posisi ssh dan helper lokal.
  5. Verifikasi tetap wajib — koneksi yang putus di tengah stream meninggalkan data setengah salinan tanpa pesan galat yang mencolok; ritual ls -ln plus cat dari subbab sebelumnya adalah satu-satunya penutup yang bisa dipercaya.

Strategi 3: Konversi Bind Mount ke Volume #

Strategi ketiga menjawab keputusan arsitektur: direktori /home/budi/situs — arena latihan bind mount sejak Chapter Bind Mount yang terakhir disunting pada Chapter Memilih Jenis Mount — ingin diubah menjadi volume agar hidup di wilayah kelolaan Docker. Pola pipa yang sama bekerja — hanya sumbernya berganti bind mount:

bash
$ docker volume create situs-statis
$ docker run --rm \
    -v /home/budi/situs:/src:ro \
    -v situs-statis:/dst \
    alpine:3.20 \
    sh -c "cd /src && tar cf - . | (cd /dst && tar xf -)"
bash
$ docker run --rm -v situs-statis:/data alpine:3.20 cat /data/index.html

Output yang Dihasilkan:

text
<h1>versi 3</h1>

Mari kita telaah konversi ini:

  1. Sumber kini bind mount — -v /home/budi/situs:/src:ro menjembatani direktori host ke helper; direktori host memang bisa dibaca tar host secara langsung, tetapi melewatinya lewat container menjaga satu pola salin yang sama untuk semua jenis sumber.
  2. Seluruh isi direktori ikut pindah — index.html versi 3 hasil suntingan Chapter Memilih Jenis Mount dan catatan.txt bekas latihan Chapter Bind Mount sama-sama mendarat di volume; pipa menyalin keadaan terakhir, bukan keadaan saat direktori pertama dibuat.
  3. Data kini mandiri dari path host — volume situs-statis bisa dipasang ke container mana pun tanpa peduli di direktori mana ia dijalankan; portabilitas yang dulu menjadi kelemahan bind mount kini diperoleh penuh.

Tabel Strategi Migrasi #

StrategiJalur dataPerlu berkas image?Cocok untuk
1. save + arsip + scp + loadhost-a → berkas → host-bYa — docker save dan docker loadMigrasi total sekali jalan ke host baru yang kosong
2a. Pipa tar antar volumevolume → volume di host yang samaTidakDuplikasi volume, penggantian nama, penyiapan volume uji
2b. Pipa tar lintas hostvolume di host jauh → volume lokalTidakSinkronisasi rutin tanpa berkas perantara
3. Bind mount → volumedirektori host → volumeTidakMembawa data masuk ke kelolaan Docker

Sebelum menutup, kita rapikan volume perantara yang sudah menuntaskan tugasnya; data-baru dan situs-statis dibiarkan sebagai hasil akhir latihan:

bash
$ docker volume rm data-lama data-web-jauh

Output yang Dihasilkan:

text
data-lama
data-web-jauh

Tiga strategi di atas berhasil memindahkan byte demi byte — tetapi perhatikan bahwa seluruh verifikasi kita menatap satu kolom yang sama berulang-ulang: angka 0 0 di ls -ln. Angka itu tampak polos, padahal inilah biang dari separuh tiket “container saya tidak bisa menulis” di forum: kernel Linux tidak mengenal nama user root atau app, ia hanya mencocokkan UID dan GID numerik — dan angka yang sama bisa berarti user berbeda di image yang berbeda. Chapter Permission dan Ownership Volume membedah mesin pencocokan angka itu dari dua arah, lalu melengkapi kotak obat kita dengan lima pola solusi untuk konflik kepemilikan yang paling sering terjadi.

Referensi #

  • Volumes — bagian resmi backup, restore, dan migrasi antar volume.
  • docker image save — referensi pembungkusan image menjadi berkas tar.
  • docker image load — referensi pemuatan kembali image dari berkas tar.