正确保持docker VSTS / Azure Devops build代理干净但已缓存

Iva*_*van 10 build docker kubernetes azure-devops azure-pipelines

我们已将dockerized构建代理添加到我们的开发Kubernetes集群中,该集群用于构建应用程序作为Azure Devops管道的一部分。我们基于Github已弃用的Microsoft / vsts-agent-docker创建了自己的映像

构建代理使用Docker(DooD)外部的Docker在我们的开发集群上创建映像。

该代理已经运行了好几天,但是有时我们的构建管道中的docker命令偶尔会出现错误:

来自守护程序的错误响应:没有这样的图像:fooproject:ci-3284.2 / usr / local / bin / docker失败,返回码:1

我们意识到构建代理正在创建大量未被删除的图像。有大量的图像阻止了构建代理,并且缺少图像,这可以解释“没有这样的图像”错误消息。

通过使用以下命令在构建管道中添加一个步骤,我们能够使构建代理再次工作:

docker system prune -f -a
Run Code Online (Sandbox Code Playgroud)

但是当然这会删除我们所有的图像,并且每次都必须从头开始构建它们,这会使我们的构建花费不必要的长时间。

我确定这一定是一个已解决的问题,但是我无法找到有关处理随时间推移而被堵塞的dockerized build agent的常规策略的任何文档。对docker和kubernetes陌生,我可能根本不知道我在寻找什么。创建保持清洁和功能并保持缓存的泊坞窗化构建代理的最佳实践是什么?

编辑:一些想法:

  • 创建一个构建步骤,清除给定管道的所有图像(除了最新映像)(尽管这可能仍然阻塞构建服务器)。
  • 进行一次cron作业,每隔x天删除一次所有映像(这将导致作业运行后首次运行时生成速度慢,并且如果使用率过高,仍可能阻塞生成服务器。
  • 每晚清除所有图像,并在工作时间以外运行所有构建。这样,构建将在白天快速运行。但是,大量使用仍然可能阻塞构建服务器。

编辑2:

在Github上发现了一个有docker问题的人,似乎正在尝试做与我完全相同的事情。他提出了一个解决方案,描述如下:

我正是试图找出如何在删除构建依赖项的情况下从自动构建环境中删除“旧”映像的方法。这意味着我不能随年龄而删除,因为nodejs图像可能在数周内不会发生变化,而我的应用程序构建在几分钟之内就一文不值。

docker image rm $(docker image ls --filter reference=docker --quiet)

那颗小宝石正是我所需要的。我将存储库名称放在引用变量中(不是最容易解释的)。由于同时标记了内部版本号和最新版本,因此docker image rm命令在要保留的图像上失败。我真的不喜欢将守护程序错误用作保护机制,但是它很有效。

尝试按照这些指示进行操作,我已将latest代码应用于该过程中生成的所有内容,然后运行

docker image ls --filter reference=fooproject

如果我尝试删除这些,则会出现以下错误:

来自守护程序的错误响应:冲突:无法删除b870ec9c12cc(必须强制执行)-在多个存储库中引用了图像

这样可以防止最新的文件被删除。但是,这并不是一种干净的方法。肯定有更好的办法?

VAS*_*VAS 5

可能您已经找到了解决方案,但在这里得到答案可能对社区的其他人有用。

docker prune目的有限。创建它是为了解决清理所有本地 Docker 镜像的问题。(正如thaJeztah 在这里提到的那样

要以更精确的方式删除图像,最好将此任务分为两部分: 1. 选择/过滤要删除的图像 2. 删除所选图像的列表

例如:

docker image rm $(docker image ls --filter reference=docker --quiet)
docker image rm $(sudo docker image ls | grep 1.14 | awk '{print $3}')
docker image ls --filter reference=docker --quiet | xargs docker image rm
Run Code Online (Sandbox Code Playgroud)

可以结合过滤器子句来准确获取您想要的内容:(
我使用 Kubernetes 主节点作为示例环境)

$ docker images

REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
k8s.gcr.io/kube-proxy                v1.14.2             5c24210246bb        3 months ago        82.1MB
k8s.gcr.io/kube-apiserver            v1.14.2             5eeff402b659        3 months ago        210MB
k8s.gcr.io/kube-controller-manager   v1.14.2             8be94bdae139        3 months ago        158MB
k8s.gcr.io/kube-scheduler            v1.14.2             ee18f350636d        3 months ago        81.6MB  # before
quay.io/coreos/flannel               v0.11.0-amd64       ff281650a721        6 months ago        52.6MB
k8s.gcr.io/coredns                   1.3.1               eb516548c180        7 months ago        40.3MB  # since
k8s.gcr.io/etcd                      3.3.10              2c4adeb21b4f        8 months ago        258MB
k8s.gcr.io/pause                     3.1                 da86e6ba6ca1        20 months ago       742kB

$ docker images --filter "since=eb516548c180" --filter "before=ee18f350636d" 

REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
quay.io/coreos/flannel   v0.11.0-amd64       ff281650a721        6 months ago        52.6MB

$ docker images --filter "since=eb516548c180" --filter "reference=quay.io/coreos/flannel" 
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
quay.io/coreos/flannel   v0.11.0-amd64       ff281650a721        6 months ago        52.6MB

$ docker images --filter "since=eb516548c180" --filter "reference=quay*/*/*" 
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
quay.io/coreos/flannel   v0.11.0-amd64       ff281650a721        6 months ago        52.6MB

$ docker images --filter "since=eb516548c180" --filter "reference=*/*/flan*" 
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
quay.io/coreos/flannel   v0.11.0-amd64       ff281650a721        6 months ago        52.6MB
Run Code Online (Sandbox Code Playgroud)

正如文档中提到的,images/ image lsfilter 比docker prunefilter好很多,until它只支持子句:

The currently supported filters are:
• dangling (boolean - true or false)  
• label (label=<key> or label=<key>=<value>)  
• before (<image-name>[:<tag>], <image id> or <image@digest>) - filter images created before given id or references
• since (<image-name>[:<tag>], <image id> or <image@digest>) - filter images created since given id or references
Run Code Online (Sandbox Code Playgroud)

如果您需要多个过滤器,则传递多个标志(例如,  --filter "foo=bar" --filter "bif=baz"

您可以使用其他 linux cli 命令来过滤docker images输出:

grep "something"      # to include only specified images
grep -v "something"   # to exclude images you want to save
sort [-k colN] [-r] [-g]] | head/tail -nX  # to select X oldest or newest images
Run Code Online (Sandbox Code Playgroud)

将它们组合起来并将结果放入 CI/CD 管道,可以让您只将需要的图像保留在本地缓存中,而不会在构建服务器上收集大量垃圾。

我在这里复制了一个使用strajansebastian评论中提供的方法的好例子:

#example of deleting all builds except last 2 for each kind of image 
#(the image kind is based on the Repository value.)

#If you want to preserve just last build modify to tail -n+2.

# delete dead containers
docker container prune -f

# keep last 2 builds for each image from the repository
for diru in `docker images --format "{{.Repository}}" | sort | uniq`; do
    for dimr in `docker images --format "{{.ID}};{{.Repository}}:{{.Tag}};'{{.CreatedAt}}'" --filter reference="$diru" | sed -r "s/\s+/~/g" | tail -n+3`; do 
        img_tag=`echo $dimr | cut -d";" -f2`; 
        docker rmi $img_tag;
    done;
done

# clean dangling images if any
docker image prune -f
Run Code Online (Sandbox Code Playgroud)