Docker 磁盤空間使用分析與清理 解決磁盤空間不足

用戶在使用 Docker 部署業務一段時間後,可能會發現宿主節點的磁盤容量持續增長,甚至將磁盤空間耗盡進而引發宿主機異常,進而對業務造成影響。 本文先對 Docker 的空間分析與清理進行說明,然後對容器的磁盤容量限制與使用建議做簡要說明。

典型問題場景

用戶發現 Docker 宿主機的磁盤空間使用率非常高。通過 du 逐層分析,發現是 Volume 或 overlay2 等目錄佔用了過高空間。示例如下:

# 根據使用的存儲驅動的不同,相應目錄會有所不同:
[root@node3 docker]# du -h --max-depth=1 |sort
104K	./network
13M	./image
20K	./plugins
24G	./overlay2   # 這個目錄佔用了非常高的磁盤磁盤空間
25G	.
283M	./volumes
4.0K	./swarm
4.0K	./tmp
4.0K	./trust
518M	./containers

空間使用分析

遇到此類問題,可以參閱如下步驟進行空間分析,定位佔用過高空間的業務來源。

分析 Docker 空間分佈

Docker 的內置 CLI 指令 docker system df,可用於查詢鏡像(Images)、容器(Containers)和本地卷(Local Volumes)等空間使用大戶的空間佔用情況。 示例輸出如下:

[root@node3 docker]# docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              17                  12                  2.713 GB            1.144 GB (42%)
Containers          15                  12                  10.75 GB            0 B (0%)
Local Volumes       8                   4                   282.9 MB            241.8 MB (85%)

查看空間佔用細節

可以進一步通過 -v參數查看空間佔用細節,以確定具體是哪個鏡像、容器或本地卷佔用了過高空間。示例輸出如下:

[root@node3 docker]# docker system df -v
# 鏡像的空間使用情況
Images space usage:

REPOSITORY                                                   TAG                 IMAGE ID            CREATED             SIZE                SHARED SIZE         UNIQUE SIZE         CONTAINERS
busybox                                                      latest              6ad733544a63        5 days ago          1.129 MB            0 B                 1.129 MB            1
nginx                                                        latest              b8efb18f159b        3 months ago        107.5 MB            107.5 MB            0 B                 4
ubuntu                                                       latest              14f60031763d        3 months ago        119.5 MB            0 B                 119.5 MB            0
alpine                                                       3.3                 606fed0878ec        4 months ago        4.809 MB            0 B                 4.809 MB            0
tutum/curl                                                   latest              01176385d84a        3 years ago         224.4 MB            0 B                 224.4 MB            1

# 容器的空間使用情況
Containers space usage:

CONTAINER ID        IMAGE                                                                    COMMAND                  LOCAL VOLUMES       SIZE                CREATED             STATUS                     NAMES
d1da451ceeab        busybox                                                                  "ping 127.0.0.1"         0                   10.7 GB             About an hour ago   Up About an hour           dstest
956ae1d241e8        nginx:latest                                                             "nginx -g 'daemon ..."   0                   26 B                3 months ago        Up 3 months                localTest_restserver_2
74973d237a06        nginx:latest                                                             "nginx -g 'daemon ..."   0                   2 B                 3 months ago        Up 3 months                

# 本地卷的空間使用情況
Local Volumes space usage:

VOLUME NAME                                                        LINKS               SIZE
83ba8747f4172a3c02a15f85b71e1565affca59f01352b4a94e0d28e65c26d1c   0                   830 B
a479c303b278f1442f66644f694a554aac630e72b7a27065a11ef85c4d87b648   0                   22.16 MB
79a25b6376e0d6587d8f4f24e08f9467981f04daad14bf3353a12d727d065503   1                   18.83 MB

空間清理

自動清理

可以通過 Docker 內置的 CLI 指令 docker system prune來進行自動空間清理。

** Tips **:

不同狀態的鏡像

  • 已使用鏡像(used image): 指所有已被容器(包括已停止的)關聯的鏡像。即 docker ps -a 看到的所有容器使用的鏡像。
  • 未引用鏡像(unreferenced image):沒有被分配或使用在容器中的鏡像,但它有 Tag 信息。
  • 懸空鏡像(dangling image):未配置任何 Tag (也就無法被引用)的鏡像,所以懸空。這通常是由於鏡像 build 的時候沒有指定 -t 參數配置 Tag 導致的。比如:
REPOSITORY                                                   TAG                 IMAGE ID            CREATED             SIZE
<none>                                                      <none>              6ad733544a63        5 days ago          1.13 MB   # 懸空鏡像(dangling image)

