Image
鏡像的遷移,適用於離線環境。
一般離線環境,都會自建Docker Registry。 無論 官方的 ,還是最近流行的 Harbor ,都是不錯的選擇。 但是,這個世界上就是有些環境,或者說一些環境在某些時期,沒有外網,也沒有內部的Registry。 這個時候要部署Docker的服務,怎么辦?
只能通過鏡像的遷移。 實際上, Harbor 的offline installer,就是采用這種形式。
Save
# use stdout docker save alpine > /tmp/alpine.tar # or write to a file directly docker save alpine -o /tmp/alpine.tar
推薦使用 -o 的形式,因為利用stdout的做法雖然直觀,但在某些場景下無效,比如利用ssh 遠程執行命令。
Load
# use stdout docker load < /tmp/wekan.tar # or read from a file directly docker load -i /tmp/wekan.tar
Container
容器的遷移,適用於已經上線,且狀態復雜、從零開始啟動不能正常工作的服務。 容器遷移的包,包含了鏡像。
Export
先准備一個正在運行的服務,並且弄臟環境。
$ docker run --rm -d --name test alpine tail -f /dev/null 9232f0c1dafe0f29918f281ca37bb41914677e818cb6f252abf3dab3be04fbb2 $ docker exec test touch proof $ docker exec test ls -hl proof -rw-r--r-- 1 root root 0 Nov 20 14:33 proof
執行導出操作:
docker export test -o test.tar
Import
首先,關閉剛才運行的服務。
$ docker kill test test
執行導入操作:
$ docker import test.tar test-img sha256:e03727eeba7e16dd3acfcc7536f1244762508f9b6b9856e49cc837c1b7ffa444
要注意的是, import 后得到的是一個鏡像,相當於是執行了 docker commit 后的內容。 當然, docker commit 不是一個推薦的操作,所以容器的導入、導出,就顯得不是那么的順眼。
最后,檢查之前創建的文件。
$ docker run --rm -d --name test test-img tail -f /dev/null ee29cb63bb2d3ed8ac890789ba80c4fe4078b9d5343a8952b6217d64b4dcbe23 $ docker exec test ls -hl proof -rw-r--r-- 1 root root 0 Nov 20 14:33 proof
可以看到,前面創建的文件是存在的,並且時間戳完全一致。
Volume

數據卷的遷移,比較麻煩。 Docker並未提供官方的簡單方案。
當然,直接用 root 用戶訪問文件系統的Docker數據,比如默認的/var/lib/docker/volumes/ 下的文件夾,直接進行打包操作,也不是不行。 但這毫無疑問是最糟糕的方案。
目前參考《 Use volumes | Docker Documentation 》,找到的最佳方案是,用另一個容器,把數據卷內容打包,並且通過掛載的形式傳遞到宿主機。
Backup
首先,准備一個Volume。
$ docker run --rm -d --name test -v test-vol:/data test-img tail -f /dev/null f4ff81f4c31025ff476fbebc2c779a915b43ba5940b5bcc42e3ef9b1379eaeab $ docker exec test touch /data/proof $ docker exec test ls -hl proof -rw-r--r-- 1 root root 0 Nov 20 14:40 proof
執行備份操作:
$ docker run --rm -v test-vol:/volume -v $PWD:/backup alpine tar cvf /backup/backup.tar volume volume/ volume/proof
直接在已運行容器中打包,然后通過 docker cp 復制出來,也是一個方案。 但這會對正在運行的容器有影響,不建議在真正重要的容器中使用。
這里利用了一個 Alpine 鏡像來執行操作。 實際上,任何一個自帶 tar 的鏡像都是可以的。
Restore
首先,清理剛才的容器和數據卷。
$ docker kill test test $ docker volume rm test-vol test-vol
執行還原操作:
docker run --rm -v test-vol:/volume -v $PWD:/backup alpine tar xf /backup/backup.tar
最后,檢查還原后的結果。
$ docker run --rm -v test-vol:/data alpine ls -ahl /data total 8 drwxr-xr-x 2 root root 4.0K Nov 20 14:48 . drwxr-xr-x 1 root root 4.0K Nov 20 14:50 .. -rw-r--r-- 1 root root 0 Nov 20 14:40 proof
結論
以上其實都不是常規手段。
Image的傳遞,更應該依賴於內部Docker Registry而非tar。 (當然,也有例外,比如集群部署大鏡像的P2P方案,也許可以借鑒這個手段。)
Container的狀態,應該是可棄的。 一個運行了很長時間的Container,應該是可以 restart 、甚至 kill 后再重新 run 也不影響既有功能的。 任何有依賴的狀態,都應該考慮持久化、網絡化,而不能單純地保存在本地文件系統中。
Volume的手動遷移,的確可以采用上述方式。 但是,Volume需要手動遷移、備份嗎? 這需要專業而完善的插件來實現。
