今日筆者docker下出現詭異問題,在容器中vim編輯檔案,儲存是,一直提示 “E667: Fsync failed”,而且在同一個主控端上的容器均有此問題,遂懷疑環境故障,且與存儲相關,後偶然運作指令“docker info”,發現異常資訊:
其中可看到,Data Space Used 已和 Data Space Total一樣,storage Pool用完,呃。。。。 docker start預設配置設定的device mapper的storage pool就是100G,它會把你所有的容器存儲到一個 100G 的簡短檔案中,并且限制每個容器最大為 10GB
要真正了解我們要做的事情,首先來了解 Device Mapper 插件的工作原理。
它是基于 Device Mapper 的“精簡目标”的特性。它實際上是目标塊裝置的快照,之是以被稱為“精簡”是因為它允許精簡配置。精簡配置意味着你有一個(希望很大)可用存儲塊的池,接着你可以從那個池中建立任意大小的塊裝置(虛拟磁盤,如有需要);在你實際讀寫後,這些存儲塊将會被标記為已使用(或者從池中拿走)。
這意味着你是可以超額使用這個池,比如在一個 100GB 的池裡面建立幾千個 10GB 的卷,甚至可能是一個 100TB 的卷在一個 1GB 的池裡面。隻要你的實際讀寫的塊的容量不大于池的大小,你怎麼做都 OK 。
除此之外,精簡目标的方式是可以做快照的。這表明無論何時,你都可以建立一個存在的卷的淺拷貝。在使用者看來,就像你有兩個一樣的卷,它們可以獨立地各自修改。即使你做了一個完整的拷貝,除了在時間上它是瞬間發生的(即使是很大的卷),它們不會兩次重複使用存儲。額外的存儲隻有當其中任何一卷有變化的時候才會發生,然後精簡目标會從池裡面配置設定一個存儲快。
從本質上來看,“精簡目标”實際上使用了兩個儲存設備:一個(大)的是存儲塊池自己,還有一個小的存儲了一些中繼資料。這些中繼資料中包括了卷、快照、以及每個卷的塊或者快照同存儲池中塊的映射資訊。
當 Docker 使用 Device Mapper 存儲插件的時候,它會在 <code>/var/lib/docker/devicemapper/devicemapper/data</code>和<code>/var/lib/docker/devicemapper/devicemapper/metadata</code> 下建立兩個檔案(如果它們不存在)來存儲對應的存儲池和相關的中繼資料。這非常友善,你不需要做任何安裝部署的工作(你不需要額外的分區來存儲 Docker 容器,或者建立 LVM 或其他類似的東西)。然而它也有兩個缺點:
存儲池會有一個預設 100GB 的容量
它将會被稀疏檔案所支援。從磁盤的使用效率的觀點來看,這還不錯的(就像在精簡池中的卷,它一開始是小的,隻有當實際需要寫的時候才會使用磁盤的存儲塊)。但是從性能的角度來看就不那麼好了,因為 VFS 增加了一些額外的負擔,特别是"第一次寫的時候"。
在了解如何調整容器的大小之前,我們來試試看如何給池增加更多空間。
警告:下面的操作會删除你所有的容器和鏡像,確定你已經把之前的資料做了備份!
記住上面說過的,當資料和元類資訊檔案不存在的時候 Docker 會建立它們,是以解決方案非常簡單:在啟動它們之前,在 Docker 裡建立這些檔案!
停止 Docker 守護程序,因為我們将要重新設定我們的存儲插件,如果我們在運作的時候移除檔案,那麼糟糕的事情就将發生。
擦去 <code>/var/lib/docker</code>。(警告:正如前面提到的,這個操作會把你所有的容器和鏡像都删除掉。)
建立存儲目錄: <code>mkdir -p /var/lib/docker/devicemapper/devicemapper</code>
建立你的池: <code>dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/data bs=1G count=0 seek=250</code> ,建立一個 250G 的稀疏檔案。如果你指定 bs=1G count=250(不使用 seek 選項),那麼它會建立一個普通檔案(而不是一個稀疏檔案)。
重新開機 Docker 守護程序。提示:在預設情況下,如果你有 AUFS 的支援, Docker 會使用它;是以如果你要強制使用 Device Mapper 的插件,需要在啟動 Docker 的指令中增加 -s devicemapper 的選項。
使用 <code>docker info</code> 來檢查 Data Space Total 的值是否正确。
警告:下面的操作也會删除你所有的容器和鏡像。確定把你重要的鏡像儲存在 registry 中,儲存你容器裡面的重要資料。
要獲得一個更快速的池,最簡單的辦法就是使用一個真實的裝置而不是一個基于檔案的循環裝置。過程幾乎一樣。假設你有一個完全空的硬碟, /dev/sdb,你想把它完全用于容器的存儲,你可以這樣做:
停止 Docker 守護程序
移除 /var/lib/docker (似曾相識,對麼?)
建立一個存儲目錄: <code>mkdir -p /var/lib/docker/devicemapper/devicemapper</code>
在目錄下建立一個資料軟連結,指向裝置:
重新開機 Docker
使用 docker info 來檢查 Data Space Total 的值是否正确
如果你希望合并多塊相似的磁盤,可以使用 RADID10 軟體,這個會通過連結到 /dev/md 而實作。另外一個非常好的選擇是把你的磁盤(或者RAID磁盤陣列)放到 LVM 的實體卷中,并且建立兩個邏輯卷:一個是資料,一個是中繼資料。對于中繼資料池的最佳的大小我沒有什麼特别的建議,不過占資料池的 1% 看起來不錯。
就像前面一樣,停止 Docker ,移除它的資料目錄,然後建立一個指向 /dev/mapper 裝置的符号連結,然後重新開機 Docker 。
如
之後重新開機docker即可。
預設來說,如果你使用 Device Mapper 的存儲插件,所有的鏡像和容器是從一個初始 10G 的檔案系統中建立的。讓我們來看看如何從一個更大的檔案系統中建立一個容器。
首先,我們用 Ubuntu 的鏡像來建立我們的容器。我們不需要在這個容器裡運作任何東西,隻需要這個檔案(或者關聯的檔案系統)存在。為了示範,我們會在這個容器裡運作 df ,來看一下根檔案系統的大小。
由于需要修改 Device Mapper 管理中的一些卷的資訊,我們現在用 root 的身份來運作一些指令。所有以#開頭的指令都必須以 root 身份來執行。隻要能通路 Docker 的 Socket 服務,你也可以用普通使用者的身份來執行其他的指令(以$開頭)。
讓我們看一下 /dev/mapper ,那裡應該有一個對應容器檔案系統的符号連結,以 docker-X:Y-Z- 開頭:
注意記住那個全名,我們未來會用到。
首先讓我們來看一下目前卷的資訊表:
第二個數字是裝置的大小,表示有多少個 512-bytes 的扇區. 這個值略高于 10GB 的大小。
我們來計算一下一個 42GB 的卷需要多少扇區,
精簡快照目标的一個神奇的特點是它不會限制卷的大小。當你建立它的時候,一個精簡的卷使用0個塊,當你開始往塊裡面寫入的時候,它們會從共用的塊池中進行配置設定。你可以寫0個塊,或者是10億個塊,這個和精簡快照目标沒關系。檔案系統的大小隻和 Device Mapper 表有關系。
覺得困惑?不要擔心。我們隻是需要裝載一個新的表,這個完全和之前的是一樣的,但是有更多的扇區。僅此而已。
舊表是 <code>0 20971520 thin 254:0 7</code> 。我們會改變第二個數字,要非常小心保持其他的值不變。你的卷可能不是 7 ,是以要使用正确的值!
這樣操作:
現在如果我們再次檢查表的資訊,步驟和前面一樣。首先使用下面的指令激活新表:
執行完指令後,再次檢查一下表的資訊,發現它會使用新的扇區數量。
我們已經調整了塊裝置的大小,但是我們仍然需要調整檔案系統的大小,我們使用 resize2fs 來操作:
作為一個可選步驟,我們會重新開機容器,檢查一下我們的确有了正确大小的空閑空間:
想把整個過程自動化起來?當然沒問題。
不幸的是,目前版本的 Docker 不能讓我們很友善地擴容鏡像。你可以把鏡像對應的塊裝置進行擴容,然後從它來建立一個容器,但是新的容器不會有正确的大小。
同樣,如果你送出了一個很大的容器,最後生成的鏡像也不會很大(這是由 Docker 為鏡像準備檔案系統的方法造成的)。
這意味着如果一個容器真的超過了 10GB ,在不使用一些其他的小技巧的情況下,你沒法正确的把它送出為一個鏡像。
Docker 将來肯定會提供一些更好的方法來擴容容器,所需的代碼變動是很小的。管理一個精簡的池和對應的元資訊比較複雜(因為這個需要很多不同的操作流程,以及一個潛在的資料遷移。鑒于移除了所有的東西來構件新的池,也就沒有在本文提及),但是我們今天提到的一些解決方案相信已經對你有所幫助。
本文轉自 憬薇 51CTO部落格,原文連結:http://blog.51cto.com/welcomeweb/1921307