我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Node.js项目中怎么优化docker镜像

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Node.js项目中怎么优化docker镜像

这篇文章给大家介绍Node.js项目中怎么优化docker镜像,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

Node 项目

简单写了一个自己用的 wechat-bot ,接下来就以这个项目演示怎么去优化 Docker 镜像

以下是我没有仔细研究 Docker 刚开始写的 Dockerfile 文件

FROM node:14.17.3

# 设置环境变量
ENV NODE_ENV=production
ENV APP_PATH=/node/app

# 设置工作目录
WORKDIR $APP_PATH

# 把当前目录下的所有文件拷贝到镜像的工作目录下 .dockerignore 指定的文件不会拷贝
COPY . $APP_PATH

# 安装依赖
RUN yarn

# 暴露端口
EXPOSE 4300

CMD yarn start

build 之后,如下图,我这个简单的 Node 程序镜像竟然有 1G 多,接下来我们将逐步去优化减少这个大小

Node.js项目中怎么优化docker镜像

优化前言

在优化之前,有些东西我们必须了解,解决问题的第一步就是先找出导致问题的原因

  • Dockerfile 文件,其内包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层如何构建

  • Docker 镜像并非只是一个文件,而是由一堆文件组成,最主要的文件是 (Layers)

    参考资料:docker 镜像分层原理

    • 镜像构建时,会一层层构建,前一层是后一层的基础

      每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像

    • 镜像层将会被缓存和复用(这也是从第二次开始构建镜像时,速度会快的原因,优化镜像构建速度的原理也是利用缓存原理来做)

    • 当 Dockerfile 的指令修改了,操作的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效

      docker build 的缓存机制,docker 是怎么知道文件变化的呢?

      Docker 采取的策略是:获取 Dockerfile 下内容(包括文件的部分 inode 信息),计算出一个唯一的 hash 值,若 hash 值未发生变化,则可以认为文件内容没有发生变化,可以使用缓存机制,反之亦然。

    • 某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效

    • 镜像的每一层只记录文件变更,在容器启动时,Docker 会将镜像的各个层进行计算,最后生成一个文件系统

      当我知道这点时,我恍然大悟,我们使用的操作系统,比如安卓、ios、win、mac 等,其实就是一个文件系统,我们的软件界面交互等,其实就是在读写文件,我们网页写个弹框,操作 dom,就是在读写本地文件或者是读写内存里的数据,个人的一些见解不知道对不对,本人非科班出身的前端 coder

优化 Dockerfile

优化第一层 FROM node:14.17.3

方案一:使用 node 的 Alpine 版本

这也是绝多数人知道的优化镜像手段,Alpine 是一个很小的 Linux 发行版,只要选择 Node 的 Alpine 版本,就会有很大改进,我们把这一句改成指令改成 FROM node:14.17.4-alpine (可以去 dockerhub 查看 node 有哪些版本标签),build 后镜像大小如下图,瞬间从 1.06G 降到 238M,可以说是效果显著

Node.js项目中怎么优化docker镜像

还可以使用其它的基础小镜像,比如 mhart/alpine-node,这个还能再小,改成 FROM mhart/alpine-node:14.17.3 再试试,可以看到又小了 5M ,虽然不多,但是秉着能压榨一点是一点的“老板原则”,积少成多,极致压榨

Node.js项目中怎么优化docker镜像

方案二:使用纯净 Alpine 镜像手动装 Node

既然 Alpine 是最小的 Linux,那我们试下用纯净的 Alpine 镜像,自己再装 Node 试试

FROM alpine:latest

# 使用 apk 命令安装 nodejs 和 yarn,如果使用 npm 启动,就不需要装 yarn
RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0

# ... 后面的步骤不变

build 后看下图,只有 174M 了,又小了不少

Node.js项目中怎么优化docker镜像

结论就是不嫌麻烦追求极致就用方案二,从 1.06G 减少到 174M

减少层数、不经常变动的层提到前面去

  • ENV 指令是可以一次性设置多个环境变量,能一次指令执行完,就不用两次,多一个指令就多一层

  • EXPOSE 指令是暴露端口,其实也可以不用写这个指令,在启动容器的时候自己映射端口,如果写了这个指令的话,因为端口不经常变,所以把这个指令提前,写上这个指令有两个好处:

    至于写还是不写,看个人吧,我个人一般不写,因为我在项目启动命令会指定项目端口,启动容器的时候映射出来就好,这样我就要维护一个地方,Dockerfile 也写了的话,项目端口变了,这里也要修改,多了点维护成本,当然也有办法让两边端口变量取自配置文件,只要改配置文件即可

    • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射

    • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口

下面是改写后的 Dockerfile

FROM alpine:latest

# 使用 apk 命令安装 nodejs 和 yarn,如果使用 npm 启动,就不需要装 yarn
RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0

# 暴露端口
EXPOSE 4300

