有没有办法只添加更改的文件作为一个新的图层泊坞窗图像 – 无需诉诸docker提交?

TL; DR

运行COPY . /app COPY . /app在图片的顶部,但是稍微过时的源代码会创build一个与整个源代码一样大的新图层,即使只有几个字节值的更改也是如此。 有没有办法只添加更改的文件作为一个新的图层泊坞窗图像 – 无需诉诸docker提交?

长版本:

将应用程序部署到生产环境时,我们需要将源代码添加到图像中。 一个非常简单的Dockerfile用于这个:

 FROM neam/dna-project-base-debian-php:0.6.0 COPY . /app 

由于源代码是巨大的(1.2 GB),所以每次部署都会造成相当大的压力:

 $ docker build -f .stack.php.Dockerfile -t project/project-web-src-php:git-commit-17c279b . Sending build context to Docker daemon 1.254 GB Step 0 : FROM neam/dna-project-base-debian-php:0.6.0 ---> 299c10c416fc Step 1 : COPY . /app ---> 78a30802804a Removing intermediate container 13b49c323bb6 Successfully built 78a30802804a $ docker tag -f project/project-web-src-php:git-commit-17c279b tutum.co/project/project-web-src-php:git-commit-17c279b $ docker login --email=tutum-project@project.com --username=project --password=******** https://tutum.co/v1 WARNING: login credentials saved in /home/dokku/.docker/config.json Login Succeeded $ docker push tutum.co/project/project-web-src-php:git-commit-17c279b The push refers to a repository [tutum.co/project/project-web-src-php] (len: 1) Sending image list Pushing repository tutum.co/project/project-web-src-php (1 tags) Image a604b236bcde already pushed, skipping Image 1565e86129b8 already pushed, skipping ... Image 71156b357f2f already pushed, skipping Image 299c10c416fc already pushed, skipping 78a30802804a: Pushing [=========> ] 234.2 MB/1.254 GB 

在下一次部署时,我们只想将更改后的文件添加到图像中,但在运行COPY . /app时请注意并注意COPY . /app COPY . /app在以前添加的图像之上实际上要求我们再次推送1.2 GB的源代码,即使我们只更改了几个字节的源代码:

新的Dockerfile( .stack.php.git-commit-17c279b.Dockerfile ):

 FROM project/project-web-src-php:git-commit-17c279b COPY . /app 

更改几个文件后,添加一些文本和代码,然后build立和推送:

 $ docker build -f .stack.php.git-commit-17c279b.Dockerfile -t project/project-web-src-php:git-commit-17c279b-with-a-few-changes . Sending build context to Docker daemon 1.225 GB Step 0 : FROM project/project-web-src-php:git-commit-17c279b ---> 4dc643a45de3 Step 1 : COPY . /app ---> ecc7adc194c4 Removing intermediate container cb3e87c6cb7a Successfully built ecc7adc194c4 $ docker tag -f project/project-web-src-php:git-commit-17c279b-with-a-few-changes tutum.co/project/project-web-src-php:git-commit-17c279b-with-a-few-changes $ docker push tutum.co/project/project-web-src-php:git-commit-17c279b-with-a-few-changes The push refers to a repository [tutum.co/project/project-web-src-php] (len: 1) Sending image list Pushing repository tutum.co/project/project-web-src-php (1 tags) Image 1565e86129b8 already pushed, skipping Image a604b236bcde already pushed, skipping ... Image fe64bff23cf8 already pushed, skipping Image 71156b357f2f already pushed, skipping ecc7adc194c4: Pushing [==> ] 68.21 MB/1.225 GB 

有一个解决方法来实现小型图层更新docker图像使用提交包括启动一个rsync进程内的图像,然后使用docker提交保存新的内容作为一个新的层,但是(如该线程中提到的)这是非正统的,因为图像不是从Dockerfile构build的,我们更喜欢不依赖于docker commit的正统解决scheme。

有没有办法只添加更改的文件作为一个新的图层泊坞窗图像 – 无需诉诸docker提交?

Docker版本1.8.3

其实, 解决方法是使用COPY . /app COPY . /app作为OP正在做 ,但是有一个开放的错误,导致这不能按预期在大多数系统上工作

