個人網(wǎng)站開發(fā)總結(jié)文檔百度推廣最近怎么了
前幾篇文章中,重點(diǎn)講解了如何實(shí)現(xiàn)構(gòu)建容器,需要回顧的小伙伴可以看以下文章:
- 《Docker實(shí)戰(zhàn)06|深入剖析Docker Run命令》
- 《Docker實(shí)戰(zhàn)07|Docker增加容器資源限制》
- 《Docker實(shí)戰(zhàn)08|Docker管道及環(huán)境變量識別》
以上三篇主要實(shí)現(xiàn)了Docker Run命令、Docker如何對容器資源進(jìn)行限制以及Docker不同進(jìn)程之間是如何進(jìn)行通信的底層原理與實(shí)現(xiàn)。
接下來的時間會和大家一起學(xué)習(xí)Docker是如何構(gòu)造鏡像的。
使用busybox創(chuàng)建容器
獲取代碼
git clone https://gitee.com/mjreams/docker.git
busybox
首先使用一個最精簡的鏡像——busybox。busybox是一個集合了非常多UNIX工具的箱子,他可以提供非常多在UNIX環(huán)境下經(jīng)常使用的命令,可以說busybox提供了一個非常完整而且小巧的系統(tǒng)。 本文中也會先使用它來作為第一個容器內(nèi)運(yùn)行的文件系統(tǒng)。
獲得busybox文件系統(tǒng)的rootfs很簡單,可以使用docker export將一個鏡像打成一個tar包。
docker pull busybox
docker run -d busybox top -b
docker export -o busybox.tar 6e6415edd69c(容器ID)
mkdir busybox
tar -xvf ./busybox.tar -C busybox/
root@iZ2ze:~/busybox# ls
bin dev etc home lib lib64 proc root sys tmp usr var
pivot_root
pivot_root是一個系統(tǒng)調(diào)用,主要功能是去改變當(dāng)前的root文件系統(tǒng)。pivot_root可以將當(dāng)前進(jìn)程的root文件系統(tǒng)移動到put_old文件夾中,然后使new_root成為新的root文件系統(tǒng)。new_root和put_old必須不能同時存在當(dāng)前root的同一個文件系統(tǒng)中。pivot_root和chroot的主要區(qū)別是,pivot_root是把整個系統(tǒng)切換到一個新的root目錄,而移除對之前root文件系統(tǒng)的依賴,這樣你就能夠umount原先的root文件系統(tǒng)。而chroot是針對某個進(jìn)程,系統(tǒng)的其他部分依舊運(yùn)行于老的root目錄中。
下面,一起把代碼來實(shí)現(xiàn)一下。
見container/init.go
有了這個函數(shù)后,就可以在init容器進(jìn)程的時候,進(jìn)行一系列的mount操作 。
其中,tmpfs是一種基于內(nèi)存的文件系統(tǒng),可以使用RAM或swap分區(qū)來存儲。下面把下載好的busybox放到/root/busybox宿主機(jī)的目錄下,使用cmd.Dir="/root/busybox"這個方法給創(chuàng)建出來的子進(jìn)程指定容器初始化后的工作目錄,然后就會運(yùn)行前面講到的那些進(jìn)程,掛載rootfs然后把當(dāng)前目錄虛擬成根目錄。
將此處修改為cmd.Dir="/root/busybox"
下面運(yùn)行一下來看看效果。
我此處使用的是容器鏡像的名字進(jìn)行掛載。你如果修改成/root/busybox
,則此處顯示/root/busybox
。
使用AUFS包裝busybox
Docker在使用鏡像啟動一個容器時,會新建2個layer: writelayer和container-init layer。write layer是容器唯一的可讀寫層:而container-init layer是為容器新建的只讀層,用來存儲容器啟動時傳入的系統(tǒng)信息(前面也提到過,在實(shí)際的場景下,它們并不是以write layer和container-init layer命名的)。最后把write layer、container叮iit layer和相關(guān)鏡像的layers都mount到一個mnt目錄下,然后把這個mnt目錄作為容器啟動的根目錄。
在上面己經(jīng)實(shí)現(xiàn)了使用宿主機(jī)/root/busybox目錄作為文件的根目錄,但在容器內(nèi)對文件的操作仍然會直接影響到宿主機(jī)的/root/busybox目錄。本節(jié)要進(jìn)一步進(jìn)行容器和鏡像隔離,實(shí)現(xiàn)在容器中進(jìn)行的操作不會對鏡像產(chǎn)生任何影響的功能。
見container/volume.go
- CreateReadOnlyLayer函數(shù)新建busybox文件夾,將busybox.tar 解壓到busybox目錄下,作為容器的只讀層。
- CreateWriteLayer函數(shù)創(chuàng)建了一個名為writeLayer的文件夾,作為容器唯一的可寫層。
- 在CreateMountPoint函數(shù)中,首先創(chuàng)建了mnt文件夾,作為掛載點(diǎn),然后把writeLayer目錄和busybox目錄mount到mnt目錄下。
最后,在NewParentProcess函數(shù)中將容器使用的宿主機(jī)目錄/root/busybox 替換成/root/mnt。
此處將busybox.tar解壓到busybox目錄下,作為容器的只讀層。
接下來,在NewParentProcess函數(shù)中將容器使用的宿主機(jī)目錄/root/busybox替換成/root/mnt。這樣,使用 AUFS 系統(tǒng)啟動容器的代碼就完成了。
Docker會在刪除容器的時候,把容器對應(yīng)的Write Layer和Container-init Layer刪除,而保留鏡像所有的內(nèi)容。本節(jié)中,在容器退出的時候會刪除Write Layer。DeleteWorkSpace函數(shù),包括DeleteMountPoint和DeleteWrite Layer。
- 首先,在 DeleteMountPoint 函數(shù)中 umountmnt 目錄 。
- 然后,刪除 mnt 目錄。
- 最后,在 DeleteWriteLayer 函數(shù)中刪除 writeLayer 文件夾。這樣容器對文件系統(tǒng)的更改就都己經(jīng)抹去了。
見container/volume.go
整體流程如下:
測試
啟動一個容器
./mydocker run -ti sh
sh-5.1# ls /root
bash busybox busybox.tar mnt writeLayer
在容器中新建一個文件夾。
新建一個宿主機(jī)窗口,查看/root/mnt目錄。
可以看到多了一個studydocker文件夾。
在容器中執(zhí)行exit退出容器,,然后再次查看宿主機(jī)上的/root/mnt文件夾內(nèi)容。發(fā)現(xiàn)已經(jīng)沒有了剛才的容器。