通过docker重新发布一个线上jar包时,报错如下:

failed to copy files: failed to copy file: Error processing tar file(exit status 1): write /xx.jar: no space left on device
Unable to find image 'xx:latest' locally
docker: Error response from daemon: pull access denied for xx, repository does not exist or may require 'docker login': denied: requested access to the resource is denied.
See 'docker run --help'.

给出提示是 :设备上没有剩余空间,docker加载镜像空间不足。

Docker一个不大不小的问题,会比较消耗磁盘空间。如果Docker一不小心把磁盘空间全占满了,服务也就宕掉了。

1、Docker System命令

docker默认存放镜像地址为 /var/lib/docker

在进行资源清理之前我们有必要搞清楚 docker 都占用了哪些系统的资源。这需要综合使用不同的命令来完成

通过 sudo docker info  命令查看(显示系统级别的信息,比如容器和镜像的数量等)

sudo docker info:显示系统级别的信息,比如容器和镜像的数量等。

docker container ls:默认只列出正在运行的容器,-a 选项会列出包括停止的所有容器。

docker image ls:列出镜像信息,-a 选项会列出 intermediate 镜像(就是其它镜像依赖的层)。

docker volume ls:列出数据卷。

docker network ls:列出 network。

还可借助如下命令查看磁盘使用情况

df -h                查看磁盘使用情况(服务器内存大小)
df -i                 查看inode使用情况

du -sh *   查看当前目录下各个文件及目录占用空间大小

df -h 查看磁盘使用情况(服务器内存大小)

df -i 查看inode使用情况

df -h /var/lib/docker 命令 查看 docker中剩余空间,发现使用 了 100%

df -h /var/lib/docker

我们也可以参考文章《谁用光了磁盘?Docker System命令详解》,文中详细介绍了Docker System命令,它可以用于管理磁盘空间。

docker system df 命令,类似于Linux上的df命令,用于查看Docker的磁盘使用情况:

docker system df

该命令列出了 docker 使用磁盘的 4 种类型 

  • Images: 所有镜像占用的空间,包括拉取的镜像、本地构建的镜像

  • Containers: 运行中的容器所占用的空间(没运行就不占空间),其实就是每个容器读写层的空间

  • Local Volumes: 本地数据卷的空间

  • Build Cache: 镜像构建过程中,产生的缓存数据

最后一列RECLAIMABLE,是指可清理的 

从上图看出,Docker镜像占用了1.793GB磁盘,Docker容器占用了2.088GB磁盘,Docker数据卷Local Volumes占用了0B磁盘

docker system df -v 命令可以进一步查看单个image镜像、container容器空间占用细节,以确定是哪个镜像、容器或本地卷占用过高空间

docker system df -v

  

解决方案:

docker system prune 命令可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及dangling镜像(即无tag的镜像)

docker system prune -a 命令清理得更加彻底,可以将没有容器使用Docker镜像都删掉。注意,这两个命令会把你暂时关闭的容器,以及暂时没有用到的Docker镜像都删掉了……所以使用之前一定要想清楚

#docker system prune 命令可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及dangling镜像(即无tag的镜像)
docker system prune 

已停止的容器(container)
未被任何容器所使用的卷(volume)
未被任何容器所关联的网络(network)
所有悬空镜像(image)

#docker system prune -a 命令清理得更加彻底,可以将没有容器使用Docker镜像都删掉
docker system prune -a

执行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

或者 通过  df -h /var/lib/docker 命令 查看 docker中剩余空间,发现只使用了 10%

 


2、/var/lib/docker/overlay2 磁盘爆满

[root@xx xx-core]# df -h
Filesystem                                   Size  Used Avail Use% Mounted on
devtmpfs                                      16G     0   16G   0% /dev
tmpfs                                         16G   16K   16G   1% /dev/shm
tmpfs                                         16G  1.6G   15G  11% /run
tmpfs                                         16G     0   16G   0% /sys/fs/cgroup
/dev/mapper/centos_temp--mini--centos7-root   92G   92G   20K 100% /
/dev/sda1                                   1014M  182M  833M  18% /boot
tmpfs                                        3.2G     0  3.2G   0% /run/user/0
/dev/mapper/vggroup-lv_data                  2.0T   80G  2.0T   4% /data
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/7bab26bb2bb4634174aed26787be242a917ca7db8e26081866ca863a4b891111/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/05bc176d2823f6e0c4258649ca749438eaa29e7be5c7ac19c50bd64a9fbcb9e3/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/81dc3e155397c16fc961eef7dcd99ebfd37a96d9b81e4be0636ed0ade8f9a67a/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/f61ae4177cae509eb3886b1e225951d376c0dffe446d43b1d8ce0d6eeb965ab4/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/115c4531e8eccc2ca6bbc4e84090a361b2458d28c07b5da2e4a46eeb66e425c7/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/43883c34f85a329a0eca43e5c1c18fe5f4285ab5c8a70af1a9674fa4e2bd6dc8/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/6b7de766ac8c18097313329c449771e3f3b681efd2c916c966671070d4c7dc1a/merged
overlay                                       92G   92G   20K 100% /var/lib/docker/overlay2/047a0c4788b63d6fdaefb7fae9b3715057e4101243492709311aa5263373121e/merged

/var/lib/docker/image/overlay2:存储镜像管理元数据的目录,以使用存储驱动命名。

/var/lib/docker/overlay2:  docker镜像存储的联合挂载根目录

overlay2表示Docker的存储驱动,可参考

 Docker存储驱动之OverlayFS简介_styshoo的博客-CSDN博客

容器/镜像等都会存在这个目录下,当量大的时候就会占满硬盘,也可参考官网 

Use the OverlayFS storage driver | Docker Documentation

