個人網(wǎng)站開發(fā)總結(jié)文檔百度推廣最近怎么了
前幾篇文章中,重點講解了如何實現(xiàn)構(gòu)建容器,需要回顧的小伙伴可以看以下文章:
- 《Docker實戰(zhàn)06|深入剖析Docker Run命令》
- 《Docker實戰(zhàn)07|Docker增加容器資源限制》
- 《Docker實戰(zhàn)08|Docker管道及環(huán)境變量識別》
以上三篇主要實現(xiàn)了Docker Run命令、Docker如何對容器資源進行限制以及Docker不同進程之間是如何進行通信的底層原理與實現(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)運行的文件系統(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)用,主要功能是去改變當前的root文件系統(tǒng)。pivot_root可以將當前進程的root文件系統(tǒng)移動到put_old文件夾中,然后使new_root成為新的root文件系統(tǒng)。new_root和put_old必須不能同時存在當前root的同一個文件系統(tǒng)中。pivot_root和chroot的主要區(qū)別是,pivot_root是把整個系統(tǒng)切換到一個新的root目錄,而移除對之前root文件系統(tǒng)的依賴,這樣你就能夠umount原先的root文件系統(tǒng)。而chroot是針對某個進程,系統(tǒng)的其他部分依舊運行于老的root目錄中。
下面,一起把代碼來實現(xiàn)一下。
見container/init.go
有了這個函數(shù)后,就可以在init容器進程的時候,進行一系列的mount操作 。
其中,tmpfs是一種基于內(nèi)存的文件系統(tǒng),可以使用RAM或swap分區(qū)來存儲。下面把下載好的busybox放到/root/busybox宿主機的目錄下,使用cmd.Dir="/root/busybox"這個方法給創(chuàng)建出來的子進程指定容器初始化后的工作目錄,然后就會運行前面講到的那些進程,掛載rootfs然后把當前目錄虛擬成根目錄。
將此處修改為cmd.Dir="/root/busybox"
下面運行一下來看看效果。
我此處使用的是容器鏡像的名字進行掛載。你如果修改成/root/busybox
,則此處顯示/root/busybox
。
使用AUFS包裝busybox
Docker在使用鏡像啟動一個容器時,會新建2個layer: writelayer和container-init layer。write layer是容器唯一的可讀寫層:而container-init layer是為容器新建的只讀層,用來存儲容器啟動時傳入的系統(tǒng)信息(前面也提到過,在實際的場景下,它們并不是以write layer和container-init layer命名的)。最后把write layer、container叮iit layer和相關(guān)鏡像的layers都mount到一個mnt目錄下,然后把這個mnt目錄作為容器啟動的根目錄。
在上面己經(jīng)實現(xiàn)了使用宿主機/root/busybox目錄作為文件的根目錄,但在容器內(nèi)對文件的操作仍然會直接影響到宿主機的/root/busybox目錄。本節(jié)要進一步進行容器和鏡像隔離,實現(xiàn)在容器中進行的操作不會對鏡像產(chǎn)生任何影響的功能。
見container/volume.go
- CreateReadOnlyLayer函數(shù)新建busybox文件夾,將busybox.tar 解壓到busybox目錄下,作為容器的只讀層。
- CreateWriteLayer函數(shù)創(chuàng)建了一個名為writeLayer的文件夾,作為容器唯一的可寫層。
- 在CreateMountPoint函數(shù)中,首先創(chuàng)建了mnt文件夾,作為掛載點,然后把writeLayer目錄和busybox目錄mount到mnt目錄下。
最后,在NewParentProcess函數(shù)中將容器使用的宿主機目錄/root/busybox 替換成/root/mnt。
此處將busybox.tar解壓到busybox目錄下,作為容器的只讀層。
接下來,在NewParentProcess函數(shù)中將容器使用的宿主機目錄/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
在容器中新建一個文件夾。
新建一個宿主機窗口,查看/root/mnt目錄。
可以看到多了一個studydocker文件夾。
在容器中執(zhí)行exit退出容器,,然后再次查看宿主機上的/root/mnt文件夾內(nèi)容。發(fā)現(xiàn)已經(jīng)沒有了剛才的容器。