掛起的卷(dangling Volume)
類似的,dangling=true 的 Volume 表示沒有被任何容器引用的卷。

docker system prune 自動清理說明

  • 該指令默認會清除所有如下資源:
    • 已停止的容器(container)
    • 未被任何容器所使用的卷(volume)
    • 未被任何容器所關聯的網絡(network)
    • 所有懸空鏡像(image)。
  • 該指令默認只會清除懸空鏡像,未被使用的鏡像不會被刪除。
  • 添加 -a 或 --all參數後,可以一併清除所有未使用的鏡像和懸空鏡像。
  • 可以添加 -f 或 --force參數用以忽略相關告警確認信息。
  • 指令結尾處會顯示總計清理釋放的空間大小。

操作示例:

[root@node3 docker]# docker system prune --help

Usage:	docker system prune [OPTIONS]

Remove unused data

Options:
  -a, --all     Remove all unused images not just dangling ones
  -f, --force   Do not prompt for confirmation
      --help    Print usage
[root@node3 docker]# docker system prune -a
WARNING! This will remove:
	- all stopped containers
	- all volumes not used by at least one container
	- all networks not used by at least one container
	- all images without at least one container associated to them
Are you sure you want to continue? [y/N] y
Deleted Containers:
c09c31c49491ee7f2324160e43947917940221b4e6cc1274906def640a7a631f
2aa0180e1a0f4c2c64349a6ed969651052373e7a9471050dce9015701cf1b957
6d18003b06823c5d76d807a319387b06680fc93d0a32bc29c1cea4c07e8d515d

Deleted Volumes:
a479c303b278f1442f66644f694a554aac630e72b7a27065a11ef85c4d87b648
79a25b6376e0d6587d8f4f24e08f9467981f04daad14bf3353a12d727d065503

Deleted Images:
untagged: tutum/curl:latest
untagged: tutum/curl@sha256:b6f16e88387acd4e6326176b212b3dae63f5b2134e69560d0b0673cfb0fb976f
deleted: sha256:01176385d84aeb1d40ed18c6d3f952abf40d2d2b4aa98fcf0a8a4b01010fb9a9
deleted: sha256:c84f85637212412c1d46d1dd50f789df2c3b44678ee3fee6a820888e734f9b5a
untagged: test:lastest
deleted: sha256:794ff09332586a091514eb3d1c44990244e57e34adc71d4b4334c0674a1377e9
deleted: sha256:636a1e7769d2242556243e9a21fb96bb878ab5b94c41ff485667252c968b375e

Total reclaimed space: 1.565 GB

手工清理

網絡清理

網絡配置通常佔用的空間非常低,略過。

鏡像清理

如果通過 docker system df 分析,是鏡像佔用了過高空間。則可以根據業務情況,評估相關鏡像的使用情況。對於懸空和未使用的鏡像, 可以使用如下指令手工清理:

# 刪除所有懸空鏡像,但不會刪除未使用鏡像:
docker rmi $(docker images -f "dangling=true" -q)

# 刪除所有未使用鏡像和懸空鏡像。
# 【說明】:輪詢到還在被使用的鏡像時,會有類似"image is being used by xxx container"的告警信息,所以相關鏡像不會被刪除,忽略即可。
docker rmi $(docker images-q)

卷清理

如果通過 docker system df 分析,是卷佔用了過高空間。則可以根據業務情況,評估相關卷的使用情況。對於未被任何容器調用的卷(-v 結果信息中,“LINKS” 顯示爲 0),可以使用如下指令手工清理:

# 刪除所有未被任何容器關聯引用的卷:
docker volume rm $(docker volume ls -qf dangling=true)

# 也可以直接使用如下指令,刪除所有未被任何容器關聯引用的卷(但建議使用上面的方式)
# 【說明】輪詢到還在使用的卷時,會有類似"volume is in use"的告警信息,所以相關卷不會被刪除,忽略即可。
docker volume rm $(docker volume ls -q)

容器清理

如果通過 docker system df 分析,是某個容器佔用了過高空間。則可以根據業務情況,評估相關容器的業務歸屬並進行處理。對於已停止或其它異常狀態的容器,可以結合 -f 或 --filter篩選器,使用類似如下指令來手工清理:

# 刪除所有已退出的容器
docker rm -v $(docker ps -aq -f status=exited)
# 刪除所有狀態爲 dead 的容器
docker rm -v $(docker ps -aq -f status=dead)

更多關於 ps 指令支持的篩選器信息,可以參閱官方文檔

在用空間資源分析

對於還在使用的空間資源,可以參閱如下說明做進一步排查分析。

