由于紅帽在Linux界的影響力,相信很多朋友在測(cè)試和生產(chǎn)系統(tǒng)用的是RedHat或者CentOS系統(tǒng),這次我在CentOS系統(tǒng)上遇到了一個(gè)很有意思的故障,通過這次故障的原因分析及解決,特意寫了這篇文章分享給大家。
我們?cè)贑entOS上部署了一套Docker系統(tǒng),運(yùn)行了一段時(shí)間后,突然發(fā)現(xiàn)所有容器運(yùn)行異常,同時(shí)宿主機(jī)內(nèi)核報(bào)磁盤I/O錯(cuò)誤:

看到問題的第一反映是查看磁盤狀態(tài)和空間使用情況,發(fā)現(xiàn)系統(tǒng)的根目錄已經(jīng)用完:

我們知道,Docker默認(rèn)的存儲(chǔ)目錄是在/var/lib/docker/下,同時(shí)我們也知道,可以通過使用-g, --graph=”/var/lib/docker” 參數(shù)修改Docker 默認(rèn)存放路徑。知道了問題后,我們可以通過掛載一個(gè)大硬盤到系統(tǒng),并將Docker的目錄更改為新掛載到硬盤上:

我將Docker的存儲(chǔ)目錄設(shè)置到剛才新增加的/data目錄下,但是原來的鏡像和容器都找不到了,因?yàn)槁窂礁牧?。原來的鏡像是在/var/lib/docker/devicemapper/devicemapper/{data,metadata},轉(zhuǎn)移文件后繼續(xù)運(yùn)行Docker服務(wù),這樣我們就有了一個(gè)300G的大房子給Docker們用了。
大家以為事情到了這里就完結(jié)了么?其實(shí)我也想,但是我順便折騰了一下,于是又發(fā)生了接下來的事情。說我手賤也好,瞎折騰也罷,導(dǎo)入一堆容器鏡像和運(yùn)行一堆容器后,系統(tǒng)又光榮告訴我所有的容器根目錄全部變成了只讀,宿主機(jī)內(nèi)核同樣報(bào)磁盤I/O錯(cuò)誤,一開始我以為data目錄又被寫滿了,但是用df –Th命令查看后,發(fā)現(xiàn)目錄還有很多空間:

但是殘酷的現(xiàn)實(shí)是,只用了不到一半的空間后,所有的容器就全部出現(xiàn)異常了,這是我祭出了經(jīng)典三板斧:重啟容器,重啟Docker服務(wù),重啟服務(wù)器。然并卵,容器還是運(yùn)行異常。通過在網(wǎng)上爬了一堆資料,在http://jpetazzo.github.io/2014/01/29/docker-device-mapper-resize/上查到,CentOS默認(rèn)用的是Device Mapper作為容器的存儲(chǔ)驅(qū)動(dòng)的,大家可以用dockers info命令查看,Docker服務(wù)啟動(dòng)時(shí)默認(rèn)會(huì)在/var/lib/docker/devicemapper/devicemapper/目錄創(chuàng)建一個(gè)100G(由于1000和1024換算的關(guān)系,系統(tǒng)實(shí)際顯示的是107.4G,其他數(shù)字亦同)的data文件,然后啟動(dòng)的容器的所有變更的數(shù)據(jù)全部保存到這個(gè)data文件中;也就是說當(dāng)容器內(nèi)產(chǎn)生的相關(guān)data數(shù)據(jù)超過100G后容器就再也沒有多余的空間可用,從而導(dǎo)致所有容器的根目錄變?yōu)橹蛔x!同時(shí)它會(huì)限制每個(gè)容器最大為 10GB。太坑爹了有木有,給了大房子只能用100G!

為了找到根本原因,我們需要了解Device Mapper存儲(chǔ)驅(qū)動(dòng)的原理: Device Mapper存儲(chǔ)驅(qū)動(dòng)是以精簡(jiǎn)配置的方式運(yùn)行的,它實(shí)際上是目標(biāo)塊設(shè)備的快照。
Docker啟動(dòng)時(shí)會(huì)設(shè)置一個(gè)100G的sparse文件( /var/lib/docker/devicemapper/devicemapper/data,元數(shù)據(jù)為/var/lib/docker/devicemapper/devicemapper/metadata ),并將其作為Device Mapper的存儲(chǔ)池,而所有容器都從該存儲(chǔ)池中分配默認(rèn)10G的存儲(chǔ)空間使用,如下圖所示:

當(dāng)有實(shí)際讀寫后,這些存儲(chǔ)塊將在存儲(chǔ)池中被標(biāo)記為已使用(或者從池中拿走)。當(dāng)實(shí)際讀寫的塊容量大于池的容量時(shí),容器的運(yùn)行空間不足,所以報(bào)I/O錯(cuò)誤。
Device Mapper存儲(chǔ)驅(qū)動(dòng)非常方便,你不需要做任何安裝部署便可以使用:如創(chuàng)建額外的分區(qū)來存儲(chǔ) Docker 容器,或者建立LVM。然而它也有兩個(gè)缺點(diǎn):
• 存儲(chǔ)池會(huì)有一個(gè)默認(rèn) 100GB 的容量,滿足不了大存儲(chǔ)的需求。
• 它將會(huì)被稀疏文件所支持(精簡(jiǎn)配置,一開始基本不占用空間,只有當(dāng)實(shí)際需要寫的時(shí)候才會(huì)使用磁盤的存儲(chǔ)塊)但性能較差。
針對(duì)這些問題,有兩個(gè)解決方案:
1. 使用更大的文件/磁盤/邏輯卷創(chuàng)建data文件: