当前位置: 首页 > 后端技术 > Node.js

Node.jsdocker镜像大小优化实践

时间:2023-04-03 14:10:33 Node.js

关注作者github一道每日面试题详解你讨厌长期部署你的应用吗?对于单个容器,超过GB并不是最佳做法。每次我们部署新版本时都要处理千兆字节,这对我们来说并不合适。本文将展示如何通过Nodejs程序通过几个简单的步骤优化Docker镜像,使其更小、更快、更适合生产环境。一个简单的Node.js项目首先基于express写一个简单的web服务器程序//package.json{"name":"docker-test","version":"1.0.0","description":"","main":"app.js","scripts":{"start":"nodeapp"},"author":"","license":"ISC","dependencies":{"express":"^4.16.4"},"devDependencies":{"eslint":"^5.16.0"}}//app.jsconstexpress=require('express')constapp=express()app.get('/',function(req,res){res.send('helloworld')})app.listen(3000)在根目录新建一个Dockerfile,写入如下代码#DockerfileFROMnodeCOPY。/home/appRUNcd/home/app&&npminstallWORKDIR/home/appCMD['npm','start']执行dockerbuild-tmyapp.dockerimages![结果](https://i.loli.net/2019/04/10...)可以看到本节最简单的nodejs程序是920MB,请不要做。接下来我们将逐渐减小此图像的体积。优化docker生产图像使用Node.jsAlpine图像大幅减小图像大小的最简单和最快的方法是选择一个小得多的基础图像。Alpine是一个小型的Linux发行版,可以完成这项工作。只需选择Node.js的Alpine版本,您就会看到巨大的改进。从节点:高山复制。/home/appRUNcd/home/app&&npminstallWORKDIR/home/appCMD['npm','start']build之后可以看到足足减少了800MB,这是一个非常大的优化。开发的依赖包在生产环境没有打包,但是我们可以继续优化。我们正在安装所有依赖项,即使我们最终只需要构建依赖项。如果只打包生产环境,就没那么好了,继续完善吧。从节点:高山复制。/home/appRUNcd/home/app&&npminstall--productionWORKDIR/home/appCMD['npm','start']构建后我们又砍掉了6MB,因为我们只有一个开发依赖,可以想象这个在正常项目中将是一个非常大的优化。使用基础版的Alpine镜像结合Nodejs如果我们使用基础版的Alpine镜像,自己安装Nodejs会怎么样呢?FROMalpine:latestRUNapk添加--no-cache--updatenodejsnodejs-npmCOPY。/home/appRUNcd/home/app&&npminstall--productionWORKDIR/home/appCMD['npm','start']构建后只剩下65MB,相比之前减少了10多倍开始。Docker镜像的多阶段构建是分层的,Dockerfile中的每条指令都会创建一个新的镜像层,可以重复使用和缓存。当Dockerfile的指令被修改,复制的文件发生变化,或者构建镜像时指定的变量不同,相应的镜像层缓存就会失效。所以我们也可以合并RUN指令,但是需要记住,我们只能合并变化频率相同的指令。我们应该将变化最少的部分放在Dockerfile的最前面,这样才能充分利用镜像缓存。通过最小化图像层数,我们可以获得更小的图像。在上面的例子中,源码会经常变动,每次构建镜像都需要重新安装npm模块,这显然不是我们希望看到的。所以我们可以先拷贝package.json,再安装npm模块,最后只拷贝剩下的源码。这样即使源代码发生变化,也不需要重新安装npm模块。从alpineASbuilderWORKDIR/home/appRUNapkadd--no-cache--updatenodejsnodejs-npmCOPYpackage.jsonpackage-lock.json./RUNnpminstall--productionFROMalpineWORKDIR/home/appRUNapk添加--no-cache--updatenodejsnodejs-npmCOPY--from=builder/usr/src/app/node_modules./node_modulesCOPY。.CMD['npm','start']最终的镜像只有51MB,相比开始时,缩小了大约17倍!并且后续的构建速度也大大提升。每条FROM指令为一个构造阶段,多个FROM为多阶段构造。虽然最终生成的图像只能是上一阶段的结果,但是可以将前一阶段的文件复制到后一阶段。这是多阶段建设的最大意义。在上面的Dockerfile中,我们先复制了package.json,然后npminstall。在第二阶段的构建中,我们直接复制了第一阶段下载的node_moduls。在下一次构建时,如果没有新的依赖,docker会使用缓存中的node_modules,减少部署时间。使用dockerinspectimageId命令可以看到,虽然我们有多个指令,但是最终的镜像只有5层,这就是层共享机制。使用多阶段构建可以充分利用Docker镜像的缓存,大大减少最终部署到生产环境的时间。结论在真实的生产环境中,没有理由使用gb大小的图像。如果你真的需要提高部署速度并且被缓慢的CI/CD所困扰,多阶段构建将是一个非常有用的方法。希望这篇简短的文章对任何考虑使用Docker进行基于Node.js的应用程序开发或部署的人有所帮助。查看原文关注github上一道日常面试题的详解