这个问题目前唯一可行的解​​决方法似乎是使用rsync来分析旧图像和新图像之间的差异,然后使用changelog输出来生成一个包含相关更改的tar文件,随后COPY :编辑到一个新的图像层。

这样,图层大小就变成几个字节或千字节,而不是每次1.2 GB。

我把文档和脚本放在一起,通过https://github.com/neam/docker-diff-based-layers来帮忙。

最终结果如下所示:

validation基于版本1图像标签内容的项目图像不会导致期望的结果

validation后续的COPY . /app COPY . /app命令重新添加每个图层中的所有文件,而不仅仅是已更改的文件:

 docker history sample-project:revision-2 

输出:

 IMAGE CREATED CREATED BY SIZE COMMENT 4a3115eaf267 3 seconds ago /bin/sh -c #(nop) COPY dir:61d102421e6692b677 16.78 MB d4b30af167f4 25 seconds ago /bin/sh -c #(nop) COPY dir:68b8f374d8731b8ad8 16.78 MB c898fe1daa44 2 minutes ago /bin/sh -c apt-get update && apt-get install 10.77 MB 39a8a358844a 4 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B b1dacad9c5c9 4 months ago /bin/sh -c #(nop) ADD file:5afd8eec1dc1e7666d 125.1 MB 

即使我们只添加/更改了几个字节,也会重新添加所有文件,并在总图像大小中添加16.78 MB。

另外,我们删除的文件没有被删除。

使用优化图层创build图像

 export RESTRICT_DIFF_TO_PATH=/app export OLD_IMAGE=sample-project:revision-1 export NEW_IMAGE=sample-project:revision-2 docker-compose -f rsync-image-diff.docker-compose.yml up docker-compose -f shell.docker-compose.yml -f process-image-diff.docker-compose.yml up cd output; docker build -t sample-project:revision-2-processed .; cd .. 

validation处理后的新图像是否具有较小尺寸的图层:

 docker history sample-project:revision-2-processed 

输出:

 IMAGE CREATED CREATED BY SIZE COMMENT 1920e750d362 24 seconds ago /bin/sh -c if [ -s /.files-to-remove.list ]; 0 B 1267bf926729 2 minutes ago /bin/sh -c #(nop) ADD file:5021c627243e841a45 19 B d04a2181b62a 2 minutes ago /bin/sh -c #(nop) ADD file:14780990c926e673f2 264 B d4b30af167f4 7 minutes ago /bin/sh -c #(nop) COPY dir:68b8f374d8731b8ad8 16.78 MB c898fe1daa44 9 minutes ago /bin/sh -c apt-get update && apt-get install 10.77 MB 39a8a358844a 4 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B b1dacad9c5c9 4 months ago /bin/sh -c #(nop) ADD file:5afd8eec1dc1e7666d 125.1 MB 

validation处理后的新图像是否包含与原始图像相同的内容:

 export RESTRICT_DIFF_TO_PATH=/app export OLD_IMAGE=sample-project:revision-2 export NEW_IMAGE=sample-project:revision-2-processed docker-compose -f rsync-image-diff.docker-compose.yml up 

输出应该表明图像/标签之间没有区别。 因此,sample-project:revision-2-processed标签现在可以被推送和部署,导致相同的最终结果,但不必在线上推送不必要的16.78M,导致更快的部署周期。

Dockercaching工作在Dockerfile中的每个层/指令。 在这种情况下,该层中使用的文件(构build上下文( . )中的所有内容)都将被修改,因此该层需要重新构build。

如果代码的特定部分不经常更改,则可以考虑将这些代码添加到单独的图层中,甚至将它们移动到“基本图像”

 FROM mybaseimage COPY ./directories-that-dont-change-often /somewhere COPY ./directories-that-change-often /somewhere 

这可能需要一些计划或重组,这取决于你的项目,但可能值得去做。

我的解决scheme:(想法从https://github.com/neam/docker-diff-based-layers !)

 docker rm -f uniquename 2> /dev/null docker run --name uniquename -v ~/repo/mycode:/src ${REPO}/${IMAGE}:${BASE} rsync -ar --exclude-from '/src/.dockerignore' --delete /src/ /app/ docker commit uniquename ${REPO}/${IMAGE}:${NEW_TAG}