有没有办法只将已更改的文件作为新图层添加到docker镜像中 - 无需借助docker commit?

Mot*_*tin 10 docker

TL; DR

COPY . /app在图像上运行但稍微过时的源代码会创建一个与整个源代码一样大的新图层,即使只有少量字节的更改也是如此.有没有办法只将已更改的文件作为新图层添加到此docker镜像中 - 而无需借助docker commit?

长版:

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

FROM neam/dna-project-base-debian-php:0.6.0
COPY . /app
Run Code Online (Sandbox Code Playgroud)

由于源代码很大(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
Run Code Online (Sandbox Code Playgroud)

在下一次部署时,我们只想将更改后的文件添加到图像中,但是COPY . /app在先前添加的图像上运行时观察和观察实际上需要我们推送价值1.2 GB的源代码,即使我们只更改了一些字节值源代码:

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

FROM project/project-web-src-php:git-commit-17c279b
COPY . /app
Run Code Online (Sandbox Code Playgroud)

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

$ 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
Run Code Online (Sandbox Code Playgroud)

有一个解决方法来实现小层,如使用提交更新docker镜像并进行小更改所述,其中包括在映像中启动rsync进程,然后使用docker commit将新内容保存为新层,但是(如该线程中所述) )这是非正统的,因为图像不是从Dockerfile构建的,我们更喜欢不依赖于docker commit的正统解决方案.

有没有办法只将已更改的文件作为新图层添加到此docker镜像中 - 而无需借助docker commit?

Docker版本1.8.3

Mot*_*tin 7

实际上,正如OP正在使用的解决方案COPY . /app一样,但是有一个开放的错误导致它在大多数系统上无法正常工作

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

这样,对于较小的更改,层大小变为几个字节或千字节,而不是每次1.2 GB.

我在https://github.com/neam/docker-diff-based-layers上整理了文档和脚本以帮助解决这个问题.

最终结果如下所示:

验证将项目图像基于修订版1图像标记内容不会导致所需结果

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

docker history sample-project:revision-2
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

此外,我们删除的文件没有被删除.

使用优化图层创建图像

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 ..
Run Code Online (Sandbox Code Playgroud)

验证处理后的新图像是否包含更改的较小图层:

docker history sample-project:revision-2-processed
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

输出应指示图像/标签之间没有差异.因此,现在可以推送和部署示例项目:版本2处理的标签,从而产生相同的最终结果,但不必通过线路推送不必要的16.78M,从而导致更快的部署周期.

  • 令人疯狂的是,这个错误并不是优先考虑的事情(甚至可以告诉我这个错误).我发现docker对于希望部署代码并逐步更新代码的常见模式的实际支持几乎没有.从整个事物中获得非常学术性的氛围,有很多"你为什么要这样做?" 键入常见的现实世界开发模式的答案. (4认同)