最近線上服務(wù)經(jīng)常出現(xiàn)一些奇奇怪怪的問題,比如網(wǎng)頁上的靜態(tài)資源加載不出來,或者請求后端莫名報錯,又或者 Redis 報錯…
當我 SSH 登錄到服務(wù)器上時,更不對勁了,敲個命令都卡頓…
如果是以前沒經(jīng)驗,或許會以為遇到了疑難雜癥,但作為多年的 Linux 用戶,我已經(jīng)知道了這種種異常的背后是「存儲空間已滿」在作祟!
那么問題就來到了「硬盤空間去哪兒了?」
先用 df 看個大概#
首先是最常用的命令
df -h
先來看看各個磁盤和掛載點的情況
在我的服務(wù)器上執(zhí)行這個命令之后發(fā)現(xiàn),根目錄的可用空間已經(jīng)只剩下幾百 KB 了…
再用 du 看具體#
使用 du 命令可以查看各個子目錄占用的空間,然后再結(jié)合 sort 命令排個序
sudo du -h --max-depth=1 / | sort -hr
參數(shù)說明:
- 因為要直接統(tǒng)計根目錄,所以需要有 root 權(quán)限
--max-depth=1 :僅顯示當前目錄及其下一級子目錄的占用情況。
sort -hr :按照大小進行降序排列。
查看目錄的總占用空間:
du -sh /
更好的工具#
前面的 du 命令,還是沒那么好用,主要是列出來的數(shù)據(jù)太多了。
這次我用上了 ncdu 工具
ncdu 是一個更加用戶友好的磁盤使用分析工具,支持交互式界面。
不過很多發(fā)行版沒有內(nèi)置,需要先安裝:
sudo apt install ncdu
使用 ncdu 分析根目錄占用#
sudo ncdu -x /
使用 -x 參數(shù)可以限制掃描范圍為當前文件系統(tǒng),不跨越掛載點。因為根目錄下有很多其他硬盤的掛載點,根據(jù)前面使用 df 命令的分析,是主硬盤滿了,所以我只要看主硬盤的就行。
ncdu 啟動之后會掃描各個文件的存儲空間,然后進入一個交互式界面,可以很直觀的看到各個目錄的占用空間大小,從大到小排序。
罪魁禍首#
在 ncdu 里可以很直觀看到 /var/lib/docker 這個目錄占用了 70% 以上的存儲空間,妥妥的答辯??!
使用 du 分析
sudo du -h --max-depth=1 /var/lib/docker | sort -hr
之后大概的占用情況是這樣(只是例子,不是真實數(shù)據(jù))
10G /var/lib/docker/overlay2
5G /var/lib/docker/volumes
1G /var/lib/docker/containers
500M /var/lib/docker/images
基本就是 docker 的鏡像、容器日志、卷之類的把硬盤吃掉了
清理 Docker 的未使用資源#
找到了問題,那就好辦了
首先把沒用的 docker 容器停掉
然后執(zhí)行一下 docker 提供的一些清理命令。
清理未使用的資源(鏡像、容器、卷和網(wǎng)絡(luò))#
Docker 提供了 docker system prune 命令,能清理未使用的資源。
docker system prune -a
-a :刪除所有未使用的鏡像(包括沒有關(guān)聯(lián)到容器的鏡像)。
- 注意:這個命令不會刪除被正在運行的容器依賴的資源,請小心操作。
僅清理未使用的卷#
如果是 /var/lib/docker/volumes 占用空間較多:
docker volume prune
僅清理未使用的網(wǎng)絡(luò)#
如果是 /var/lib/docker/network 占用較多:
docker network prune
刪除不需要的容器、鏡像和卷#
刪除未運行的容器#
docker container prune
刪除無用的鏡像#
docker image prune -a
刪除無用的卷#
docker volume prune
清理舊的鏡像和未使用的標簽#
如果在使用大量鏡像,很多舊版本可能已經(jīng)沒有用了。
列出鏡像按大小排序#
docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" | sort -k2 -h
刪除指定鏡像#
docker rmi <image-id>
啥玩意這么大?#
在分析存儲空間的占用過程中,我還發(fā)現(xiàn)有個文件特別離譜,下面這個文件,500多個G…
/var/lib/docker/containers/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df-json.log
找出拉屎的容器#
來看看是哪個容器拉的屎。
日志文件的路徑中包含了容器的 ID:e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df
來找一下是哪個容器:
docker ps | grep e4b5a99b429a
在容器列表中找不到該容器,可能它已經(jīng)被停止或刪除了。在這種情況下,可以使用 docker inspect 檢查具體信息:
docker inspect e4b5a99b429a
分析日志內(nèi)容#
可以通過 tail 或 less 查看日志內(nèi)容,檢查是否有異常輸出:
sudo tail -n 50 /var/lib/docker/containers/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df/e4b5a99b429a612885417460214ea40a6a49a3360c29180af800ff7aef4c03df-json.log
日志的具體內(nèi)容我就不貼了,看起來應(yīng)該沒啥問題,就是運行久了,日積月累…
處理這個問題的方法,見下一小節(jié)。
清理 docker 日志文件#
如果 /var/lib/docker/containers 占用大量空間,可能是容器日志文件過大。
查看日志文件#
每個容器的日志存儲在 /var/lib/docker/containers/<container-id>/<container-id>-json.log 。
使用以下命令找到最大的日志文件:
sudo find /var/lib/docker/containers/ -type f -name "*.log" -exec du -h {} + | sort -hr | head -n 10
手動清理日志#
清空一個特定容器的日志文件:
sudo truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log
設(shè)置日志文件大小限制#
在 Docker 的配置文件中限制日志大?。ㄍ扑]):
-
編輯 Docker 配置文件(通常是 /etc/docker/daemon.json ):
sudo nano /etc/docker/daemon.json
-
添加或修改以下配置:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
max-size :單個日志文件最大 10 MB。
max-file :保留 3 個日志文件。
-
重新加載 Docker:
sudo systemctl restart docker
遷移 /var/lib/docker 到新磁盤#
可以將 /var/lib/docker 掛載到其他磁盤,從而緩解當前磁盤的存儲壓力。這是一個常見的做法,尤其在有多塊磁盤的情況下。
方法一:直接遷移 /var/lib/docker 到新磁盤#
停止 Docker 服務(wù)#
在遷移數(shù)據(jù)之前,需要先停止 Docker 服務(wù):
sudo systemctl stop docker
移動 /var/lib/docker 到新位置#
假設(shè)新磁盤掛載在 /mnt/new-disk ,執(zhí)行以下命令:
sudo mv /var/lib/docker /mnt/new-disk/docker
創(chuàng)建軟鏈接#
將新的路徑鏈接回 /var/lib/docker ,讓 Docker 繼續(xù)按默認路徑工作:
sudo ln -s /mnt/new-disk/docker /var/lib/docker
啟動 Docker 服務(wù)#
sudo systemctl start docker
運行以下命令確保 Docker 正常工作:
docker info
方法二:修改 Docker 配置文件,指定新存儲位置#
停止 Docker 服務(wù)#
sudo systemctl stop docker
移動 /var/lib/docker 到新磁盤#
將現(xiàn)有數(shù)據(jù)遷移到新磁盤掛載點。例如,新磁盤掛載在 /mnt/new-disk :
sudo mv /var/lib/docker /mnt/new-disk/docker
修改 Docker 配置#
編輯 Docker 的配置文件(通常是 /etc/docker/daemon.json ),指定新的存儲路徑:
sudo nano /etc/docker/daemon.json
添加或修改以下內(nèi)容:
{
"data-root": "/mnt/new-disk/docker"
}
啟動 Docker 服務(wù)#
sudo systemctl start docker
再次檢查 Docker 是否正常運行:
docker info | grep "Docker Root Dir"
你應(yīng)該能看到新的路徑(如 /mnt/new-disk/docker )。
方法三:直接掛載新磁盤到 /var/lib/docker #
如果想直接將新磁盤作為 /var/lib/docker 的掛載點,可以使用以下方法
格式化新磁盤#
假設(shè)新磁盤為 /dev/sdb1 ,先格式化并創(chuàng)建文件系統(tǒng)(如 ext4 ):
sudo mkfs.ext4 /dev/sdb1
掛載新磁盤#
將新磁盤掛載到 /var/lib/docker :
sudo mount /dev/sdb1 /var/lib/docker
遷移現(xiàn)有數(shù)據(jù)#
如果 /var/lib/docker 目錄下已有數(shù)據(jù),需要先復(fù)制到新磁盤:
sudo rsync -a /var/lib/docker/ /mnt/new-disk/
然后再將新磁盤掛載回 /var/lib/docker 。
修改 /etc/fstab 確保開機自動掛載#
編輯 /etc/fstab 文件,添加一行掛載配置:
/dev/sdb1 /var/lib/docker ext4 defaults 0 2
注意事項#
-
數(shù)據(jù)遷移風(fēng)險:在遷移或重建 /var/lib/docker 時,務(wù)必備份重要數(shù)據(jù)(如持久卷數(shù)據(jù))。
-
權(quán)限問題:確保新目錄的權(quán)限與原始目錄一致:
sudo chown -R root:root /mnt/new-disk/docker
-
檢查掛載點:確保新磁盤掛載成功,并設(shè)置自動掛載,避免系統(tǒng)重啟后路徑丟失。
通過以上方法,可以成功將 /var/lib/docker 掛載到其他磁盤,緩解存儲壓力并優(yōu)化存儲布局。
重建 /var/lib/docker#
如果清理后空間仍然不足,可以重建 Docker 的存儲目錄(會刪除所有容器、鏡像和數(shù)據(jù))
停止 Docker 服務(wù):
sudo systemctl stop docker
備份現(xiàn)有 Docker 數(shù)據(jù)(可選):
sudo mv /var/lib/docker /var/lib/docker.bak
創(chuàng)建一個新的空目錄:
sudo mkdir /var/lib/docker
啟動 Docker 服務(wù):
sudo systemctl start docker
總結(jié)#
在這次 Linux 服務(wù)器硬盤空間消失問題的排查過程中,我經(jīng)歷了一次完整的存儲分析和優(yōu)化實戰(zhàn)。
關(guān)鍵步驟概括:#
- 初步排查存儲占用情況
- 使用
du 和 ncdu 等工具,快速定位占用空間較大的目錄。
- 發(fā)現(xiàn)
/var/lib/docker 目錄占用了大量存儲空間。
- 深入定位具體問題
- 找到具體的容器日志文件路徑,通過容器 ID 確認了是哪個容器產(chǎn)生了大量日志。
- 使用
docker inspect 和 docker logs ,進一步分析日志內(nèi)容。
- 解決問題
- 清空了過大的容器日志文件,通過
truncate 命令立即釋放空間。
- 修改 Docker 配置文件(
daemon.json )限制了日志文件的大小,避免類似問題再次發(fā)生。
- 驗證與優(yōu)化
- 重啟 Docker 服務(wù)后,驗證了服務(wù)正常運行。
- 使用
docker system prune 清理了無用資源,并規(guī)劃了日志管理策略。
個人收獲與思考:#
這次問題的解決讓我深刻體會到以下幾點:
- 系統(tǒng)監(jiān)控的重要性:及時監(jiān)控存儲使用情況,可以避免問題擴大化。
- 日志管理最佳實踐:過度增長的日志文件是常見的存儲占用原因,必須設(shè)置合理的日志大小限制。
- 工具的高效使用:
du 、ncdu 和 Docker 命令等工具在排查問題中大大提升了效率。
- 日常維護習(xí)慣:定期清理無用的容器資源(例如停止的容器、未使用的鏡像),可以保持系統(tǒng)健康運行。
這次實踐不僅解決了磁盤空間問題,也讓我對 Linux 系統(tǒng)管理和 Docker 的運維有了更深的理解。在未來的運維工作中,我將更加注重系統(tǒng)的監(jiān)控與優(yōu)化,提前預(yù)防類似問題的發(fā)生。
|