自從我們的kubernetes集群部署到生產(chǎn)環(huán)境后,將流量從原有的服務(wù)器上切過來之后,部分節(jié)點出現(xiàn)掛載目錄容量爆滿的情況。
運維的同事報給我們之后,我們首先想到的是節(jié)點鏡像過多,于是我們提供一個命令用于清理當(dāng)前節(jié)點上無用的、報錯的、鏡像和docker資源文件
docker system prune ?命令可以用于清理磁盤,刪除關(guān)閉的容器、無用的數(shù)據(jù)卷和網(wǎng)絡(luò),以及dangling鏡像(即無tag的鏡像)
docker system prune -a 命令清理得更加徹底,可以將沒有容器使用Docker鏡像都刪掉。
待運維執(zhí)行之后,目錄存儲資源釋放了一些,我們本以為這就告一段落了。然而,事與愿違,沒過多久,再次容量報警。。。
我們開始重視起來,開始檢視節(jié)點上工作的容器,發(fā)現(xiàn)在日志爆炸的節(jié)點上運行了定時任務(wù),開發(fā)人員將定時任務(wù)的日志輸出到控制臺,于是我們回到節(jié)點docker的工作目錄,通過du -sh *方式查看每個文件夾大小,發(fā)現(xiàn)docker目錄下containers目錄占用空間巨大,進去看原來是每個運行的容器存放日志的目錄,我們找出占用空間最大的日志目錄,發(fā)現(xiàn)容器日志特別的大
我們可使用如下命令查看各個日志的文件大小
ls -lh $(find /var/lib/docker/containers/ -name *-json.log)
那我們?nèi)绾吻謇砣罩灸?,如果docker容器正在運行,那么使用rm -rf 方式刪除日志后,通過df -h會發(fā)現(xiàn)磁盤空間并沒有釋放
原因:在Linux或者Unix系統(tǒng)中,通過rm或者文件管理器刪除文件將會從文件系統(tǒng)的目錄結(jié)構(gòu)上解除鏈接(unlink).然而如果文件是被打開的(有一個進程正在使用),那么進程將仍然可以讀取該文件,磁盤空間也一直被占用
我們通過cat /dev/null > *-json.log來清理相應(yīng)的日志,然后重啟
systemctl daemon-reload
systemctl restart docker
然而,我思考,不能每次滿的時候找運維清理日志啊,這多麻煩,難道docker沒有相應(yīng)的機制應(yīng)付輸出到控制臺的日志嗎?答案是:當(dāng)然不會
在新版的docker中我們可以通過設(shè)置vim /etc/docker/daemon.json 來限制docker的日志量
"log-driver":"json-file","log-opts":{ "max-size" :"200m","max-file":"5"}
顧名思義max-size就是每個日志文件大小,max-file是最多生成的文件數(shù),如上我設(shè)置成功后,每個容器運行的日志最多有五份每份200M大小,這樣就基本限制了容器的日志大小。
然后你覺得結(jié)束了嗎??并不?。?/p>
容器日志我們是限制完了,本以為高枕無憂,不用擔(dān)心出現(xiàn)日志爆滿的情況了,但是事與愿違,過幾天硬盤容量又滿了。。。
我們究其原因,發(fā)現(xiàn)在docker的運行目錄下overlay這個文件夾里存放著所有的容器掛載目錄,也就是容器的系統(tǒng)文件在這里放著,在容器中跑著的服務(wù)產(chǎn)生日志很可能并不是輸出到控制臺,而是保存到本地,容器內(nèi)的日志文件也是會占用磁盤空間的,這就讓我們犯愁了,這個不好限制開發(fā)團隊不存日志或者規(guī)定團隊存放目錄啊,對于一個成熟的容器平臺來說,海納百川那是必須的~
于是我們打起了kubelet的主意
在k8s中文社區(qū)中有詳細的限制方法?那具體做法呢,其實就是為節(jié)點加上驅(qū)逐策略,當(dāng)cpu或者內(nèi)存或者硬盤空間不滿足要求時,自動驅(qū)逐一些消耗資源大的容器,保證節(jié)點穩(wěn)定性。
里面主要是有以下幾個關(guān)鍵驅(qū)逐信號

上面的每個信號都支持整數(shù)值或者百分比。百分比的分母部分就是各個信號的總量。kubelet 支持兩種文件系統(tǒng)分區(qū)。
nodefs:保存 kubelet 的卷和守護進程日志等。
imagefs:在容器運行時,用于保存鏡像以及可寫入層。
imagefs 是可選的。Kubelet 能夠利用 cAdvisor 自動發(fā)現(xiàn)這些文件系統(tǒng)。Kubelet 不關(guān)注其他的文件系統(tǒng)。所有其他類型的配置,例如保存在獨立文件系統(tǒng)的卷和日志,都不被支持。
因為磁盤壓力已經(jīng)被驅(qū)逐策略接管,因此未來將會停止對現(xiàn)有 垃圾收集 方式的支持。
具體的內(nèi)容大家可以詳細去看看社區(qū)里的介紹,我這里就不再贅述了,我這邊獻上我的驅(qū)逐方案~
執(zhí)行vim /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
在里面插入
Environment="KUBELET_OTHER_ARGS=
--eviction-hard=memory.available<2Gi,nodefs.available<5Gi,imagefs.available<5Gi?
--eviction-minimum-reclaim=memory.available=500Mi,nodefs.available=5Gi,imagefs.available=5Gi?
--node-status-update-frequency=10s?
--eviction-pressure-transition-period=30s"
解讀:內(nèi)存小于2G驅(qū)逐,root目錄磁盤空間小于5G驅(qū)逐,鏡像目錄磁盤空間小于5G驅(qū)逐,節(jié)點檢測為每10秒一次,在跳出壓力狀態(tài)之前要等待的時間為30秒。
在某些場景下,驅(qū)逐 Pod 可能只回收了很少的資源。這就導(dǎo)致了 kubelet 反復(fù)觸發(fā)驅(qū)逐閾值。另外回收資源例如磁盤資源,是需要消耗時間的。
要緩和這種狀況,Kubelet 能夠?qū)γ糠N資源定義?minimum-reclaim。kubelet 一旦發(fā)現(xiàn)了資源壓力,就會試著回收至少?minimum-reclaim?的資源,使得資源消耗量回到期望范圍。
也就是說當(dāng)內(nèi)存觸發(fā)驅(qū)逐時,kubelet至少要讓內(nèi)存有2.5G,當(dāng)root和鏡像磁盤空間發(fā)生驅(qū)逐時,kubelet至少要讓磁盤有10G的空間。
那驅(qū)逐的規(guī)則是什么呢,對什么樣的容器做驅(qū)逐呢?這個我們下回分解哈。
那總的來說,若要解決節(jié)點鏡像存儲報警,我們可以從三個方面入手
1.容器:通過docker限制容器日志大小
2.k8s:通過kubelet來驅(qū)逐過大的容器
3.跟開發(fā)人員溝通,精簡容器,不讓內(nèi)存泄漏,不隨意使用資源(很難啦~~~)
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????祝各位新春快樂~