rootfs 與容器技術(shù)
回到我們?cè)?Linux 的環(huán)境,運(yùn)行我們的“容器”:
/root/test/container
我們是不是可以像虛擬機(jī)中的操作系統(tǒng)一樣,在容器中“為非作歹”了呢?
那!當(dāng)!然!不!行!啦!
1. 為什么需要 rootfs
先忽略 Cgroup 機(jī)制。在容器中探索時(shí),不知大家是否發(fā)現(xiàn),/bin,/etc,/var ...
等等目錄下的內(nèi)容,它們與宿主機(jī)的目錄完全一致。你在這些目錄里的更改一樣會(huì)影響到宿主機(jī)。聰明的讀者一定發(fā)現(xiàn)了,我們創(chuàng)建進(jìn)程的時(shí)候不是指定開啟 Mount Namespace 了嗎,為什么不生效呢?
即使我們啟用了 Mount Namespace,但它需要手動(dòng)指定掛載時(shí)才能生效,我們?cè)诖a中指定容器進(jìn)程中的 /tmp
目錄使用空的內(nèi)存盤掛載,所以我們?cè)谌萜髦性L問到的 /tmp
目錄是空的,與宿主機(jī)不一致的。
至于其他的目錄,因?yàn)槲覀円矝]有指定掛載點(diǎn)變更,它們會(huì)直接使用宿主機(jī)的目錄。但理想狀態(tài)下,我們會(huì)希望,進(jìn)入在一個(gè)新的容器后,它的所有文件都應(yīng)該盡可能與宿主機(jī)隔離,我們才能放心使用它。
實(shí)現(xiàn)起來也不算復(fù)雜,我們知道 Linux 的目錄結(jié)構(gòu)都是從 /
開始的,如果我們制作一份 /
目錄,然后在容器進(jìn)程啟動(dòng)的時(shí)候?qū)⑺袚Q掛載到容器的 /
,就可以解決這個(gè)問題。而像這種完整包含根目錄的拷貝,我們稱呼它:rootfs。
2. 構(gòu)建 rootfs
構(gòu)建一個(gè)真正可用的 rootfs 的過程其實(shí)非常繁瑣,我們不需要了解它的細(xì)節(jié),我們僅僅需要使用它基本的功能理解 rootfs 即可。
這里我們使用的構(gòu)建命令如下:
cd /root/test/
mkdir rootfs
# 為rootfs提供初始目錄結(jié)構(gòu)和核心依賴庫
sudo rpm -ivh --nodeps --root /home/root/test/rootfs https://mirrors.aliyun.com/centos/8/BaseOS/x86_64/os/Packages/centos-release-8.1-1.1911.0.9.el8.x86_64.rpm
# 為rootfs安裝vim 工具和gcc編譯環(huán)境
sudo dnf --installroot=/root/test/rootfs install vim gcc --nogpgcheck
3. 使用 rootfs
在 Linux 環(huán)境的 /root/test/
目錄下,已經(jīng)有一份打包好的 rootfs,我們直接使用它即可。
我們來探查一下它的目錄結(jié)構(gòu):
tree -L 1
發(fā)現(xiàn)它與宿主機(jī)的/
目錄的結(jié)構(gòu)一致, 因?yàn)樗褪俏覀內(nèi)萜鲗⒁褂玫?code>/。
下面我們讓我們的容器使用這個(gè) rootfs,編寫一個(gè) helloworld 程序
Tip: 下面我們會(huì)使用到 chroot, chroot 是在 unix 系統(tǒng)的一個(gè)操作,針對(duì)正在運(yùn)作的軟件行程和它的子進(jìn)程,改變它外顯的根目錄。一個(gè)運(yùn)行在這個(gè)環(huán)境下,經(jīng)由 chroot 設(shè)置根目錄的程序,它不能夠?qū)@個(gè)指定根目錄之外的文件進(jìn)行訪問動(dòng)作,不能讀取,也不能更改它的內(nèi)容。Namespace Mount 事實(shí)上就是受到 chroot 的啟發(fā)改進(jìn)而來的。
cd /root/test/
## 運(yùn)行容器環(huán)境
./container
## chroot切換到rootfs
chroot /root/rootfs /bin/bash
# 進(jìn)入容器中的home目錄,編寫代碼 helloworld.c并編譯執(zhí)行
cd /home
vim helloworld.c
#include <stdio.h>
int main()
{
// printf() 中字符串需要引號(hào)
printf("Hello, World!");
return 0;
}
保存后編譯運(yùn)行
cc helloworld.c -o helloworld
./helloworld
我們將看到終端中顯示:
hello, world!
這樣我們獲得了一個(gè)文件系統(tǒng)目錄與宿主機(jī)隔離的環(huán)境,在這里,我們可以放心大膽地操作,不用擔(dān)心影響到宿主機(jī)的環(huán)境。
至此,我們獲取了一個(gè)可以使用 C 語言編譯運(yùn)行應(yīng)用的容器。
4. 拓展思考
如果 多個(gè)項(xiàng)目同時(shí)使用這個(gè)容器,他們之間如何隔離文件系統(tǒng)呢?
直接拷貝或者重新構(gòu)建多個(gè) rootfs 似乎可行,但這浪費(fèi)了空間
如果 容器使用過程中,不小心誤刪了某個(gè) rootfs 中的關(guān)鍵文件,導(dǎo)致容器被損壞, 怎么辦?
讓 rootfs 的關(guān)鍵文件設(shè)定為只讀的狀態(tài),似乎可以解決這個(gè)問題。
如果我們想與其他人分享我們的容器和容器內(nèi)的應(yīng)用,該怎么辦呢?
平臺(tái)相同的情況下,我們把 rootfs 和容器進(jìn)程文件拷貝一份副本給他們就行了。傳輸方式?U 盤,網(wǎng)盤,通訊軟件好像都可以。
如果…?
5. 小結(jié)
本節(jié)我們學(xué)習(xí)了容器場(chǎng)景下的 rootfs 需求的認(rèn)知和構(gòu)建使用。需要注意的是,rootfs只是一個(gè)操作系統(tǒng)所包含的文件、配置和目錄,并不包括操作系統(tǒng)內(nèi)核,因此在容器中運(yùn)行的內(nèi)核與宿主機(jī)一致,與內(nèi)核相關(guān)的模塊是無法隔離的。
結(jié)合前兩節(jié)中 Namespace 和 CGroup 的內(nèi)容,我們對(duì)容器技術(shù)的核心概念和原理應(yīng)該具有了充分的理解。但技術(shù)在產(chǎn)品化的過程中,比如拓展思考的部分,僅僅腦補(bǔ)就會(huì)遇到無數(shù)的問題,我們自己的解決方案似乎問題也很大,所以閉門造車是不行的,容器技術(shù)的核心部分將講到這里,下面的章節(jié)就讓主角 Docker 正式登場(chǎng)。