overlay 分区是 Docker 的虚拟文件系统,其真实的文件系统是 /dev/vda1

1、无用的镜像和容器太多

使用以下命令大致看下情况

docker system df -v
# 用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及无tag的镜像。
docker system prune

# 可以将没有容器使用 Docker 镜像都删掉。注意,这两个命令会把你暂时关闭的容器,以及暂时没有用到的Docker镜像都删掉了
docker system prune -a

2、容器输出的日志太大

这种情况往往是容器长时间运行,容器打印了大量的日志未清理,占据了大量磁盘空间。比如之前运行的一个Jenkins容器,运行几个月后,打印的日志占了近10个G的磁盘。这种情况下清理日志文件就行了

容器的日志文件在/var/lib/docker/containers/{containerId}

查看文件的大小

du -h --max-depth=1

在该目录下,会存在以目录名为前缀,以“-json.log”为后缀的目录文件;可以删除日志文件,也可调整应用程序让打印的日志保持在某种大小

上述方法不行,可

1、首先找到overlay2目录

cd /var/lib/docker/overlay2

2、查看文件的大小

du -h --max-depth=1

找到比较大的文件

 

3、查看占用空间的pid,以及对应的容器名称

[root@xx overlay2]# docker ps -q | xargs docker inspect --format '{{.State.Pid}}, {{.Name}}, {{.GraphDriver.Data.WorkDir}}' | grep "43883c34f85a329a0eca43e5c1c18fe5f4285ab5c8a70af1a9674fa4e2bd6dc8"
125440, /energy-task-mgl, /var/lib/docker/overlay2/43883c34f85a329a0eca43e5c1c18fe5f4285ab5c8a70af1a9674fa4e2bd6dc8/work

4、解决方法(会删除对应的容器和对应镜像)

docker stop energy-task-gd && docker rm energy-task-gd && docker rmi image_id

再使用df -h 查看

df -h

网上很多误导说是overlay的原因,然后去迁移路径什么的。其实和overlay没关系(它的usage和真实的disk  usage相同),它只是一个docker的虚拟文件系统,真实的文件系统是前者/dev/vda1,可以看到路径所指为根目录,所以你要去找是哪里出现了垃圾;如下

(1)日志文件。如nginx日志,配置的时候就应该给个日志限制,防止不断增长

大文件占用了 /dev/vda1 分区。这个分区一般是挂载在 “/” 下面。

可以重点关注下面几个目录:

  • /var/tmp
  • /var/log
  • /root

(2)/tmp 。 这个路径下可能藏了很多例如python安装模块产生的临时文件,注意定时清理

3、手动清理Docker镜像/容器/数据卷

对于旧版的Docker(版本1.13之前),是没有Docker System命令的,因此需要进行手动清理。这里给出几个常用的命令:

docker rmi [image]

或 

docker image rm [image]

支持的子命令如下:

-f, -force:强制删除镜像,即便有容器引用该镜像

-no-prune:不要删除未带标签的父镜像

删除所有关闭的容器:

docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs docker rm

删除所有dangling镜像(即无tag的镜像):

docker rmi $(docker images | grep "^<none>" | awk "{print $3}")

dangling是一种特殊的,不会再被使用到的镜像,docker有专门清理dangling镜像的命令 

docker image prune -f

删除所有dangling数据卷(即无用的Volume):

docker volume rm $(docker volume ls -qf dangling=true)

4、自动化删除none标签镜像或异常容器

配置自动化删除,在对应的机器上配置crontab

1. crontab -e

2. 添加如下指令(分别在凌晨前删除none标签的镜像和异常退出的容器)

59 23 * * *  docker rmi -f  `docker images | grep '' | awk '{print $3}'`

59 23 * * *  docker rm `docker ps -a | grep Exited | awk '{print $1}'

5、限制容器的日志大小

有一次,当我使用1与2提到的方法清理磁盘之后,发现并没有什么作用

我们使用 docker 镜像创建容器时,docker会创建一些目录,如:

/var/lib/docker/containers/<容器ID> 目录,如果容器使用了默认的日志模式,那么该容器的日志会以 JSON 形式保存在此目录下

/var/lib/docker/overlay2 目录,该目录包含容器的读写层,如果容器使用自己的文件系统保存了数据,那么这些数据就会写到此目录下

Containers 包含的我们容器自身的容量、产生的数据容量、产生的日志容量

# 查看所有容器下日志的大小
find /var/lib/docker/containers/ -name *-json.log |xargs du -sh
 
# 写个空文件到容器日志中
cat /dev/null > /var/lib/docker/containers/2d2f01c90365bd6926bcc01f9fb17d399eb2ebecb0bd3c808ee5b6c11ae4083d/2d2f01c90365bd6926bcc01f9fb17d399eb2ebecb0bd3c808ee5b6c11ae4083d-json.log
 
# 将某个日志文件清零🆑
truncate -s 0 /var/lib/docker/containers/2d2f01c90365bd6926bcc01f9fb17d399eb2ebecb0bd3c808ee5b6c11ae4083d/2d2f01c90365bd6926bcc01f9fb17d399eb2ebecb0bd3c808ee5b6c11ae4083d-json.log

设置容器日志的最大容量,下面是nginx的设置的例子

nginx:
  image: nginx:1.12.1
  restart: always
  logging:
    driver: "json-file"
  options:
    max-size: "5g"

在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,再也不用担心了~

6、重启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加载镜像报错 dockerError processing tar file(exit status 1): no space left on device_while10的博客-CSDN博客

谁用光了磁盘?Docker System命令详解 - DockOne.io

如何清理Docker占用的磁盘空间?_咖猫的博客-CSDN博客_docker 磁盘清理

Docker overlay2占用大量磁盘空间解决办法_普通网友的博客-CSDN博客_overlay2占用磁盘空间 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