CentOS系統故障 | 一樁"血案"引發的容器儲存驅動比較

有容雲發表於2016-08-04

寫在前面: 由於紅帽在Linux界的影響力,相信很多朋友在測試和生產系統用的是RedHat或者CentOS系統,這次我在CentOS系統上遇到了一個很有意思的故障,通過這次故障的原因分析及解決,特意寫了這篇文章分享給大家。

我們在CentOS上部署了一套Docker系統,執行了一段時間後,突然發現所有容器執行異常,同時宿主機核心報磁碟I/O錯誤: enter image description here

看到問題的第一反映是檢視磁碟狀態和空間使用情況,發現系統的根目錄已經用完: enter image description here

我們知道,Docker預設的儲存目錄是在/var/lib/docker/下,同時我們也知道,可以通過使用-g, --graph=”/var/lib/docker” 引數修改Docker 預設存放路徑。知道了問題後,我們可以通過掛載一個大硬碟到系統,並將Docker的目錄更改為新掛載到硬碟上: enter image description here

我將Docker的儲存目錄設定到剛才新增加的/data目錄下,但是原來的映象和容器都找不到了,因為路徑改了。原來的映象是在/var/lib/docker/devicemapper/devicemapper/{data,metadata},轉移檔案後繼續執行Docker服務,這樣我們就有了一個300G的大房子給Docker們用了。

大家以為事情到了這裡就完結了麼?其實我也想,但是我順便折騰了一下,於是又發生了接下來的事情。說我手賤也好,瞎折騰也罷,匯入一堆容器映象和執行一堆容器後,系統又光榮告訴我所有的容器根目錄全部變成了只讀,宿主機核心同樣報磁碟I/O錯誤,一開始我以為data目錄又被寫滿了,但是用df –Th命令檢視後,發現目錄還有很多空間: enter image description here

但是殘酷的現實是,只用了不到一半的空間後,所有的容器就全部出現異常了,這是我祭出了經典三板斧:重啟容器,重啟Docker服務,重啟伺服器。然並卵,容器還是執行異常。通過在網上爬了一堆資料,在http://jpetazzo.github.io/2014/01/29/docker-device-mapper-resize/上查到,CentOS預設用的是Device Mapper作為容器的儲存驅動的,大家可以用dockers info命令檢視,Docker服務啟動時預設會在/var/lib/docker/devicemapper/devicemapper/目錄建立一個100G(由於1000和1024換算的關係,系統實際顯示的是107.4G,其他數字亦同)的data檔案,然後啟動的容器的所有變更的資料全部儲存到這個data檔案中;也就是說當容器內產生的相關data資料超過100G後容器就再也沒有多餘的空間可用,從而導致所有容器的根目錄變為只讀!同時它會限制每個容器最大為 10GB。太坑爹了有木有,給了大房子只能用100G! enter image description here

為了找到根本原因,我們需要了解Device Mapper儲存驅動的原理: Device Mapper儲存驅動是以精簡配置的方式執行的,它實際上是目標塊裝置的快照。 Docker啟動時會設定一個100G的sparse檔案( /var/lib/docker/devicemapper/devicemapper/data,後設資料為/var/lib/docker/devicemapper/devicemapper/metadata ),並將其作為Device Mapper的儲存池,而所有容器都從該儲存池中分配預設10G的儲存空間使用,如下圖所示: enter image description here

當有實際讀寫後,這些儲存塊將在儲存池中被標記為已使用(或者從池中拿走)。當實際讀寫的塊容量大於池的容量時,容器的執行空間不足,所以報I/O錯誤。

Device Mapper儲存驅動非常方便,你不需要做任何安裝部署便可以使用:如建立額外的分割槽來儲存 Docker 容器,或者建立LVM。然而它也有兩個缺點: • 儲存池會有一個預設 100GB 的容量,滿足不了大儲存的需求。 • 它將會被稀疏檔案所支援(精簡配置,一開始基本不佔用空間,只有當實際需要寫的時候才會使用磁碟的儲存塊)但效能較差。

針對這些問題,有兩個解決方案: 1. 使用更大的檔案/磁碟/邏輯卷建立data檔案: enter image description here

  1. 通過Docker啟動引數的--storage-opt選項來限制每個容器初始化的磁碟大小,如-storage-opt dm.basesize=80G 這樣每個容器啟動後,根目錄的總空間就是80G。

但是我總覺得這樣的解決方式不夠優雅,需要多步操作才能滿足需求,同時,容器的空間還是被限制的,只是限制的大小變化而已。那有沒有更好的辦法呢? 讓我們繼續來爬資料,在Docker的官方網站上: (https://docs.docker.com/engine/reference/commandline/dockerd/)

![enter code here][10]

Docker在儲存驅動方面支援 AUFS、Device Mapper、Btrfs、ZFS、 Overlay 、Overlay2等多址方式,現由於AUFS並未併入核心,目前只有Ubuntu系統上能夠使用aufs作為docker的儲存引擎,而在CentOS系統上預設使用Device Mapper,但是幸運的是,在Linux核心3.18.0以上的版本,是可以原生支援Overlay驅動方式的,Overlayfs跟AUFS很像,但是效能比AUFS好,有更好的記憶體利用。

Docker通過-s引數選擇儲存驅動, 通過-s=overlay,我們將儲存驅動器設定為Overlay方式,再重啟Docker應用。 enter image description here

大家可以看到,現在Docker已經是使用了OverlayFS(這裡大家要注意,如果系統有儲存的映象和執行的容器,更改儲存驅動後將都不可用,請先行備份)。

通過修改為OverlayFS,Device Mapper的儲存池容量限制及單個容器執行最大空間限制統統沒有了,同時Overlay的讀寫效能也好於Device Mapper,只需通過-s=overlay一個引數即可優雅的使用更好的檔案系統來執行容器。

至此,容器執行時I/O錯誤的原因已經完美解決,希望這篇文章能幫到在使用過程中遇到相同問題的朋友。

溫馨提示: Docker Live時代●Online Meetup-第二期《容器安全問題及解決之道》開始報名啦! enter image description here

容器使用愈加廣泛,當前國內外容器安全現狀如何?對於在生產環境中的容器使用需要注意到哪些安全問題?針對這些問題又該如何避免和解決?答案盡在8月17日,Docker Live時代●Online Meetup-第二期《容器安全問題及解決之道》;有容雲首席架構師馬洪喜攜手美女總監雷偉為您揭曉!

活動詳情請點選:《Docker Live時代 | Online Meetup第二期-容器安全問題及解決之道》 活動報名請戳我:http://www.youruncloud.com/videos/meetup.html#start

相關文章