基于已有容器構(gòu)建自己的 Docker 鏡像
通過前面的介紹,我們知道了Docker 鏡像是多個基于 UnionFS 的鏡像層依次掛載的結(jié)果,而容器的文件系統(tǒng)則是在以只讀方式掛載鏡像后增加的一個可讀可寫的文件系統(tǒng)復(fù)合而成。
Docker 中為我們提供了將容器中的這個可讀可寫的環(huán)境持久化為一個鏡像層的方法,即docker commit
。 docker commit
將容器修改的內(nèi)容保存為鏡像,我們可以把它理解為提交容器的更改。
1.生成變更后的鏡像
我們以上一節(jié)的 busybox 為例:
# 重新創(chuàng)建一個busybox容器
docker run --name busybox -d -i busybox
# 進(jìn)入容器
docker exec -it busybox sh
# 做些更改,新建個文件
echo 'something' > something
# 查看變更后的目錄和文件
ls
exit
退出容器后,使用docker commit
進(jìn)行提交變更
[root@centos8 ~]# docker commit -m 'something' busybox
sha256:19da0182bca9305944f6a66b1331ff7394a915bc8982cf520660a883484699fc
-m
參數(shù)進(jìn)行提交的注釋,用法類似 git。
執(zhí)行 docker commit
將容器記錄成鏡像層的時候,會先暫停容器的運行,以保證容器內(nèi)的文件系統(tǒng)處于一個相對穩(wěn)定的狀態(tài),確保數(shù)據(jù)的一致性。提交鏡像更新后,docker images
從本地鏡像列表中找到它。
2. 為鏡像命名
在上面的例子里,我們發(fā)現(xiàn)提交容器更新后產(chǎn)生的鏡像并沒有 REPOSITORY 和 TAG 的內(nèi)容,也就是說,這個新的鏡像還沒有名字。 Docker 為我們提供了一個為鏡像取名的命令,也就是 docker tag
命令。
docker tag 19da0182bca9 mybusybox:1.0
使用 docker tag
也能夠?qū)σ延械溺R像創(chuàng)建一個新的別名副本(舊的鏡像與名稱也會保留)。
docker tag mybusybox:1.0 mybusybox:latest
當(dāng)然,我們可以在提交變更的時候同時命名鏡像
docker commit -m 'something' busybox mybusybox2:latest
3. 遷移鏡像
在我們將更新導(dǎo)出為鏡像后,我們還可以開始遷移鏡像。
由于 Docker 是以集中的方式管理鏡像的,所以在遷移之前,我們要先從 Docker 中取出鏡像。docker save
命令可以將鏡像輸出,提供了一種讓我們保存鏡像到 Docker 外部的方式。
# 將 something:latest鏡像,導(dǎo)出到something-latest.tar
docker save -o ./something-latest.tar something:latest
-o
選項,用來指定輸出文件
在鏡像導(dǎo)出之后,我們就可以找到已經(jīng)存儲鏡像內(nèi)容的 something-latest.tar 這個文件了。如果使用解壓軟件查看其中的內(nèi)容,會看到里面其實就是鏡像所基于的幾個鏡像層的記錄文件。
我們可以通過很多種方式將導(dǎo)出的鏡像文件復(fù)制到另一臺機器上,在這么操作之后,我們就要將鏡像導(dǎo)入到這臺新機器中運行的 Docker 中。
導(dǎo)入鏡像用 docker load
命令即可。
Tips: 我們并不真的需要一臺新的機器,把當(dāng)前環(huán)境中 Docker something 鏡像刪掉即可
docker image rm something:latest
docker load -i something-latest.tar
鏡像導(dǎo)入后,我們就可以通過 docker images
看到它了,導(dǎo)入的鏡像會延用原有的鏡像名稱。
4. 從容器直接導(dǎo)出到鏡像壓縮包
使用 docker export
命令我們可以直接導(dǎo)出容器,我們可以把它理解為 docker commit
與 docker save
的結(jié)合體。
下面我們從容器 busybox 中直接導(dǎo)出鏡像包:
docker export -o ./something-export.tar busybox
需要注意的是,這種方式導(dǎo)出的鏡像壓縮包不能使用docker load
的方式導(dǎo)入,而應(yīng)該使用 docker import
。使用 docker import
并非直接將容器導(dǎo)入,而是將容器運行時的內(nèi)容以鏡像的形式導(dǎo)入。所以導(dǎo)入的結(jié)果其實是一個鏡像,而不是容器。在 docker import
的參數(shù)里,我們需要給這個鏡像命名。
docker import ./something-export.tar something:export
5. 小結(jié)
這一節(jié)我們介紹了如何通過 docker commit
工具,從容器快速生成 Docker 鏡像,在開發(fā)的過程中,使用 docker save
和 docker load
,或者是使用 docker export
和 docker import
都可以達(dá)到遷移容器或者鏡像的目的。但這種方式可維護(hù)性較差,后面的章節(jié)我們會學(xué)習(xí)如何使用 Dockerfile,從基礎(chǔ)鏡像來構(gòu)建新的鏡像,這也是 Docker 官方推薦的方式。