TL;博士
在带有但稍微过时的源代码的映像之上运行COPY . /app会创建一个与整个源代码一样大的新层,即使只有几个字节的更改。是否有一种方法只将已更改的文件添加到这个对接器映像中作为一个新的层-而不求助于停靠提交?
长版本:
在将应用程序部署到生产中时,我们需要将源代码添加到映像中。为此使用了一个非常简单的Dockerfile:
FROM neam/dna-project-base-debian-php:0.6.0
COPY . /app由于源代码很大(1.2GB),因此对每个部署都有很大的推动作用:
$ 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时,实际上需要再次推送1.2GB的源代码,即使我们只更改了几字节的源代码:
新Dockerfile (.stack.php.git-commit-17c279b.Dockerfile):
FROM project/project-web-src-php:git-commit-17c279b
COPY . /app更改几个文件后,添加一些文本和代码,然后构建和推送:
$ 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有一个解决方法可以实现使用提交使用小更改更新停靠器映像上描述的小层,其中包括在映像中启动rsync进程,然后使用docker commit将新内容保存为新层,但是(如该线程中提到的)这是非正统的,因为映像不是从Dockerfile构建的,我们更喜欢不依赖于码头提交的正统解决方案。
是否有一种方法只将已更改的文件添加到这个对接器映像中作为一个新的层-而不求助于停靠提交?
码头版本1.8.3
发布于 2016-04-12 00:52:01
实际上,就像行动小组所做的,但是有一个打开的错误导致这在大多数系统上无法正常工作。
这个问题目前唯一可行的解决办法似乎是在推送新图像之前使用rsync来分析新旧图像之间的差异,然后使用changelog输出生成一个tar文件,其中包含相应的更改,这些更改随后被复制到一个新的图像层。
这样,对于较小的更改,层大小就变成了几个字节或千字节,而不是每次1.2GB。
我将文档和脚本放在一起,以便在https://github.com/neam/docker-diff-based-layers帮助解决这个问题。
最终结果如下:
验证基于修订1图像标记内容的项目映像不会导致期望的结果。
验证后续的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.78MB被添加到整个图像大小中。
另外,我们删除的文件没有被删除。
用优化的图层创建图像
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 ..验证处理后的新图像具有较小大小的层,并进行更改:
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验证处理后的新图像是否包含与原始图像相同的内容:
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输出应该表明图像/标记之间没有区别。因此,示例项目:Revision2处理的标记现在可以被推送和部署,从而得到相同的最终结果,但不必将不必要的16.78M推到电线上,从而加快部署周期。
发布于 2016-04-11 18:31:12
Docker缓存可以在Dockerfile中的每个层/指令中工作。在这种情况下,该层中使用的文件(构建上下文(.)中的所有内容)都会被修改,因此需要重新构建该层。
如果代码的特定部分不经常更改,您可以考虑在单独的层中添加这些部分,甚至将它们移动到“基本映像”中。
FROM mybaseimage
COPY ./directories-that-dont-change-often /somewhere
COPY ./directories-that-change-often /somewhere这可能需要一些计划或重组才能发挥作用,这取决于您的项目,但可能是值得的。
发布于 2017-01-19 09:37:19
我的解决方案:( 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}https://stackoverflow.com/questions/36553502
复制相似问题