docker registry服务器磁盘100%,该如何释放?
一、问题描述
我自己搭建了一个docker registry私服,总磁盘有300G左右,有几年的时间,一直没动,没有扩展磁盘,也没有删除镜像。
最近忽然无法push镜像了,在服务器上查找一番,发现磁盘空间100%了。
二、所用环境
Ubuntu 16.04
registry 2.1.1
三、解决困难
1.registry默认配置不允许删除
1) 更改registry容器内/etc/docker/registry/config.yml文件
storage:
delete:
enabled: true
2.registry删除镜像时,仅删除索引,无法清理文件
1) 清理文件数据需要较复杂的运算,参见《了解docker registry的存储格式》(后续完善)
2) 升级registry到2.4.1,运用registry自带命令
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
3.执行删除操作需要找到具体镜像的digest_hash值
1) 找出你想要的镜像名称的tag
$ curl -I -X GET <protocol>://<registry_host>/v2/<镜像名>/tags/list
2) 拿到digest_hash参数
$ curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET http://<仓库地址>/v2/<镜像名>/manifests/<tag>
3) 复制digest_hash
Docker-Content-Digest: <digest_hash>
4) 删除清单
$ curl -I -X DELETE <protocol>://<registry_host>/v2/<repo_name>/manifests/<digest_hash>
四、解决方案
1.registry官方推荐删除方案
1) 更改registry容器内/etc/docker/registry/config.yml文件
storage:
delete:
enabled: true
1) 找出你想要的镜像名称的tag
$ curl -I -X GET <protocol>://<registry_host>/v2/<镜像名>/tags/list
2) 拿到digest_hash参数
$ curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET http://<仓库地址>/v2/<镜像名>/manifests/<tag>
例如:
$ curl --header "Accept: application/vnd.docker.distribution.manifest.v2+json" -I -X GET http://10.109.252.221:5000/v2/wordpress/manifests/latest
3) 复制digest_hash
Docker-Content-Digest: <digest_hash>
4) 删除清单
$ curl -I -X DELETE <protocol>://<registry_host>/v2/<repo_name>/manifests/<digest_hash>
例如:
$ curl -I -X DELETE http://10.109.252.221:5000/v2/wordpress/manifests/sha256:b3a15ef1a1fffb8066d0f0f6d259dc7f646367c0432e3a90062b6064f874f57c
6) 删除文件系统内的镜像文件,注意2.4版本以上的registry才有此功能
$ docker exec -it <registry_container_id> bin/registry garbage-collect <path_to_registry_config>
例如:
$ docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
2.简易版删除
1) 打开镜像的存储目录,如有-V操作打开挂载目录也可以,删除镜像文件夹
$ docker exec <容器名> rm -rf /var/lib/registry/docker/registry/v2/repositories/<镜像名>
2) 执行垃圾回收操作,注意2.4版本以上的registry才有此功能
$ docker exec -it <registry_container_id> bin/registry garbage-collect <path_to_registry_config>
例如:
$ docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
3.删除时,遇到一个问题,一个镜像中tag数太多了,有的删除有的不删除
每次发版时,会在git branch名称后加一个时间戳,因此发版时,同一个git branch,最后一个时间戳为发版的时间戳
此处显示出awk功能的强大,一条语句解决问题:
cd /var/lib/registry/docker/registry/v2/repositories/<镜像名称>/_manifests/tags
ls | awk -F '.' '{print $1"."$2"."$3"."$4" "$5 }' | sort -k1rd | awk '{if(a[$1]<$2){b[$1][a[$1]]=1;a[$1]=$2}else{b[$1][$2]=1}}END{for(n in b){for(m in b[n]){if(m is not null) print n"."m}}}' | sort -k1rd | xargs -i rm -rf {}
逐条语句解释一下:
ls ——显示当前文件夹下的文件名
awk -F ‘.’ ‘{print $1″.”$2″.”$3″.”$4″ “$5 }’ ——此时将branch名称与时间戳区分开(awk应用功能之一,拆分同一个字段)
sort -k1rd ——k1表示用第一个字段,rd表示按字典序倒序
awk ‘{if(a[$1]<$2){b[$1][a[$1]]=1;a[$1]=$2}else{b[$1][$2]=1}}END{for(n in b){for(m in b[n]){if(m is not null) print n”.”m}}}’ ——这条语句有意思了,居然可以用awk写编程语句
详细拆分一下单引号内的语句,使用格式展开如下:
{
if (a[$1] < $2) { ##默认生成a[]数组,以$1作为index,以$2作为值,循环上一个管道输出,当原来存储值小于现有$2时
b[$1][a[$1]] = 1; ##默认生成b[][]二维数组,把$1和a[$1]作为二维数组的index,值不重要
a[$1] = $2
} else { ##当a数组原有存储值≥现有$2时
b[$1][$2] = 1 ##记录$1和$2进入b[][]数组
} ##两个判断结束后,b内的数组为分组结构,排除分组内最大值外都在b数组内
}
END { ##END标识初始化结束,开始输出
for (n in b) { ##第一层循环
for (m in b[n]) { ##第二层循环
if (m is not null) print n"."m ##将上一个awk输出的拆除的字段又拼接起来,还原了文件夹名称,判空是因为第一个判断时,将一个空的$2写入数组了
}
}
}
最后将过滤出的文件夹删除,使用管道xargs重定向删除。
4.使用hyper/docker-registry-web将数据删除
1) 修改/conf/config.yml,指定readonly为false,指定registry对应的服务:
registry:
url: http://registry:5000/v2
name: localhost
readonly: false
2) 搭建docker-registry-web后,服务启动,用户登录,手动web端删除repository,后续如有空闲时间,会逐渐补充如何搭建此服务。
直接点击delete就可以删除了。
3) 执行垃圾回收操作,注意2.4版本以上的registry才有此功能
$ docker exec -it <registry_container_id> bin/registry garbage-collect <path_to_registry_config>
例如:
$ docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
参考:https://shipengliang.com/software-exp/docker-registry%E4%BB%93%E5%BA%93%E9%95%9C%E5%83%8F%E5%88%A0%E9%99%A4%E6%96%B9%E6%B3%95.html