Docker chapter 6 镜像构建优化 - 依赖缓存 与 多阶段构建

old dockerfile

# syntax=docker/dockerfile:1FROM node:18-alpine
WORKDIR /app
RUN yarn install --production
COPY . .
CMD ["node", "src/index.js"]
EXPOSE 3000

# syntax=docker/dockerfile:1 是 Dockerfile 的一个解析器指令,它用于声明构建时使用的 Dockerfile 语法版本。

如果你不指定这个指令,BuildKit 将使用它内置的 Dockerfile 前端版本。声明一个语法版本可以让你自动使用最新的 Dockerfile 版本,而无需升级 BuildKit 或 Docker Engine,甚至可以使用自定义的 Dockerfile 实现。

大多数用户会将这个解析器指令设置为 docker/dockerfile:1,这会让 BuildKit 在构建前拉取 Dockerfile 语法的最新稳定版本。

在你的 Dockerfile 中,# syntax=docker/dockerfile:1 指令告诉 Docker 使用最新稳定版本的 Dockerfile 语法来解析和构建这个 Dockerfile。

note 1 :

 EXPOSE 3000  和 docker run -dp 127.0.0.1:3001:3000 getting-started-2  的关联

Dockerfile 中的 EXPOSE 指令只是声明了应用程序在容器内部监听的端口,它并不会自动映射这个端口到宿主机。如果你想让应用程序可以从宿主机访问,你需要在启动容器时使用 -p 或 --publish 参数来映射端口。

容器启动时映射的端口并不一定要和 EXPOSE 指令声明的端口相同。例如,你的 Dockerfile 中有 EXPOSE 3000,但你可以在启动容器时使用 -p xxxx:3000 来将容器的 3000 端口映射到宿主机的 xxxx 端口。

但是,如果你的应用程序在容器内部监听的端口和 EXPOSE 指令声明的端口不同,那么 EXPOSE 指令就没有意义了。因为 EXPOSE 指令的主要目的就是告诉使用这个镜像的人,应用程序在哪个端口提供服务。镜像就是一个模版,可以同时生成多个容器实例服务

这样就相当于你可以将启动多个主机端口 映射同样的实例服务

3001 -> 3000    3002 -> 3000 

 note 2 : caching of the dependencies

watching the old dockerFile command line 。 at some circumstance , we will recreated image when update code ,but it will download  dependencies again 。 that's  terrible , please following to optimize the dockerFile 。

# syntax=docker/dockerfile:1FROM node:18-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
CMD ["node", "server/test.js"]
EXPOSE 3000

原因 :

Once a layer changes, all downstream layers have to be recreated as well

一旦一个图层改变,所有的下游层都会重新构建 

Docker 使用一种称为层(layer)的概念来构建和存储镜像。每个 Dockerfile 指令都会创建一个新的层,并在此基础上进行下一步操作。这些层是只读的,但可以被后续的层修改。

Docker 会尽可能地使用缓存来加速镜像构建过程。当 Docker 构建镜像时,它会查看每个指令和之前构建的镜像层。如果 Docker 发现一个指令和一个已经缓存的层完全匹配,那么它就会使用这个缓存的层,而不是重新执行指令。

例如,如果你的 Dockerfile 的前两个指令是 FROM node:18-alpine 和 WORKDIR /app,并且你之前已经构建过一个使用相同指令的镜像,那么 Docker 就会使用这两个缓存的层。

但是,如果一个指令的上下文(例如,被复制的文件)发生了改变,那么 Docker 就不能使用缓存,而必须重新执行指令。这就是为什么在 Dockerfile 中,我们通常先复制 package.json 和 yarn.lock,然后运行 yarn install,最后再复制其余的文件。这样,即使源代码发生改变,只要依赖没有改变,yarn install 的步骤就可以使用缓存,从而加速构建过程。

 

如果指令不变,那么就会用缓存的老的 layer 

修改  /app 为  /gyk 后 ,/app 后的所有layer 全部失效。

 

 所以:

重新 build

 

note3   .dockerignore

 

.dockerignore 文件用于指定哪些文件或目录应该被 Docker 忽略,不应该被复制到镜像中。这与 .gitignore 文件的作用类似,但是用于 Docker。

在你提供的例子中,.dockerignore 文件的内容是:

node_modules