# 设置环境变量
ENV NODE_ENV=production \
    APP_PATH=/node/app

# 设置工作目录
WORKDIR $APP_PATH

# 把当前目录下的所有文件拷贝到镜像的工作目录下 .dockerignore 指定的文件不会拷贝
COPY . $APP_PATH

# 安装依赖
RUN yarn

# 启动命令
CMD yarn start

这一步的优化,无论从镜像大小还是构建镜像速度都看不到明显的差别,因为改动的层内容少(体现不出来),但是可以查看到镜像的层是变少了的,可以自行试试查看镜像的层试试

减少镜像层数是“好老板”的传统优良习惯,不让“员工”浪费资源

package.json 提前提高编译速度

从下图可以看到每次我们 build 的时候最耗时的就是在执行 yarn 命令装依赖的时候,大部分时候我们只是改代码,依赖不变,这时候如果可以让这一步缓存起来,依赖没有变化的时候,就不需要重新装依赖,就可以大大改进编译速度

Node.js项目中怎么优化docker镜像

前面我们说了镜像构建时,是一层层构建,前一层是后一层的基础,既然是这样的话,我们就把 package.json 文件单独提前拷贝到镜像,然后下一步装依赖,执行命令装依赖这层的前一层是拷贝 package.json 文件,因为安装依赖命令不会变化,所以只要 package.json 文件没变化,就不会重新执行 yarn 安装依赖,它会复用之前安装好的依赖,原理讲清楚了,下面我们看效果

改变后的 Dockerfile 文件

FROM alpine:latest

# 使用 apk 命令安装 nodejs 和 yarn,如果使用 npm 启动,就不需要装 yarn
RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0

# 暴露端口
EXPOSE 4300

# 设置环境变量
ENV NODE_ENV=production \
    APP_PATH=/node/app

# 设置工作目录
WORKDIR $APP_PATH

# 拷贝 package.json 到工作跟目录下
COPY package.json .

# 安装依赖
RUN yarn

# 把当前目录下的所有文件拷贝到镜像的工作目录下 .dockerignore 指定的文件不会拷贝
COPY . .

# 启动命令
CMD yarn start

build 看下图,编译时间从 29.6s 到 1.3s,使用了缓存的层前面会有个 CACHED 字眼,仔细看下图可以看到

Node.js项目中怎么优化docker镜像

使用多阶段构建再次压榨镜像大小

多阶段构建这里不多说了,不了解的可以先搜相关资料了解

因为我们运行 node 程序是只需要生产的依赖和最终 node 可以运行的文件,就是说我们运行项目只需要 package.js 文件里 dependencies 里的依赖,devDependencies 依赖只是编译阶段用的,比如 eslint 等这些工具在项目运行时是用不到的,再比如我们项目是用 typescript 写的,node 是不能直接运行 ts 文件,ts 文件需要编译成 js 文件,运行项目我们只需要编译后的文件和 dependencies 里的依赖就可以运行,也就是说最终镜像只需要我们需要的东西,任何其他东西都可以删掉,下面我们使用多阶段改写 Dockerfile

# 构建基础镜像
    FROM alpine:3.14 AS base

    # 设置环境变量
    ENV NODE_ENV=production \
        APP_PATH=/node/app
    
    # 设置工作目录
    WORKDIR $APP_PATH

    # 安装 nodejs 和 yarn
    RUN apk add --no-cache --update nodejs=14.17.4-r0 yarn=1.22.10-r0

# 使用基础镜像 装依赖阶段
    FROM base AS install

    # 拷贝 package.json 到工作跟目录下
    COPY package.json ./

    # 安装依赖
    RUN yarn

# 最终阶段,也就是输出的镜像是这个阶段构建的,前面的阶段都是为这个阶段做铺垫
    FROM base

    # 拷贝 装依赖阶段 生成的 node_modules 文件夹到工作目录下
    COPY --from=install $APP_PATH/node_modules ./node_modules

    # 将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入镜像的工作目录下
    COPY . .

    # 启动
    CMD yarn start

细心的朋友会发现我这里有指定 alpine 版本,而上面都是用的 latest 版本,因为就在刚刚发现有个坑需要注意下,就是我们选择 alpine 版本的时候,最好不要选择 latest 版本,因为后面要装的软件版本可能会在 alpine 的 latest 版本没有对应软件的版本号,就会安装错误,我刚刚就翻车了,点击查看 alpine 版本下的包信息

Node.js项目中怎么优化docker镜像

build 后,我们看看镜像大小,上次的是 174M 再次降到 73.4M,极致压榨。镜像:”放过我把,我真的没有了“

Node.js项目中怎么优化docker镜像

讲解:

