我不明白为什么 '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 当然比这个示例长得多,因此图像大小的增加也相当大。这就是为什么我什至关心..
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
命令能够成功运行,我当然希望生成的图像会更大(因为这会安装额外的文件)。
自 Docker 17.09 起,可以在 Dockerfile 中的 ADD/COPY 操作上使用
--chown
标志来更改 ADD/COPY 步骤本身的所有者,而不是使用 chown 进行单独的 RUN 操作,这会增加镜像的大小,正如您所注意到的。最好将此作为默认模式,即复制文件的用户的权限应用于复制的文件。然而,Docker 团队不想破坏向后兼容性,因此引入了一个新标志。
的更多信息
COPY --chown=<user>:<group> <hostPath> <containerPath>
其他替代方案是:
在构建映像之前更改暂存文件夹中的权限。
通过更改所有权的引导脚本运行容器。
压扁层!
不幸的是,这是一个已知问题:https://github.com/docker/docker/issues/5505和https://github.com/docker/docker/issues/6119#issuecomment-70606158
您可以通过将 docker 存储驱动程序从 aufs 更改为 devicemapper 来解决此问题,如 https://github.com/docker/docker/issues/6119#issuecomment-268870519
中所述现在您可以使用 ImageLayers.io 直观地检查图像及其图层,以帮助了解额外尺寸的原因。
还有, docker 历史显示了类似的东西。
关于
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
这将避免将已选择的文件/目录添加到新图像层。
这是由于 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