你可以继续使用与上面相同的Dockerfile,只是现在要调用两次:
FROM node:8 as build WORKDIR /app COPY package.json index.js ./ RUN npm install FROM node:8 COPY --from=build /app / EXPOSE 3000 CMD ["index.js"]Dockerfile的第一部分创建了三个层,然后这些层被合并并复制到第二个阶段。在第二阶段,镜像顶部又添加了额外的两个层,所以总共是三个层。
现在来验证一下。首先,构建容器:
$ docker build -t node-multi-stage .查看镜像的历史:
$ docker history node-multi-stage IMAGE CREATED BY SIZE 331b81a245b1 /bin/sh -c #(nop) CMD ["index.js"] 0B bdfc932314af /bin/sh -c #(nop) EXPOSE 3000 0B f8992f6c62a6 /bin/sh -c #(nop) COPY dir:e2b57dff89be62f77… 1.62MB b87c2ad8344d /bin/sh -c #(nop) CMD ["node"] 0B <missing> /bin/sh -c set -ex && for key in 6A010… 4.17MB <missing> /bin/sh -c #(nop) ENV YARN_VERSION=1.3.2 0B <missing> /bin/sh -c ARCH= && dpkgArch="$(dpkg --print… 56.9MB <missing> /bin/sh -c #(nop) ENV NODE_VERSION=8.9.4 0B <missing> /bin/sh -c set -ex && for key in 94AE3… 129kB <missing> /bin/sh -c groupadd --gid 1000 node && use… 335kB <missing> /bin/sh -c set -ex; apt-get update; apt-ge… 324MB <missing> /bin/sh -c apt-get update && apt-get install… 123MB <missing> /bin/sh -c set -ex; if ! command -v gpg > /… 0B <missing> /bin/sh -c apt-get update && apt-get install… 44.6MB <missing> /bin/sh -c #(nop) CMD ["bash"] 0B <missing> /bin/sh -c #(nop) ADD file:1dd78a123212328bd… 123MB文件大小是否已发生改变?
$ docker images | grep node- node-multi-stage 331b81a245b1 678MB node-vanilla 075d229d3f48 679MB最后一个镜像(node-multi-stage)更小一些。
你已经将镜像的体积减小了,即使它已经是一个很小的应用程序。
但整个镜像仍然很大!
有什么办法可以让它变得更小吗?
2. 用distroless去除容器中所有不必要的东西这个镜像包含了Node.js以及yarn、npm、bash和其他的二进制文件。因为它也是基于Ubuntu的,所以你等于拥有了一个完整的操作系统,其中包括所有的小型二进制文件和实用程序。
但在运行容器时是不需要这些东西的,你需要的只是Node.js。
Docker容器应该只包含一个进程以及用于运行这个进程所需的最少的文件,你不需要整个操作系统。
实际上,你可以删除Node.js之外的所有内容。
但要怎么做?
所幸的是,谷歌为我们提供了distroless。
以下是distroless存储库的描述:
“distroless”镜像只包含应用程序及其运行时依赖项,不包含程序包管理器、shell以及在标准Linux发行版中可以找到的任何其他程序。
这正是你所需要的!
你可以对Dockerfile进行调整,以利用新的基础镜像,如下所示:
FROM node:8 as build WORKDIR /app COPY package.json index.js ./ RUN npm install FROM gcr.io/distroless/nodejs COPY --from=build /app / EXPOSE 3000 CMD ["index.js"]你可以像往常一样编译镜像:
$ docker build -t node-distroless .这个镜像应该能正常运行。要验证它,可以像这样运行容器:
$ docker run -p 3000:3000 -ti --rm --init node-distroless现在可以访问:3000页面。
不包含其他额外二进制文件的镜像是不是小多了?
$ docker images | grep node-distroless node-distroless 7b4db3b7f1e5 76.7MB只有76.7MB!
比之前的镜像小了600MB!
但在使用distroless时有一些事项需要注意。
当容器在运行时,如果你想要检查它,可以使用以下命令attach到正在运行的容器上:
$ docker exec -ti <insert_docker_id> bashattach到正在运行的容器并运行bash命令就像是建立了一个SSH会话一样。
但distroless版本是原始操作系统的精简版,没有了额外的二进制文件,所以容器里没有shell!
在没有shell的情况下,如何attach到正在运行的容器呢?
答案是,你做不到。这既是个坏消息,也是个好消息。
之所以说是坏消息,因为你只能在容器中执行二进制文件。你可以运行的唯一的二进制文件是Node.js:
$ docker exec -ti <insert_docker_id> node