查看“Docker镜像构建最佳实践”的源代码
←
Docker镜像构建最佳实践
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
== 镜像分层 == 使用docker image history命令,您可以查看创建镜像中的每个层的命令。 <ol style="list-style-type: decimal;"> <li><p>使用docker image history命令查看您创建的getting-started镜像的层。</p> <pre> docker image history getting-started</pre></li> <li><p>您应该会得到类似以下的输出。</p> <pre> IMAGE CREATED CREATED BY SIZE COMMENT a78a40cbf866 18 seconds ago /bin/sh -c #(nop) CMD ["node" "src/index.j… 0B f1d1808565d6 19 seconds ago /bin/sh -c yarn install --production 85.4MB a2c054d14948 36 seconds ago /bin/sh -c #(nop) COPY dir:5dc710ad87c789593… 198kB 9577ae713121 37 seconds ago /bin/sh -c #(nop) WORKDIR /app 0B b95baba1cfdb 13 days ago /bin/sh -c #(nop) CMD ["node"] 0B <missing> 13 days ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B <missing> 13 days ago /bin/sh -c #(nop) COPY file:238737301d473041… 116B <missing> 13 days ago /bin/sh -c apk add --no-cache --virtual .bui… 5.35MB <missing> 13 days ago /bin/sh -c #(nop) ENV YARN_VERSION=1.21.1 0B <missing> 13 days ago /bin/sh -c addgroup -g 1000 node && addu… 74.3MB <missing> 13 days ago /bin/sh -c #(nop) ENV NODE_VERSION=12.14.1 0B <missing> 13 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 13 days ago /bin/sh -c #(nop) ADD file:e69d441d729412d24… 5.59MB </pre> <p>每行代表镜像中的一个层。此处显示底部为基础层,顶部为最新的层。使用此信息,您还可以快速查看每个层的大小,帮助诊断大型镜像。</p> <p>您会注意到,几行被截断了。如果您添加–no-trunc标志,您将获得完整的输出。</p> <pre> docker image history --no-trunc getting-started</pre></li></ol> == 层缓存 == 现在您已经看到了分层的工作原理,有一个重要的教训可以帮助减少构建容器镜像的时间。一旦一个层发生变化,所有下游层也必须重新创建。 看一下您为入门应用程序创建的以下Dockerfile。 <pre># syntax=docker/dockerfile:1 FROM node:18-alpine WORKDIR /app COPY . . RUN yarn install --production CMD ["node", "src/index.js"]</pre> 回顾一下镜像历史输出,您会看到Dockerfile中的每个命令都成为镜像中的一个新层。您可能还记得,当您对镜像进行更改时,必须重新安装yarn依赖项。每次构建时都固定包含相同的依赖项是没有多大意义的。 为了解决这个问题,您需要重新构建Dockerfile以支持依赖项的缓存。对于基于Node的应用程序,这些依赖项在package.json文件中定义。您可以首先只复制该文件,安装依赖项,然后再复制其他所有内容。然后,只有在package.json发生更改时才重新创建yarn依赖项。 <ol style="list-style-type: decimal;"> <li><p>更新Dockerfile,首先复制package.json,在安装依赖项,然后再复制其他所有内容。</p> <pre> # syntax=docker/dockerfile:1 FROM node:18-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --production COPY . . CMD ["node", "src/index.js"]</pre></li> <li><p>在与Dockerfile相同的文件夹中创建一个名为.dockerignore的文件,并包含以下内容。</p> <pre> node_modules</pre> <p>.dockerignore文件是一种选择性地仅复制与镜像相关的文件的简便方法。在这种情况下,第二个COPY步骤应该省略node_modules文件夹,因为否则它可能会覆盖由RUN步骤中的命令创建的文件。</p></li> <li><p>使用docker build构建一个新的镜像。</p> <pre> docker build -t getting-started .</pre> <p>您应该会看到以下输出。</p> <pre> [+] Building 16.1s (10/10) FINISHED => [internal] load build definition from Dockerfile => => transferring dockerfile: 175B => [internal] load .dockerignore => => transferring context: 2B => [internal] load metadata for docker.io/library/node:18-alpine => [internal] load build context => => transferring context: 53.37MB => [1/5] FROM docker.io/library/node:18-alpine => CACHED [2/5] WORKDIR /app => [3/5] COPY package.json yarn.lock ./ => [4/5] RUN yarn install --production => [5/5] COPY . . => exporting to image => => exporting layers => => writing image sha256:d6f819013566c54c50124ed94d5e66c452325327217f4f04399b45f94e37d25 => => naming to docker.io/library/getting-started</pre></li> <li><p>现在,对src/static/index.html文件进行更改。例如,将</p> <title> <p>更改为”The Awesome Todo App”。</p></li> <li><p>现在再次使用docker build -t getting-started .构建Docker镜像。这次,您的输出应该稍有不同。</p> <pre> [+] Building 1.2s (10/10) FINISHED => [internal] load build definition from Dockerfile => => transferring dockerfile: 37B => [internal] load .dockerignore => => transferring context: 2B => [internal] load metadata for docker.io/library/node:18-alpine => [internal] load build context => => transferring context: 450.43kB => [1/5] FROM docker.io/library/node:18-alpine => CACHED [2/5] WORKDIR /app => CACHED [3/5] COPY package.json yarn.lock ./ => CACHED [4/5] RUN yarn install --production => [5/5] COPY . . => exporting to image => => exporting layers => => writing image sha256:91790c87bcb096a83c2bd4eb512bc8b134c757cda0bdee4038187f98148e2eda => => naming to docker.io/library/getting-started</pre> <p>首先,您应该注意到构建速度更快了。而且,您会看到有几个步骤正在使用先前缓存的层。推送和拉取此镜像以及对其进行更新也将更快。</p></li></ol> == 多阶段构建 == 多阶段构建是一种非常强大的工具,可以使用多个阶段来创建镜像。它们具有以下几个优势: * 将构建时依赖与运行时依赖分离 * 通过仅打包应用程序运行所需的内容来减小镜像大小 <span id="maventomcat示例"></span> === Maven/Tomcat示例 === 在构建基于Java的应用程序时,您需要JDK将源代码编译为Java字节码。但是,该JDK在生产环境中是不需要的。此外,您可能会使用Maven或Gradle等工具来帮助构建应用程序。在最终镜像中也不需要这些工具。多阶段构建可以帮助解决这个问题。 <pre># syntax=docker/dockerfile:1 FROM maven AS build WORKDIR /app COPY . . RUN mvn package FROM tomcat COPY --from=build /app/target/file.war /usr/local/tomcat/webapps </pre> 在此示例中,您使用一个阶段(称为build)来使用Maven执行实际的Java构建。在第二个阶段(从FROM tomcat开始),您从构建阶段复制文件。最终镜像只是最后一个阶段的创建结果,可以使用–target标志进行覆盖。 <span id="react示例"></span> === React示例 === 在构建React应用程序时,您需要一个Node环境来将JS代码(通常是JSX)、SASS样式表等编译为静态HTML、JS和CSS。如果您不进行服务器端渲染,甚至在生产构建中也不需要Node环境。您可以将静态资源放入一个静态的nginx容器中。 <pre># syntax=docker/dockerfile:1 FROM node:18 AS build WORKDIR /app COPY package* yarn.lock ./ RUN yarn install COPY public ./public COPY src ./src RUN yarn run build FROM nginx:alpine COPY --from=build /app/build /usr/share/nginx/html</pre> 在上一个Dockerfile示例中,它使用node:18镜像执行构建(最大化层缓存),然后将输出复制到一个nginx容器中。
返回至“
Docker镜像构建最佳实践
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
基础知识
正则表达式
Markdown
分布式
项目管理
系统集成项目管理基础知识
云原生
Docker
云原生安全
云原生词汇表
十二因素应用
Kubernetes
音频处理
音频合成
Edge-tts
CMS系统
Docsify
VuePress
Mediawiki
自动生成
Marp
CI/CD
GitLab
设计
颜色
平面设计
AI
数字人
操作系统
GNU/Linux
数据库
Mysql
工具
链入页面
相关更改
特殊页面
页面信息