1. 問題背景
Docker項(xiàng)目使用了mount namespace和rootfs的文件鏡像來實(shí)現(xiàn)了容器鏡像文件系統(tǒng)和宿主機(jī)系統(tǒng)的隔離。但是诉字,以下兩個(gè)容器和宿主機(jī)的文件交互問題怎么解決多糠?
- 容器中新建的文件累舷,宿主機(jī)怎么獲取到?
- 宿主機(jī)上的文件和目錄夹孔,容器內(nèi)部進(jìn)程怎么獲缺挥?
2. 使用方式
可以通過以下兩種起Docker容器的方式搭伤,把宿主機(jī)目錄掛載進(jìn)入容器的對(duì)應(yīng)目錄:
$ docker run -v /docker_dir ...
$ docker run -v /home:/docker_dir ...
當(dāng)不指明宿主機(jī)目錄時(shí)只怎,Docker會(huì)默認(rèn)在宿主機(jī)上創(chuàng)建一個(gè)臨時(shí)目錄: /var/lib/docker/volumes/[VOLUME_ID]/_data作為宿主機(jī)上的被掛載目錄。
3. 原理
3.1 Docker容器原理
回憶《Docker(2)容器技術(shù)基本概念理解》中的Docker容器的核心原理:
- 啟動(dòng)Linux Namespace配置
- 設(shè)置指定的Cgroups參數(shù)
- 切換進(jìn)程的根目錄(change root, 配合namespace mount)
而在第三步執(zhí)行chroot和pivot_root之前怜俐,容器進(jìn)程是可以一直看到宿主機(jī)上的整個(gè)文件系統(tǒng)的身堡。所以可以在這里做點(diǎn)文章。
3.2 綁定掛載(bind mount)機(jī)制
當(dāng)我們宿主機(jī)上已經(jīng)存在了一個(gè)容器鏡像時(shí)拍鲤,鏡像的各個(gè)層贴谎,都被保存在/var/lib/docker/aufs/diff目錄下,容器啟動(dòng)之后季稳,會(huì)被聯(lián)合掛載在/var/lib/docker/aufs/mnt下赴精,這時(shí)候容器所需要的rootfs就準(zhǔn)備好了。
因此绞幌,對(duì)于 2. 使用方式 中的場(chǎng)景,我們只需要在rootfs準(zhǔn)備好一忱,chroot執(zhí)行之前莲蜘,吧Volume指定的宿主機(jī)目錄(比如/home目錄)谭确,掛載到指定的容器目錄(如/test目錄)在宿主機(jī)上對(duì)應(yīng)的目錄(/var/lib/docker/aufs/mnt/[可讀可寫層ID]/test)上,這個(gè)Volume掛載工作就完成了票渠。
同時(shí)逐哈,因?yàn)閳?zhí)行掛載時(shí),“容器進(jìn)程”已經(jīng)完成了創(chuàng)建问顷,所以這時(shí)Mount Namespace已經(jīng)開啟昂秃,所以這個(gè)掛載點(diǎn),只能在容器中看見杜窄,宿主機(jī)是看不到的肠骆。保證了容器的隔離性不會(huì)被Volume打破。
上面提到的掛載操作塞耕,使用的就是Linux的綁定掛載(bind mount)機(jī)制蚀腿。
綁定掛載
允許用戶將一個(gè)目錄或者文件,掛載到一個(gè)指定的目錄上扫外,并且莉钙,之后在這個(gè)掛載點(diǎn)上的操作,只發(fā)生在被掛載的目錄或者文件上筛谚,而原來掛載點(diǎn)的內(nèi)容會(huì)被隱藏起來不受影響磁玉。
該去學(xué)習(xí)一下Linux內(nèi)核了
綁定掛載其實(shí)是一個(gè)inode替換的過程,在Linux操作系統(tǒng)中驾讲,inode可以理解為存放文件內(nèi)容的對(duì)象蚊伞,而dentry,也叫目錄項(xiàng)蝎毡,就是訪問這個(gè)inode所使用的“指針”厚柳。
在下圖中,mount --bind /home /test 沐兵,會(huì)把/home掛載到/test上别垮,實(shí)際上相當(dāng)于吧/test的/dentry,指向修改為/home的inode扎谎,這樣修改/test碳想,實(shí)際上修改的是/home對(duì)應(yīng)的inode。