Docker(3)Volume與綁定掛載(bind mount)機制

1. 問題背景

Docker項目使用了mount namespace和rootfs的文件鏡像來實現了容器鏡像文件系統和宿主機系統的隔離。但是,以下兩個容器和宿主機的文件交互問題怎麼解決?

  • 容器中新建的文件,宿主機怎麼獲取到?
  • 宿主機上的文件和目錄,容器內部進程怎麼獲取?

2. 使用方式

可以通過以下兩種起Docker容器的方式,把宿主機目錄掛載進入容器的對應目錄:

$ docker run -v /docker_dir ...
$ docker run -v /home:/docker_dir ...

當不指明宿主機目錄時,Docker會默認在宿主機上創建一個臨時目錄: /var/lib/docker/volumes/[VOLUME_ID]/_data作爲宿主機上的被掛載目錄。

3. 原理

3.1 Docker容器原理

回憶《Docker(2)容器技術基本概念理解》中的Docker容器的核心原理:

  • 啓動Linux Namespace配置
  • 設置指定的Cgroups參數
  • 切換進程的根目錄(change root, 配合namespace mount)
    而在第三步執行chroot和pivot_root之前,容器進程是可以一直看到宿主機上的整個文件系統的。所以可以在這裏做點文章。

3.2 綁定掛載(bind mount)機制

當我們宿主機上已經存在了一個容器鏡像時,鏡像的各個層,都被保存在/var/lib/docker/aufs/diff目錄下,容器啓動之後,會被聯合掛載在/var/lib/docker/aufs/mnt下,這時候容器所需要的rootfs就準備好了。
因此,對於 2. 使用方式 中的場景,我們只需要在rootfs準備好,chroot執行之前,吧Volume指定的宿主機目錄(比如/home目錄),掛載到指定的容器目錄(如/test目錄)在宿主機上對應的目錄(/var/lib/docker/aufs/mnt/[可讀可寫層ID]/test)上,這個Volume掛載工作就完成了。
同時,因爲執行掛載時,“容器進程”已經完成了創建,所以這時Mount Namespace已經開啓,所以這個掛載點,只能在容器中看見,宿主機是看不到的。保證了容器的隔離性不會被Volume打破
上面提到的掛載操作,使用的就是Linux的綁定掛載(bind mount)機制。

綁定掛載
允許用戶將一個目錄或者文件,掛載到一個指定的目錄上,並且,之後在這個掛載點上的操作,只發生在被掛載的目錄或者文件上,而原來掛載點的內容會被隱藏起來不受影響。

該去學習一下Linux內核了
綁定掛載其實是一個inode替換的過程,在Linux操作系統中,inode可以理解爲存放文件內容的對象,而dentry,也叫目錄項,就是訪問這個inode所使用的“指針”。
在下圖中,mount --bind /home /test ,會把/home掛載到/test上,實際上相當於吧/test的/dentry,指向修改爲/home的inode,這樣修改/test,實際上修改的是/home對應的inode。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章