我把这个构建分成了三个阶段:

  • 第一阶段:构建基础镜像

    安装依赖、编译、运行等等阶段,就是所有阶段共用的东西都在第一阶段封到一个基础镜像里供其它阶段使用,比如设置环境变量、设置工作目录、安装 nodejs、yarn 等等

  • 第二阶段:装依赖阶段

    在这个阶段,装依赖,如果项目需要编译,可以在这个阶段装依赖编译好

    这里在说下装依赖的小细节,就是执行 yarn --production 加个 production 参数或者环境变量 NODE_ENVproduction,yarn 将不会安装 devDependencies 中列出的任何软件包,点我查看官方文档说明,因为我设置了环境变量所以就没加这个参数

  • 第三阶段:最终使用镜像

    拷贝第二阶段安装的好的依赖文件夹,然后在拷贝代码文件到工作目录,执行启动命令,第二阶段装依赖多出的一些垃圾我们不需要,我们就只拷贝我们要用的东西,大大减少镜像的大小

    如果项目需要编译,在拷贝编译后的文件夹,不需要拷贝编译前的代码,有编译后的代码和依赖就可以跑起项目

多阶段构建,最后生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中的文件拷贝到后边的阶段中,这就是多阶段构建的最大意义。

关于Node.js项目中怎么优化docker镜像就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Node.js项目中怎么优化docker镜像

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

docker-compose镜像怎么发布springboot项目

这篇文章主要介绍了docker-compose镜像怎么发布springboot项目的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇docker-compose镜像怎么发布springboot项目文章都会有所收获,
2023-06-08

Docker怎么部署Go项目发布镜像到仓库

这篇文章主要介绍“Docker怎么部署Go项目发布镜像到仓库”,在日常操作中,相信很多人在Docker怎么部署Go项目发布镜像到仓库问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Docker怎么部署Go项目发
2023-07-05

怎么选择一个最好的Node.js Docker镜像

这篇文章主要介绍“怎么选择一个最好的Node.js Docker镜像”,在日常操作中,相信很多人在怎么选择一个最好的Node.js Docker镜像问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么选择一个最
2023-07-04

Docker中怎么样制作镜像

小编给大家分享一下Docker中怎么样制作镜像,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言以制作CentOS镜像为例,讲述对镜像自定义,打包以及推送的远程仓
2023-06-25

docker中镜像的commit怎么用

这篇文章将为大家详细讲解有关docker中镜像的commit怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 docker commit:表示提交容器副本使之成为一个新的镜像。假设我们在dock
2023-06-04

Docker镜像构建中docker commit怎么使用

这篇“Docker镜像构建中docker commit怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Docker镜像
2023-06-29

docker中怎么用build制作镜像

在Docker中,可以使用`docker build`命令来制作镜像。首先,在项目的根目录下创建一个名为`Dockerfile`的文件,它包含了构建镜像的指令。在`Dockerfile`中,可以指定基础镜像、复制文件、安装软件包、设置环境
2023-10-26

idea怎么快速实现将SpringBoot项目打包Docker镜像并部署

这篇文章主要介绍了idea怎么快速实现将SpringBoot项目打包Docker镜像并部署的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇idea怎么快速实现将SpringBoot项目打包Docker镜像并部署文
2023-06-30

ubuntu镜像下载太慢怎么优化

如果你在下载Ubuntu镜像时速度很慢,可以尝试以下几种优化方法:1. 使用国内镜像源:Ubuntu官方提供了多个全球镜像站点,你可以尝试选择一个位于你所在地区的镜像站点,以获得更快的下载速度。可以在Ubuntu官方网站上的“下载”页面查找
2023-09-08

python flask项目打包成docker镜像发布的方法是什么

这篇文章主要介绍了python flask项目打包成docker镜像发布的方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python flask项目打包成docker镜像发布的方法是什么文章都会有所收
2023-07-05

Ubuntu中怎么配置Docker-CE镜像加速

Ubuntu中怎么配置Docker-CE镜像加速,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。实验环境操作系统:Ubuntu 18.04.4 LTSLAN IP :192.
2023-06-05

将本地Python项目打包成docker镜像,上传到服务器,在docker中运行

文章目录 Docker环境创建虚拟环境pycharm使用虚拟环境准备打包保存为镜像文件拆分文件、合并文件加载镜像文件启动容器进入容器退出容器复制物理路径到容器指定路径 参考文献 Docker环境 windows11Docke
2023-08-18

docker容器中怎么创建一个MariaDB镜像

docker容器中怎么创建一个MariaDB镜像,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。基于commit命令方式创建docker的安装[root@test01 ~]#
2023-06-04

Node.js中怎么部署项目的选项

这篇文章主要讲解了“Node.js中怎么部署项目的选项”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Node.js中怎么部署项目的选项”吧!一:使用Node.js内置的HTTP模块Node.
2023-07-05

docker容器中怎么创建一个SSH服务镜像

docker容器中怎么创建一个SSH服务镜像,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。基于commit命令方式创建docker的安装[root@test01
2023-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录