讓 Docker 引覺得傲的是它可以實現相比於其餘虛擬化軟件更快的環境遷移和部署,在這件事情上,輕量級的容器和鏡像結構的設計無疑發揮了巨大的做用。經過將容器打包成鏡像,再利用體積遠小於其餘虛擬化軟件的 Docker 鏡像,咱們能夠更快的將它們複製到其餘的機器上。在這一節中,咱們就專門來談談如何進行這樣的遷移。mysql
以前咱們已經介紹過了,Docker 鏡像的本質是多個基於 UnionFS 的鏡像層依次掛載的結果,而容器的文件系統則是在以只讀方式掛載鏡像後增長的一個可讀可寫的沙盒環境。
基於這樣的結構,Docker 中爲咱們提供了將容器中的這個可讀可寫的沙盒環境持久化爲一個鏡像層的方法。更淺顯的說,就是咱們可以很輕鬆的在 Docker 裏將容器內的修改記錄下來,保存爲一個新的鏡像。
將容器修改的內容保存爲鏡像的命令是 docker commit
,因爲鏡像的結構很像代碼倉庫裏的修改記錄,而記錄容器修改的過程又像是在提交代碼,因此這裏咱們更形象的稱之爲提交容器的更改。nginx
sudo docker commit webapp sha256:0bc42f7ff218029c6c4199ab5c75ab83aeaaed3b5c731f715a3e807dda61d19e
Docker 執行將容器內沙盒文件系統記錄成鏡像層的時候,會先暫停容器的運行,以保證容器內的文件系統處於一個相對穩定的狀態,確保數據的一致性。web
在使用 docker commit 提交鏡像更新後,咱們能夠獲得 Docker 建立的新鏡像的 ID,以後咱們也可以從本地鏡像列表中找到它。sql
$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 0bc42f7ff218 3 seconds ago 372MB ## ......
像經過 Git 等代碼倉庫軟件提交代碼同樣,咱們還能在提交容器更改的時候給出一個提交信息,方便之後查詢。docker
sudo docker commit -m "Configured" webapp
在上面的例子裏,咱們發現提交容器更新後產生的鏡像並沒 REPOSITORY 和 TAG 的內容,也就是說,這個新的鏡像尚未名字。app
以前咱們談到過,使用沒有名字的鏡像並非很好的選擇,由於咱們沒法直觀的看到咱們正在使用什麼。好在 Docker 爲咱們提供了一個爲鏡像取名的命令,也就是 docker tag
命令。webapp
sudo docker tag 0bc42f7ff218 webapp:1.0
使用 docker tag
可以爲未命名的鏡像指定鏡像名,也可以對已有的鏡像建立一個新的命名。ide
sudo docker tag webapp:1.0 webapp:latest
當咱們對未命名的鏡像進行命名後,Docker 就不會在鏡像列表裏繼續顯示這個鏡像,取而代之的是咱們新的命名。而若是咱們對之後鏡像使用 docker tag,舊的鏡像依然會存在於鏡像列表中。設計
$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE webapp 1.0 0bc42f7ff218 29 minutes ago 372MB webapp latest 0bc42f7ff218 29 minutes ago 372MB
因爲鏡像是對鏡像層的引用記錄,因此咱們對鏡像進行命名後,雖然可以在鏡像列表裏同時看到新老兩個鏡像,實質是它們其實引用着相同的鏡像層,這個咱們可以從鏡像 ID 中看得出來 ( 由於鏡像 ID 就是最上層鏡像層的 ID )。正是這個緣由,咱們雖然建立了新的鏡像,但對物理存儲的佔用空間卻不是鏡像大小直接翻倍,而且建立也在霎那之間。code
除了使用 docker tag
在容器提交爲新的鏡像後爲鏡像命名這種方式外,咱們還能夠直接在docker commit
命令裏指定新的鏡像名,這種方式在使用容器提交時會更加方便。
sudo docker commit -m "Upgrade" webapp webapp:2.0
在咱們將更新導出爲鏡像後,就能夠開始遷移鏡像的工做了。
因爲 Docker 是以集中的方式管理鏡像的,因此在遷移以前,咱們要先從 Docker 中取出鏡像。docker save
命令能夠將鏡像輸出,提供了一種讓咱們保存鏡像到 Docker 外部的方式。
sudo docker save webapp:1.0 > webapp-1.0.tar
在默認定義下,docker save
命令會將鏡像內容放入輸出流中,這就須要咱們使用管道進行接收 ( 也就是命令中的 > 符號 ),這屬於 Linux 等系統控制檯中的用法,這裏咱們不作詳細講解。
管道這種用法有時候依然不太友好,docker save
命令還爲咱們提供了 -o 選項,用來指定輸出文件,使用這個選項可讓命令更具備統一性。
sudo docker save -o ./webapp-1.0.tar webapp:1.0
在鏡像導出以後,咱們就能夠找到已經存儲鏡像內容的 webapp-1.0.tar 這個文件了。有興趣的朋友,可使用解壓軟件查看其中的內容,你會看到裏面其實就是鏡像所基於的幾個鏡像層的記錄文件。
咱們能夠經過不少種方式將導出的鏡像文件複製到另外一臺機器上,在這麼操做以後,咱們就要將鏡像導入到這臺新機器中運行的 Docker 中。
導入鏡像的方式也很簡單,使用與docker save
相對的docker load
命令便可。
sudo docker load < webapp-1.0.tar
相對的,docker load
命令是從輸入流中讀取鏡像的數據,因此咱們這裏也要使用管道來傳輸內容。固然,咱們也可以使用 -i 選項指定輸入文件。
sudo docker load -i webapp-1.0.tar
鏡像導入後,咱們就能夠經過 docker images
看到它了,導入的鏡像會延用原有的鏡像名稱。
經過 docker save
和 docker load
命令咱們還可以批量遷移鏡像,只要咱們在 docker save
中傳入多個鏡像名做爲參數,它就可以將這些鏡像都打成一個包,便於咱們一次性遷移多個鏡像。
sudo docker save -o ./images.tar webapp:1.0 nginx:1.12 mysql:5.7
裝有多個鏡像的包能夠直接被 docker load
識別和讀取,咱們將這個包導入後,全部其中裝載的鏡像都會被導入到 Docker 之中。
也許 Docker 的開發者認爲,提交鏡像修改,再導出鏡像進行遷移的方法還不夠效率,因此還爲咱們提供了一個導出容器的方法。
使用 docker export
命令咱們能夠直接導出容器,咱們能夠把它簡單的理解爲 docker commit
與 docker save
的結合體。
sudo docker export -o ./webapp.tar webapp
相對的,使用 docker export
導出的容器包,咱們可使用 docker import
導入。這裏須要注意的是,使用 docker import
並不是直接將容器導入,而是將容器運行時的內容以鏡像的形式導入。因此導入的結果實際上是一個鏡像,而不是容器。在 docker import
的參數裏,咱們能夠給這個鏡像命名。
sudo docker import ./webapp.tar webapp:1.0
在開發的過程當中,使用 docker save
和 docker load
,或者是使用 docker export
和 docker import
均可以達到遷移容器或者鏡像的目的。————————————————