摘要:用了 Docker,好處挺多的,但是有一個不大不小的問題,它會一不小心占用太多磁盤,這就意味着我們必須及時清理。
作為一個有信仰的技術公司,我們Fundebug的后台采用了酷炫的全 Docker 化架構,所有服務,包括數據庫都運行在 Docker 里面。這樣做當然不是為了炫技,看得清楚的好處還是不少的:
- 所有服務器的配置都非常簡單,只安裝了 Docker,這樣新增服務器的時候要簡單很多。
- 可以非常方便地在服務器之間移動各種服務,下載 Docker 鏡像就可以運行,不需要手動配置運行環境。
- 開發/測試環境與生產環境嚴格一致,不用擔心由於環境問題導致部署失敗。
至少,上線這一年多來,Docker 一直非常穩定,沒有出什么問題。但是,它有一個不大不小的問題,會比較消耗磁盤空間。
如果 Docker 一不小心把磁盤空間全占滿了,你的服務也就算玩完了,因此所有 Docker 用戶都需要對此保持警惕。當然,大家也不要緊張,這個問題還是挺好解決的。
1. docker system 命令
在誰用光了磁盤?Docker System 命令詳解中,我們詳細介紹了docker system命令,它可以用於管理磁盤空間。
docker system df命令,類似於 Linux 上的df命令,用於查看 Docker 的磁盤使用情況:
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磁盤,Docker 容器占用了104.8MB磁盤,Docker 數據卷占用了1.4GB磁盤。
docker system prune命令可以用於清理磁盤,刪除關閉的容器、無用的數據卷和網絡,以及 dangling 鏡像(即無 tag 的鏡像)。docker system prune -a命令清理得更加徹底,可以將沒有容器使用 Docker 鏡像都刪掉。注意,這兩個命令會把你暫時關閉的容器,以及暫時沒有用到的 Docker 鏡像都刪掉了...所以使用之前一定要想清楚吶。
執行docker system prune -a命令之后,Docker 占用的磁盤空間減少了很多:
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. 手動清理 Docker 鏡像/容器/數據卷
對於舊版的 Docker(版本 1.13 之前),是沒有 docker system 命令的,因此需要進行手動清理。這里給出幾個常用的命
刪除所有關閉的容器
docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs docker rm
刪除所有 dangling 鏡像(即無 tag 的鏡像):
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
刪除所有 dangling 數據卷(即無用的 volume):
docker volume rm $(docker volume ls -qf dangling=true)
Fundebug提供實時、專業的錯誤監控服務,為您的線上代碼保駕護航,歡迎大家免費使用!
3. 限制容器的日志大小
有一次,當我使用 1 與 2 提到的方法清理磁盤之后,發現並沒有什么作用,於是,我進行了一系列分析。
在 Ubuntu 上,Docker 的所有相關文件,包括鏡像、容器等都保存在/var/lib/docker/目錄中:
du -hs /var/lib/docker/
97G /var/lib/docker/
Docker 竟然使用了將近100GB磁盤,這也是夠了。使用du命令繼續查看,可以定位到真正占用這么多磁盤的目錄:
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的磁盤。進一步分析可知,真正占用磁盤空間的是 nginx 的日志文件。那么這就不難理解了。我們Fundebug每天的數據請求為百萬級別,那么日志數據自然非常大。
使用truncate命令,可以將 nginx 容器的日志文件“清零”:
truncate -s 0 /var/lib/docker/containers/a376aa694b22ee497f6fc9f7d15d943de91c853284f8f105ff5ad6c7ddae7a53/*-json.log
當然,這個命令只是臨時有作用,日志文件遲早又會漲回來。要從根本上解決問題,需要限制 nginx 容器的日志文件大小。這個可以通過配置日志的max-size來實現,下面是 nginx 容器的 docker-compose 配置文件:
nginx:
image: nginx:1.12.1
restart: always
logging:
driver: "json-file"
options:
max-size: "5g"
重啟 nginx 容器之后,其日志文件的大小就被限制在5GB,再也不用擔心了~
4. 重啟 Docker
還有一次,當我清理了鏡像、容器以及數據卷之后,發現磁盤空間並沒有減少。根據Docker disk usage提到過的建議,我重啟了 Docker,發現磁盤使用率從 83%降到了 19%。根據高手指點,這應該是與內核 3.13 相關的 BUG,導致 Docker 無法清理一些無用目錄:
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.
我查看了一下內核版本,發現真的是 3.13:
uname -r
3.13.0-86-generic
如果你的內核版本也是 3.13,而且清理磁盤沒能成功,不妨重啟一下 Docker。當然,這個晚上操作比較靠譜。
參考
- 誰用光了磁盤?Docker System 命令詳解
- INTRODUCING DOCKER 1.13
- Docker 文檔:docker system
- Docker 文檔:json-file
- Docker disk usage
關於Fundebug
Fundebug專注於JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟件、百姓網等眾多品牌企業。歡迎大家免費試用!
版權聲明
轉載時請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/01/10/how-to-clean-docker-disk/