这意味着 node_modules 目录不会被复制到 Docker 镜像中。这是因为 node_modules 目录通常包含大量的文件,而且这些文件在构建过程中会被 yarn install 或 npm install 命令重新创建。因此,将 node_modules 目录复制到镜像中不仅会浪费空间,还可能导致问题,因为它可能会覆盖由 RUN 步骤创建的文件。

note 4  muti-stage builds 多阶段构建

多阶段构建(Multi-stage builds)是 Docker 提供的一种强大的工具,它允许你在一个 Dockerfile 中定义多个阶段来构建镜像。这有几个优点:

  1. 分离构建时依赖和运行时依赖:在构建阶段,你可能需要一些额外的工具和库来编译你的应用程序(例如,编译器,构建工具等)。但是在运行阶段,这些工具和库可能就不再需要了。通过使用多阶段构建,你可以在一个阶段安装和使用这些工具,然后在另一个阶段只复制你的应用程序和它需要的运行时依赖。

  2. 减少总体镜像大小:由于你只复制了应用程序和它的运行时依赖,所以最终的镜像会比包含所有构建工具和库的镜像小得多。这可以减少存储和网络传输的开销,使你的应用程序更快地启动,并且减少了安全风险,因为镜像中包含的组件更少。

下面是一个简单的多阶段构建的例子:

 

# 第一阶段:构建应用程序
FROM node:18-alpine AS build
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
RUN yarn build# 第二阶段:运行应用程序
FROM node:18-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY package.json yarn.lock ./
RUN yarn install --production
CMD ["node", "dist/index.js"]

在这个例子中,第一阶段使用 node:18-alpine 镜像来安装所有依赖并构建应用程序。然后,第二阶段使用同样的 node:18-alpine 镜像,但只复制了构建的应用程序和运行时依赖,并安装了这些运行时依赖。这样,最终的镜像就只包含了运行应用程序所需要的东西。

 

在 Dockerfile 中,WORKDIR /app 指令设置了工作目录为 /app。这意味着后续的指令(如 COPYRUN 等)都会在这个目录下执行。

在你提供的 Dockerfile 的第二阶段中,COPY --from=build /app/dist ./dist 这行指令的作用是从构建阶段(被命名为 build)的镜像中复制 /app/dist 目录到当前工作目录下的 dist 目录。

这里的 ./dist 是相对于当前的工作目录 /app 的,所以 ./dist 实际上就是 /app/dist

所以,这行指令的效果是将构建阶段生成的应用程序(位于 /app/dist)复制到最终镜像的 /app/dist 目录下。

然后,CMD ["node", "dist/index.js"] 这行指令在容器启动时会运行 /app/dist/index.js,也就是你刚刚复制过来的应用程序

React example

When building React applications, you need a Node environment to compile the JS code (typically JSX), SASS stylesheets, and more into static HTML, JS, and CSS. If you aren't doing server-side rendering, you don't even need a Node environment for your production build. You can ship the static resources in a static nginx container. 

# 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 buildFROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html

 

example:

# syntax=docker/dockerfile:1FROM node:18-alpine AS build
WORKDIR /gyk
COPY package.json yarn.lock ./ 
# 依赖文件不变,不会重新下载依赖,一旦变化,后面layer失效,重新下载依赖
RUN yarn install --production
COPY . .
# 如只改动源代码,则之后执行 COPY .. 后的 指令
CMD ["node", "server/test.js"]
EXPOSE 3044FROM nginx:alpine
COPY --from=build /gyk/. /usr/share/nginx/html
#/gyk/* 表示 gyk 目录下的所有文件和子目录,如果你想使用 . 来表示 gyk 目录下的所有内容,你可以直接写成 /gyk/.。这样,Docker 就会复制 gyk 目录下的所有文件和子目录,在 Dockerfile 中,COPY 指令不支持 ** 这种形式的通配符。** 通常在 shell 脚本或某些编程语言中用于匹配任意多级的子目录,但在 Dockerfile 的 COPY 指令中,这种语法是不被支持的

优化后 43.37 M 

在 Docker 的多阶段构建中,每个阶段都必须以 FROM 指令开始,这是 Dockerfile 语法的要求。FROM 指令用于指定基础镜像,如果你不指定基础镜像,Docker 就不知道如何创建新的镜像。

如果你的第二阶段不需要任何特定的镜像,你可以使用一个非常小的基础镜像,如 scratchscratch 是一个特殊的 Docker 镜像,它是空的,不包含任何文件。这通常用于创建非常小的镜像,只包含你的应用程序和它的运行时依赖。

 