鏡像空間分析

如果某個鏡像佔用了過高空間,則可以通過如下方式做進一步空間分析:

  1. 通過 docker system df 獲取佔用過高空間的鏡像信息。
  2. 基於相應鏡像創建測試容器。
  3. exec 進入容器後,結合 du 等 shell 指令做進一步空間分析,定位出佔用最高空間的目錄或文件。
  4. 結合業務情況做進一步處理,重新 build 鏡像。

示例:

[root@node3]# docker exec -it dstest sh
/ # du -h | head
8.0K	./root
32.0K	./etc
4.0K	./usr/sbin
8.0K	./usr
10.0G	./home/java/logs
10.0G	./home/java
10.0G	./home
1.1M	./bin
0	./dev/shm
0	./dev/mqueue

容器空間分析

如果某個運行中的容器佔用了過高空間,則可以通過如下方式做進一步空間分析:

Tips

容器的只讀層與鏡像層的空間佔用情況
一個容器的佔用的總空間,包含其最頂層的讀寫層(writable layer)和底部的只讀鏡像層(base image layer,read-only)。更多相關說明,可以參閱官方文檔
可以通過 docker ps 的 -s參數來分別顯示二者的空間佔用情況,進而判斷相應容器的空間佔用主要是來自原始鏡像,還是運行中產生。
容器空間佔用示意圖
示例:

# 如下容器的原始鏡像佔用了 422MB 空間,實際運行過程中只佔用了 2B 空間:
CONTAINER ID        IMAGE                                                                                                                                COMMAND                  CREATED             STATUS              PORTS                                           NAMES                                                                                    SIZE
ac39128ccbc0        registry.aliyuncs.com/acs-sample/wordpress:4.6                                                                                       "/entrypoint.sh ap..."   3 months ago        Up 11 days          0.0.0.0:32779->80/tcp                           Web_web_4                                                                                2 B (virtual 422 MB)

容器空間佔用的分析步驟:

  1. 通過 docker system df 獲取佔用過高空間的容器信息。
  2. 通過前述 -s參數確認到底是底層鏡像,還是運行過程中產生的數據佔用了過高空間。
  3. exec 進入容器,結合 du 等 shell 指令做進一步空間分析,定位出佔用最高空間的目錄或文件。
  4. 結合業務情況做進一步處理。

引申:Docker 磁盤空間限制與使用建議

磁盤空間限制

使用 Device Mapper 存儲驅動限制容器磁盤空間

如果使用 Device Mapper 作爲底層存儲驅動,則可以通過 Docker daemon 的如下參數來全侷限制單個容器佔用空間的大小:

  • --storage-opt dm.basesize=20G表示限制單個容器最多佔用 20G 空間,將應用於任何新建容器。

更多關於 Device Mapper 存儲驅動的說明,可以參閱官方文檔

使用 btrfs 存儲驅動限制容器磁盤空間

btrfs 驅動主要使用 btrfs 所提供的 subvolume 功能來實現。一個容器會對應一個 subvolume。針對容器對應的 subvolume 啓用並配置 quota 即可限制其磁盤空間。示例配置:

btrfs qgroup limit -e 50G /var/lib/docker/btrfs/subvolumes/<CONTAINER_ID>

btrfs 還有其它很好的特性,比如可以在線擴容(在線加入一塊新的塊設備,來擴充整個文件系統的大小)。更多關於 btrfs 存儲驅動的說明,可以參閱官方文檔

外掛 LVM 卷

如果使用的是其它不支持對單個容器的磁盤容量進行限制的存儲驅動,則可以考慮如下通用方案:

  • 通過 LVM 方式創建一個指定容量的卷,然後掛載到宿主操作系統上特定目錄。最後通過 --volume 參數來讓容器來掛載使用相應目錄。

注意:該方案的前提條件是,容器中所有落盤操作要全部落到上述 “–volume” 參數指定的卷中,否則容器還會佔用默認 aufs 所在盤的空間,進而造成統計不準。

Docker 存儲使用建議

細化的存儲使用最佳實踐與採用的存儲驅動(storage driver)類型強相關,您可以參閱官方文檔做相關了解,本文不做進一步細化說明。
通用的存儲使用建議如下:

  • 容器內的業務日誌務必配置輪詢覆寫,或者使用日誌驅動將日誌輸出到外部存儲。避免日誌文件持續增長,佔用過高磁盤空間。
  • 結合外部監控對宿主機的磁盤空間使用情況進行監控和告警。
  • 可以參閱文檔 如何給容器服務的Docker增加數據盤來擴容默認 Docker 存儲空間。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章