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

问题描述 投票:0回答:6

我不明白为什么 '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

为什么?

注意: 我的实际 dockerfile 当然比这个示例长得多,因此图像大小的增加也相当大。这就是为什么我什至关心..

docker filesize chown dockerfile
6个回答
22
投票

Dockerfile 中的每个步骤都会生成一个新的中间映像或“层”,其中包含文件系统上与上一层相比发生的任何更改。 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 ...
行,无论是否运行
adduser
chown
命令,我都看不到最终图像大小有任何差异。给定:

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
命令能够成功运行,我当然希望生成的图像会更大(因为这会安装额外的文件)。


18
投票

自 Docker 17.09 起,可以在 Dockerfile 中的 ADD/COPY 操作上使用

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

阅读 Docker 文档中有关 COPYADD

的更多信息

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

其他替代方案是:

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

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

  3. 压扁层!


3
投票

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

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

中所述

2
投票

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

还有, docker 历史显示了类似的东西。


2
投票

关于

chown
需要注意的一点是,Docker 仍然会认为在
chown
之后目录已更改所有者,即使该目录之前已由同一用户拥有。意思是,像这样:

FROM ubuntu:latest
RUN mkdir hello
WORKDIR /hello
COPY . .
RUN groupadd userx && adduser userx --ingroup userx
RUN chown userx:userx -R /hello
RUN chown userx:userx -R /hello
RUN chown userx:userx -R /hello

将使图像大小包含“hello”4次,即使其膨胀。

如果在给定的父目录中,某些目录已被 chown,而另一些目录尚未被 chown,则您可能会遇到此问题,但将

chown
添加到许多其他 Docker 命令中会使事情变得不可读。

因此,至少在 Ubuntu 中,可以运行:

# `--from=root:root` here being essential
RUN chown userX:userX --from=root:root -R /hello

这将避免将已选择的文件/目录添加到新图像层。


0
投票

这是由于 dockerfile 创作不规范造成的。当使用 chown-R 时,会创建一个新层来存储所有权更改,从而导致图像尺寸更大

解决方案是使用“COPY --chown=hsadmin:hsadmin”指令,这意味着将文件复制到容器时,文件的所有权已设置为“hsadmin”用户和组。这样做可以避免在复制文件后创建新图层来更改文件的所有权。

FROM alpine:edge

ARG UID=1000
ARG GID=1000

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache shadow

RUN addgroup -g $GID hsadmin && adduser -D -u $UID -G hsadmin hsadmin

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    mkdir -p /home/hsadmin/app

COPY --chown=hsadmin:hsadmin cloudEngine-v2.7.0.tar.gz /home/hsadmin/app
USER hsadmin

图像体积为1.08克

test        1.7      294cfb715748   6 minutes ago    1.08GB

在授权目录之前进行复制,这会在 Docker 镜像中创建一个新层来存储所有权更改,从而增加镜像的大小。

FROM alpine:edge

ARG UID=1000
ARG GID=1000

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache shadow

RUN addgroup -g $GID hsadmin && adduser -D -u $UID -G hsadmin hsadmin

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    mkdir -p /home/hsadmin/app

COPY cloudEngine-v2.7.0.tar.gz /home/hsadmin/app

RUN chown -R hsadmin:hsadmin /home/hsadmin/app
USER hsadmin

尺寸增大

test          1.8          fbbb35320d83   3 seconds ago    2.14GB
© www.soinside.com 2019 - 2024. All rights reserved.