note 5 :node:18-alpine 和 nginx:alpine 的 alpine 是什么意思

alpine 是一个轻量级的 Linux 发行版,它的设计目标是尽可能地减小体积。alpine 镜像通常只有 5MB 左右,相比其他的 Linux 发行版,如 Ubuntu 或 Debian,它的体积小很多。

在 Docker 中,alpine 通常用作基础镜像,用于构建更小的 Docker 镜像。例如,node:18-alpine 是一个包含 Node.js 18 版本和 Alpine Linux 的 Docker 镜像,nginx:alpine 是一个包含 Nginx 和 Alpine Linux 的 Docker 镜像。

使用 alpine 作为基础镜像的好处是可以减小最终 Docker 镜像的体积,这可以减少存储和网络传输的开销,使你的应用程序更快地启动,并且减少了安全风险,因为镜像中包含的组件更少

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/479929.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络基础入门指南

文章目录 网络分层模型OSI七层模型及其作用TCP/IP四层模型及作用为什么网络需要分层? 常见的网络协议应用层常见的协议传输层常见的协议网络层常见协议 从输入URL到页面展示的过程HTTP常见的状态码HTTP与HTTPS的区别HTTP是不保存状态的协议,如何保存用户…

FlinkCDC详解

1、FlinkCDC是什么 1.1 CDC是什么 CDC是Chanage Data Capture(数据变更捕获)的简称。其核心原理就是监测并捕获数据库的变动(例如增删改),将这些变更按照发生顺序捕获,将捕获到的数据,写入数据…

【机器学习】数据清洗——基于Numpy库的方法删除重复点

🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:机器学习 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进…

代码随想录算法训练营day20

题目:530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先 参考链接:代码随想录 530.二叉搜索树的最小绝对差 思路:我一开始想到的方法是先生成中序序列,然后对相邻两项的差进行计算,取…

STM32使用软件SPI协议操作TFT18彩屏

时间记录:2024/2/20 一、SPI协议介绍 (1)SPI设备通过4根线进行通信,CS片选线,选择从设备,SCK时钟线,由主设备产生时钟,主机MOSI线连从机MISO线,由主机向从机发送信息&am…

Softing OPC UA SIS(安全集成服务器)最新版本集成了MQTT协议

Softing工业自动化的安全集成服务器软件(Secure Integration Server, SIS)最新版本新增了MQTT协议支持,为IT/OT云应用数据集成提供了更多的连接方案以及更高的安全性。 (MQTT强化了安全集成服务器安全性和连接功能) So…

阿里云服务器租用价格,2024年新版活动报价明细表

2024年阿里云服务器租用价格表更新,云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年,轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

Sample Pairing(ICLR 2018)

paper:Data Augmentation by Pairing Samples for Images Classification 本文的创新点 本文提出了一种新的应用于图像分类的数据增强方法SamplePairing,这种简单的数据增强技术显著提高了所有测试的数据集的分类精度。此外当训练集中的样本数量非常少…

[极客挑战2019]HTTP

这道题考察的是http请求头字段的含义和使用; 具体如下 Referer:来源地址 User-Agent:客户端配置信息:浏览器类型、版本、系统类型等 X-Forwarded-For:代理地址,即数据发出的地址 开始解题:(对我这初学者真的烧脑&a…

嵌入式学习第十九天!(时间获取、文件属性和权限的获取、软链接和硬链接)

时间获取: 1. time time_t time(time_t *tloc); 功能:返回1970-01-01到现在的秒数(格林威治时间) 参数: tloc:存放秒数空间首地址 返回值: 成功返回秒数 失败返回-1 2. localtime struct tm *localtime(const tim…

JavaScript中手动实现Array.prototype.map方法

在前端开发中,我们经常需要对数组进行操作和处理。在JavaScript中,数组是常用的数据类型之一。而数组的map方法可以将一个数组中的每个元素都进行某种操作,并返回一个新的数组。今天,我们就来手动实现JavaScript中数组原型的map方…

System Verilog浅学——1.二进制和运算符

材料来源:B站up:Tan-Yifan 【SystemVerilog常用语法简介】https://www.bilibili.com/video/BV1XA41177of?p14&vd_source1a46c7af8e528520d93f15dd5c760634 二进制 常量 格式:二进制位宽进制符号(b:2;h:16;d:10)数据 1b1 …