Docker container中mount文件內容無法同步的問題解決


  這篇博文主要講述了我遇到的一個Docker使用mount volume中的一個“坑”,即在宿主機中修改了某個已經mount進container的文件,但在container中發現卻沒有改變。我們嘗試找解決方法,也順便嘗試知道是什么原因。

1. 問題描述

在Linux(Oracle Linux Server release 7.7)本地創建一個文件"test.txt"(默認權限664),然后再用如下命令mount進一個container:

docker run -v "/home/ec2-user/deleme_me/test.txt:/test.txt" --rm -it ubuntu:18.04 /bin/bash

在container中看到了"/test.txt"的內容與宿主機相同。

然后在宿主機上用vim(7.4.1099)修改文件內容,增加一行內容,再到container中,發現/test.txt並沒有隨之變化。

很顯然,這不是我們所期望的,按照我們的設想,在這樣的mount之后,宿主機和container中文件的變更應該是雙向同步的,即在容器中改變文件內容,宿主機中應當即時得到更新,反之亦然,因為mount本身就表示同一個文件,只是借由docker使其其出現在了不同的 Mount namespaces 中。

那究竟是什么原因導致這樣與設想大相徑庭的結果呢?

2. 問題分析

我們知道,在Docker中,mount volume的原理是借用了Linux Namespace中的 Mount NameSpace,隔離系統中不同進程的掛載點視圖,實際文件是沒有變化的,比如上面的例子,在container中,/bin/bash實際就是一個運行在宿主機上的進程,被Docker用Linux分別隔離了Mount Namespace、UTS Namespace、IPC Namespace、PID Namespace、Network Namespace和User Namespace,使得它看上去好像運行在了一個獨立的、相對隔離的系統上,但實際它的一切資源都是宿主機在不同Namespace中的一個投影,文件也不例外。

所謂文件沒有變化,我們如何證明呢?在Linux中,證明文件是否相同的根本途徑是,判斷其inode,如果兩個文件的inode相同,兩個文件必定為同一文件,從而兩個文件的內容也必然相同。

那我們來看看宿主機和container中看到的text.txt是不是一樣:

// container中
root@e365010a98f6:/# stat test.txt File: test.txt Size: 7 Blocks: 8 IO Block: 4096 regular file Device: ca01h/51713d Inode: 4510751 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ UNKNOWN) Gid: ( 1000/ UNKNOWN) Access: 2020-04-26 14:03:12.898485003 +0000 Modify: 2020-04-26 14:03:12.898485003 +0000 Change: 2020-04-27 01:35:38.779485729 +0000 Birth: -

 

// 宿主機中
$ stat test.txt File: 'test.txt' Size: 7 Blocks: 8 IO Block: 4096 regular file Device: ca01h/51713d Inode: 4510751 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ec2-user) Gid: ( 1000/ec2-user) Access: 2020-04-26 14:03:12.898485003 +0000 Modify: 2020-04-26 14:03:12.898485003 +0000 Change: 2020-04-27 01:35:38.779485729 +0000 Birth: -

以上兩個代碼塊中,上圖是container中的,下圖時候宿主機中的。我們看到在容器中和宿主機中的test.txt的inode號都是4510745,即可認為是同一文件。

這時,回到我們剛開始遇到的那個問題,我們在宿主機中修改test.txt文件,用Vim打開文件,追加一行,然后保存退出,然后打開container中的文件,發現出現了怪事,container中的文件沒有更新,也就是重現了我們一開始描述的問題。

那我們再來看看他們的文件信息:

// container中
root@e365010a98f6:/# stat test.txt File: test.txt Size: 7 Blocks: 8 IO Block: 4096 regular file Device: ca01h/51713d Inode: 4510751 Links: 0 Access: (0664/-rw-rw-r--) Uid: ( 1000/ UNKNOWN) Gid: ( 1000/ UNKNOWN) Access: 2020-04-26 14:03:12.898485003 +0000 Modify: 2020-04-26 14:03:12.898485003 +0000 Change: 2020-04-27 01:42:25.252402227 +0000 Birth: -

 

// 宿主機中
$ stat test.txt File: 'test.txt' Size: 14 Blocks: 8 IO Block: 4096 regular file Device: ca01h/51713d Inode: 6553165 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ec2-user) Gid: ( 1000/ec2-user) Access: 2020-04-27 01:42:25.252402227 +0000 Modify: 2020-04-27 01:42:25.252402227 +0000 Change: 2020-04-27 01:42:25.252402227 +0000 Birth: -

由上面的輸出可以看到,container中的inode沒有變化,但宿主機中的已經變化了,也就是說,從文件系統層面來看,此時container中和宿主機中它們已經不是同一個文件了。既然不是同一個文件,那又有什么同步可言?

那好了,那問題的初步原因明白了,就是用vim在宿主機編輯了被mount進container的文件后,宿主機上的文件inode變化了,導致兩個文件內容無法同步。

那問題就變成vim為何有什么神奇的邏輯呢?

原來,Linux默認情況下,vim為了防止在你修改文件的過程中,由於磁盤或者系統出現問題而導致當前被修改的文件的損壞,它做了類似如下邏輯:

  • 復制出一個需要修改文件的副本,命名為在原來文件的基礎上增加".swp"后綴以及"."前綴
  • 修改內容保存到有".swp"后綴的文件,並flush到磁盤
  • 交換原文件和swp文件的名稱
  • 刪除swp文件

如此一來,在宿主機看來,原來inode就被釋放掉了,可是在container看來,他還是需要留着這個inode。

3. 解決方法

提到解決,實際上無解的,因為以上出現的每一方站在其自身的角度看,都是合理的,這些邏輯也是by design的。於是乎,我們就尋找workaround的角度來嘗試繞過我們的問題吧。

以下幾種方法均可以成功繞過該問題:

  • 用echo等代替vim文件修改

既然這個修改文件的邏輯是vim引入的,那么我們替換vim就可以解決問題了,增加文件內容的方法很多,比如我們可以echo代替:

root@2c8d3dfc7d57:/# echo hello >> test.txt
  • 修改vim配置

打開vim,輸入

:scriptnames

找到vimrc的路徑,例如是"/etc/vimrc",再打開"/etc/vimrc",添加如下兩行:

set backup
set backupcopy=yes

這樣可以解決問題,不過也有一個很大的副作用,那就是每次用vim編輯文件保存之后,vim會生成一個類似該被修改文件,但末尾增加了一個"~"后綴,用以保存修改之前的文件內容。

  • 修改文件權限

我們發現,當文件的權限修改為"其他user有寫權限"后,以上說的vim邏輯就變了,修改保存后,原文件的inode不再變化,這就使得我們workaround變得非常簡單:

$ chmod 666 test.txt

這個應該是目前為止,最為輕量的workaround了。

4. 參考

1. https://forums.docker.com/t/modify-a-file-which-mount-as-a-data-volume-but-it-didnt-change-in-container/2813

2. https://unix.stackexchange.com/questions/36467/why-inode-value-changes-when-we-edit-in-vi-editor

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM