为什么 chown 会增加 docker 图像的大小?

Why does chown increase size of docker image?

我不明白为什么 'chown' 命令会增加我的 docker 图片的大小?

以下 Dockerfile 创建一个大小为 5.3MB 的图像:

FROM alpine:edge
RUN adduser example -D -h /example -s /bin/sh

然而,此示例创建了一个大小为 8.7MB 的图像:

FROM alpine:edge
RUN adduser example -D -h /example -s /bin/sh && \
    chown -R example.example /lib

为什么?

注意:我的实际docker文件当然比这个例子长很多,因此图像尺寸的增加也比较大。这就是为什么我什至关心..

Dockerfile 中的每一步都会生成一个新的中间映像,或 "layer",其中包含文件系统上从上一层发生的任何更改。 docker 图像由层的集合组成,层层叠加以创建最终的文件系统。

如果你有:

RUN adduser example -D -h /example -s /bin/sh

那么除了 /etc 中的几个文件(/etc/passwd/etc/group 以及它们的影子等价物)之外,您可能没有做任何更改。

如果你有:

RUN adduser example -D -h /example -s /bin/sh && \
    chown -R example.example /lib

然后已更改的列表递归地包括 /lib 中的所有内容,这可能更大。事实上,在我的 alpine:edge 容器中, /lib 的内容看起来是 3.4MB:

/ # du -sh /lib
3.4M    /lib

这正是您示例中图像大小变化的原因。

更新

使用您实际的 Dockerfile,注释掉 npm install ... 行,无论是否使用 adduserchown 命令,我都看不出最终图像大小有任何差异运行。鉴于:

RUN echo "http://nl.alpinelinux.org/alpine/edge/main" > /etc/apk/repositories && \
    echo "http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
    apk add -U wget iojs && \
    apk upgrade && \
    wget -q --no-check-certificate https://ghost.org/zip/ghost-0.6.0.zip -O /tmp/ghost.zip && \
    unzip -q /tmp/ghost.zip -d /ghost && \
    cd /ghost && \
#    npm install --production && \
    sed 's/127.0.0.1/0.0.0.0/' /ghost/config.example.js > /ghost/config.js && \
    sed -i 's/"iojs": "~1.2.0"/"iojs": "~1.6.4"/' package.json && \
#   adduser ghost -D -h /ghost -s /bin/sh && \
#   chown -R ghost.ghost * && \
    npm cache clean && \
    rm -rf /var/cache/apk/* /tmp/*

我得到:

$ docker build -t sotest .
[...]
Successfully built 058d9f41988a
$ docker inspect -f '{{.VirtualSize}}' 058d9f41988a
31783340

鉴于:

RUN echo "http://nl.alpinelinux.org/alpine/edge/main" > /etc/apk/repositories && \
    echo "http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
    apk add -U wget iojs && \
    apk upgrade && \
    wget -q --no-check-certificate https://ghost.org/zip/ghost-0.6.0.zip -O /tmp/ghost.zip && \
    unzip -q /tmp/ghost.zip -d /ghost && \
    cd /ghost && \
#    npm install --production && \
    sed 's/127.0.0.1/0.0.0.0/' /ghost/config.example.js > /ghost/config.js && \
    sed -i 's/"iojs": "~1.2.0"/"iojs": "~1.6.4"/' package.json && \
    adduser ghost -D -h /ghost -s /bin/sh && \
    chown -R ghost.ghost * && \
    npm cache clean && \
    rm -rf /var/cache/apk/* /tmp/*

我得到:

$ docker build -t sotest .
[...]
Successfully built 696b481c5790
$ docker inspect -f '{{.VirtualSize}}' 696b481c5790
31789262

即两张图片大小差不多( 差异约为 5 Kb)。

如果 npm install 命令能够 运行 成功,我当然希望生成的图像更大(因为那样会安装额外的文件)。

现在您可以使用 ImageLayers.io 直观地检查您的图像及其图层,以帮助了解额外尺寸的原因。

另外, docker 历史显示了类似的东西。

不幸的是,这是一个已知问题:https://github.com/docker/docker/issues/5505 and https://github.com/docker/docker/issues/6119#issuecomment-70606158

您可以通过将 docker 存储驱动程序从 aufs 更改为 devicemapper 来解决此问题,如 https://github.com/docker/docker/issues/6119#issuecomment-268870519

中所述

从 Docker 17.09 开始,可以在 Docker 文件中的 ADD/COPY 操作上使用 --chown 标志来更改 ADD/COPY 步骤本身的所有者而不是使用 chown 的单独 运行 操作,它会增加图像的大小,正如您所注意到的。最好将此作为默认模式,即复制文件的用户权限应用于复制的文件。但是,Docker 团队不想破坏向后兼容性,因此引入了一个新标志。

在 Docker 关于 COPY and ADD

的文档中阅读更多内容

COPY --chown=<user>:<group> <hostPath> <containerPath>

其他备选方案是:

  1. 在构建映像之前更改暂存文件夹中的权限。

  2. 运行 通过 bootstrap 脚本更改所有权的容器。

  3. 压扁图层!