摘要:用了 Docker,好處挺多的,但是有一個(gè)不大不小的問(wèn)題,它會(huì)一不小心占用太多磁盤(pán),這就意味著我們必須及時(shí)清理。
好處:
- 所有服務(wù)器的配置都非常簡(jiǎn)單,只安裝了 Docker,這樣新增服務(wù)器的時(shí)候要簡(jiǎn)單很多。
- 可以非常方便地在服務(wù)器之間移動(dòng)各種服務(wù),下載 Docker 鏡像就可以運(yùn)行,不需要手動(dòng)配置運(yùn)行環(huán)境。
- 開(kāi)發(fā)/測(cè)試環(huán)境與生產(chǎn)環(huán)境嚴(yán)格一致,不用擔(dān)心由于環(huán)境問(wèn)題導(dǎo)致部署失敗。
至少,上線這一年多來(lái),Docker 一直非常穩(wěn)定,沒(méi)有出什么問(wèn)題。但是,它有一個(gè)不大不小的問(wèn)題,會(huì)比較消耗磁盤(pán)空間。
如果 Docker 一不小心把磁盤(pán)空間全占滿(mǎn)了,你的服務(wù)也就算玩完了,因此所有 Docker 用戶(hù)都需要對(duì)此保持警惕。當(dāng)然,大家也不要緊張,這個(gè)問(wèn)題還是挺好解決的。
1. docker system 命令
在誰(shuí)用光了磁盤(pán)?Docker System 命令詳解中,我們?cè)敿?xì)介紹了docker system命令,它可以用于管理磁盤(pán)空間。
docker system df命令,類(lèi)似于 Linux 上的df命令,用于查看 Docker 的磁盤(pán)使用情況:
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 147 36 7.204GB 3.887GB (53%)
Containers 37 10 104.8MB 102.6MB (97%)
Local Volumes 3 3 1.421GB 0B (0%)
Build Cache 0B 0B
可知,Docker 鏡像占用了7.2GB磁盤(pán),Docker 容器占用了104.8MB磁盤(pán),Docker 數(shù)據(jù)卷占用了1.4GB磁盤(pán)。
docker system prune命令可以用于清理磁盤(pán),刪除關(guān)閉的容器、無(wú)用的數(shù)據(jù)卷和網(wǎng)絡(luò),以及 dangling 鏡像(即無(wú) tag 的鏡像)。docker system prune -a命令清理得更加徹底,可以將沒(méi)有容器使用 Docker 鏡像都刪掉。注意,這兩個(gè)命令會(huì)把你暫時(shí)關(guān)閉的容器,以及暫時(shí)沒(méi)有用到的 Docker 鏡像都刪掉了...所以使用之前一定要想清楚吶。
執(zhí)行docker system prune -a命令之后,Docker 占用的磁盤(pán)空間減少了很多:
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 10 10 2.271GB 630.7MB (27%)
Containers 10 10 2.211MB 0B (0%)
Local Volumes 3 3 1.421GB 0B (0%)
Build Cache 0B 0B
2. 手動(dòng)清理 Docker 鏡像/容器/數(shù)據(jù)卷
對(duì)于舊版的 Docker(版本 1.13 之前),是沒(méi)有 docker system 命令的,因此需要進(jìn)行手動(dòng)清理。這里給出幾個(gè)常用的命
刪除所有關(guān)閉的容器
docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs docker rm
刪除所有 dangling 鏡像(即無(wú) tag 的鏡像):
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
刪除所有 dangling 數(shù)據(jù)卷(即無(wú)用的 volume):
docker volume rm $(docker volume ls -qf dangling=true)
Fundebug提供實(shí)時(shí)、專(zhuān)業(yè)的錯(cuò)誤監(jiān)控服務(wù),為您的線上代碼保駕護(hù)航,歡迎大家免費(fèi)使用!
3. 限制容器的日志大小
有一次,當(dāng)我使用 1 與 2 提到的方法清理磁盤(pán)之后,發(fā)現(xiàn)并沒(méi)有什么作用,于是,我進(jìn)行了一系列分析。
在 Ubuntu 上,Docker 的所有相關(guān)文件,包括鏡像、容器等都保存在/var/lib/docker/目錄中:
du -hs /var/lib/docker/
97G /var/lib/docker/
Docker 竟然使用了將近100GB磁盤(pán),這也是夠了。使用du命令繼續(xù)查看,可以定位到真正占用這么多磁盤(pán)的目錄:
92G /var/lib/docker/containers/a376aa694b22ee497f6fc9f7d15d943de91c853284f8f105ff5ad6c7ddae7a53
由docker ps可知,nginx 容器的 ID 恰好為a376aa694b22,與上面的目錄/var/lib/docker/containers/a376aa694b22的前綴一致:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a376aa694b22 192.168.59.224:5000/nginx:1.12.1 "nginx -g 'daemon off" 9 weeks ago Up 10 minutes nginx
因此,nginx 容器竟然占用了92GB的磁盤(pán)。進(jìn)一步分析可知,真正占用磁盤(pán)空間的是 nginx 的日志文件。那么這就不難理解了。我們Fundebug每天的數(shù)據(jù)請(qǐng)求為百萬(wàn)級(jí)別,那么日志數(shù)據(jù)自然非常大。
使用truncate命令,可以將 nginx 容器的日志文件“清零”:
truncate -s 0 /var/lib/docker/containers/a376aa694b22ee497f6fc9f7d15d943de91c853284f8f105ff5ad6c7ddae7a53/*-json.log
當(dāng)然,這個(gè)命令只是臨時(shí)有作用,日志文件遲早又會(huì)漲回來(lái)。要從根本上解決問(wèn)題,需要限制 nginx 容器的日志文件大小。這個(gè)可以通過(guò)配置日志的max-size來(lái)實(shí)現(xiàn),下面是 nginx 容器的 docker-compose 配置文件:
nginx:
image: nginx:1.12.1
restart: always
logging:
driver: "json-file"
options:
max-size: "5g"
重啟 nginx 容器之后,其日志文件的大小就被限制在5GB,再也不用擔(dān)心了~
4. 重啟 Docker
還有一次,當(dāng)我清理了鏡像、容器以及數(shù)據(jù)卷之后,發(fā)現(xiàn)磁盤(pán)空間并沒(méi)有減少。根據(jù)Docker disk usage提到過(guò)的建議,我重啟了 Docker,發(fā)現(xiàn)磁盤(pán)使用率從 83%降到了 19%。根據(jù)高手指點(diǎn),這應(yīng)該是與內(nèi)核 3.13 相關(guān)的 BUG,導(dǎo)致 Docker 無(wú)法清理一些無(wú)用目錄:
it's quite likely that for some reason when those container shutdown, docker couldn't remove the directory because the shm device was busy. This tends to happen often on 3.13 kernel. You may want to update it to the 4.4 version supported on trusty 14.04.5 LTS.
The reason it disappeared after a restart, is that daemon probably tried and succeeded to clean up left over data from stopped containers.
我查看了一下內(nèi)核版本,發(fā)現(xiàn)真的是 3.13:
uname -r
3.13.0-86-generic
如果你的內(nèi)核版本也是 3.13,而且清理磁盤(pán)沒(méi)能成功,不妨重啟一下 Docker。當(dāng)然,這個(gè)晚上操作比較靠譜。