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

《上篇》面向Javascript开发者的Docker介绍(基于Node.js)

时间:2023-04-03 11:38:53 Node.js

Docker的开源应用容器引擎,如果你是后端开发者,相信你应该了解或熟悉这项技术,而对于很多前端开发者可能只是停留在听的阶段,根本不知道它是什么?或者认为这是一个后端技术,我不需要知道,比如我真的不知道它是什么,但是如果你想成为高级前端,这部分空缺需要被填满。咸鱼也是有梦想的,说不定哪天也能跳龙门呢!本文将通过使用Web前端代码和mongoDB数据库构建全栈node.js应用程序来了解有关Docker及其用途的更多信息。什么是DockerDocker是一个开源的应用容器引擎,基于Go语言,遵循Apache2.0协议开源。Docker允许开发人员将他们的应用程序和依赖项打包到一个轻量级、可移植的容器中,然后将其发布到任何流行的Linux、Window机器上,或者实现虚拟化。不懂,能简单介绍一下Docker的前世今生吗?2010年,几位年轻的IT专业人士在美国旧金山成立了一家名为dotCloud(容器技术)的公司。结果坚持不下来,就开源了,火了,火了,我又改名了,于是Docker就出现了。Docker出现之前如何模拟隔离的系统环境?答案就是虚拟机,大家应该都不陌生。许多开发人员会在他们的计算机中安装VMWare。通过它,我们可以创建几台子电脑,一台是Windows11,一台是CentOS,还有我最喜欢的QQ、微信等软件。多台子机相互隔离,互不影响,好开心!但是动不动就几G,几十G,磁盘承受不了,启动慢。前面提到,在Docker出现之前,虚拟机以环境隔离为业界网红,但弊端严重,而Docker容器技术其实是一种虚拟化技术,轻、快、集成,而且只需要MB级别即使是KB级别,不像虚拟机需要模拟一个操作系统,Docker只需要虚拟出一个小规模的环境(类似“沙箱”)。不行,要看数据对比,我相信,整理...上一节Docker的核心概念,我们了解到Docker是一种容器虚拟化技术,更轻量级、更快、更容易集成。Next在我们快速了解了它的核心概念之后,我们将进入今天的主题,并在编写代码时更好地理解它。Docker的三个核心概念:镜像(Image)、容器(Container)、仓库(Repository)。上面的关系图可以体现三者的关系。它本身不是容器,它是创建容器的工具和应用程序容器引擎。镜像,又称Docker镜像,是一种特殊的文件系统。除了提供容器运行时所需的程序、库、资源、配置等文件外,还包括一些为运行时准备的配置参数(如环境变量),镜像不包含任何动态数据。我们可以有很多个镜像,我们想把它们保存起来,然后我们可以在任何地方使用它们来创建一个容器环境,那么我们就需要一个仓库来存储,这就是Docker仓库。如果有这样一个仓库,是不是每个人都可以在里面存图片呢?不会,如果存了一个有问题的镜像,创建容器的时候不会挂掉吗?所以需要有一个角色负责管理Docker镜像,也就是DockerRegistry服务(类似于仓库管理员)。官方还提供了一个公共的Registry服务,就是DockerHub(有点像我们的npmmarket),里面存放着很多高质量的官方镜像。同时我们也可以通过Dockfile文件来自定义我们的镜像,后面会介绍。通过上面的介绍,相信大家应该对Docker有了一个大概的了解。下面是一些常用的Docker命令,#Container$dockerrun//创建并启动容器$dockerstart//启动容器$dockerps//查看容器$dockerstop//终止容器$dockerrestart//查看容器$dockerattach//进入容器$dockerexec//查看容器$dockerexport//导出容器$dockerimport//导入容器快照$dockerrm//移除容器$dockerlog//查看日志#image$dockersearch//检索图像$dockerpull//获取图像$dockerimages//列出图像$dockerimagels//列出图像$dockerrmi//删除图像$dockerimagerm//删除图像$dockersave//导出镜像$dockerload//导入镜像#Dockfile自定义镜像和常用命令$dockerbuild//构建镜像$dockerrun//运行镜像COPY//复制文件ADD//高级复制CMD//容器启动命令ENV//环境变量EXPOSE//暴露接口#Service$docker-v//查看docker的简要信息$docker-version//查看docker版本的详细信息$systemctlstartdocker//启动docker$systemctlstopdocker//关闭docker$systemctlenabledocker//设置开机启动$servicedockerrestart//重启docker服务$servicedockerstop//关闭要创建一个带有docker服务的Hello-World容器,首先需要下载Docker下载地址。我下载了WindowDockerDesktop。接下来检查版本信息是否下载成功。我下载了版本为20.10.11然后拉取DockerHub官方的hello-world镜像,创建并执行容器,这样我们的第一个容器就创建好了,可以使用上面提到的命令行dockerimagels/dockerimageprune来查看或删除无用镜像(容器停止时不会删除,有利于下次下载安装速度),可以多试试命令!创建一个Node程序接下来,我们将创建一个Node程序,在后面的教程介绍中都会用到。具体代码细节不再介绍。您可以检查以下server.js和package.json:constexpress=require("express");constapp=express();constport=8080;app.get("/",async(req,res)=>{res.setHeader("Content-Type","text/html");res.status(200);res.send("

Hello!前端晚间课程

");});app.listen(port,()=>{console.log(`示例应用监听http://localhost:${port}`);});{"name":"docker-example","version":"1.0.0","description":"","main":"server.js","scripts":{"start":"nodemonserver.js"},"author":"前端晚间课","license":"ISC","dependencies":{"express":"^4.17.2"},"devDependencies":{"nodemon":"^2.0.15"}}运行npmrunstart,运行成功...不同Node版本的问题对于上面的server.js文件,我们添加以下代码://...constmyPromise=newPromise((resolve,reject)=>{setTimeout(()=>{resolve("good");},300);reject("bad");});myPromise.then(()=>{console.log("thiswillneverrun");});然后分别在Node<15和Node>=15运行,结果会得到两个不同的结果,Node<15(node:764)UnhandledPromiseRejectionWarning:somethinghappened(Use`node--trace-warnings...`toshowwherethewarningwascreated)(node:764)UnhandledPromiseRejectionWarning:UnhandledPromiseRejectionWarning:未处理的承诺拒绝。这个错误要么是在没有catch块的情况下在异步函数内部抛出,要么是因为拒绝了一个没有用.catch()处理的承诺。要在未处理的promise拒绝时终止节点进程,请使用CLI标志`--unhandled-rejections=strict`(参见https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode)。(拒绝ID:2)(节点:764)[DEP0018]DeprecationWarning:未处理的承诺拒绝已弃用。将来,未处理的承诺拒绝将以非零终止Node.js进程exitcode.Node>=15node:internal/process/promises:218triggerUncaughtException(err,true/*fromPromise*/);^[UnhandledPromiseRejection:此错误源于在没有catch块的情况下在异步函数内部抛出,或者拒绝未使用.catch()处理的承诺。promiserejectedwithreason"recipecouldnotbegenerated".]{code:'ERR_UNHANDLED_REJECTION'}会发现两个版本的执行结果会不一致,高版本(Node>=15)会直接crash程序(ERR_UNHANDLED_REJECTION),这是一个未处理的被拒绝的Promise错误现在假设由于某种原因,此应用程序必须在Nodev14或更早版本上运行才能工作(忽略try..catch的使用)。团队中的每个开发人员都必须准备好在那个环境中开发和运行,但是我们公司还有一个新的应用程序在Nodev17上运行!那我们应该怎么解决这个问题呢?答:Docker创建Dockerfile上一节我们介绍了两个不同版本的Node导致的unhandledrejectedpromises的问题。我们介绍了如何使用Docker来解决这个问题。其实很简单,就是一个Node<15的运行环境来保证我们的程序不会崩溃,我们可以在DockerHub中搜索Node的镜像,里面有很多版本信息可以选择。当然我们不需要直接使用dockerpullnode来拉取节点镜像。前面我们提到了Dockerfile可以用来定制自定义镜像。自动判断当前机器是否有Node镜像。如果没有,会自动去DockerHub拉取。看看我们的Dockerfile:#首先选择你需要的镜像,运行在alpine上的node版本是目前最流行的FROMnode:14-alpine3.12#Workingdirectory#这是你将在容器中的位置WORKDIR/usr/src/app#通配符用于确保package.json和package-lock.json都被复制#COPY源目录容器的工作目录COPYpackage*.json./#安装应用依赖RUNnpminstall#如果你正在构建for生产代码#RUNnpmci--only=production#BundledappsourceCOPY..#将此端口配置为可从容器外部访问#浏览器向Node应用程序发送HTTP请求所必需的EXPOSE8080#dockerrun上的CMDRun#是执行shellnpmrunstartCMD["npm","run","start》]ok,我们的Dockerfile已经创建成功了,我们也在上面的代码注释中简单介绍了Dockerfile的指令,更详细的指令用法大家可以自行谷歌搜索,不过大家可能会好奇上面的配置文件,为什么COPY需要执行两次,最后一次COPY..并没有复制整个目录,为什么要复制package*.json?Docker层和缓存COPY两次是必须的,因为Docker有层(层的特性),每执行一条指令都会在上一条指令创建的层的基础上再创建一层,创建的层会被缓存,只要有achange会重新创建一次,我们回过头来看一下Dockerfile。COPYpackage*.json./我们在运行npminstall之前根据这个文件的内容创建一个layer,也就是说除非我们改变package.json,否则下次构建Docker时会使用npminstall已经运行过的缓存layer,我们不必在每次运行dockerbuild时都安装所有依赖项。这将为我们节省很多时间。复制。.将查看我们项目目录中的每个文件,因此该层将在任何文件更改时重建(package*.json除外)。这正是我们想要的。要构建应用程序容器,让我们添加一个.dockerignore文件,类似于我们的.gitignore,因为我们不想复制这些文件。node_modulesnpm-debug.log一切准备就绪,我们开始构建自己的镜像,#使用当前项目目录作为源目录,给镜像起个名字叫qianduanwanjianke$dockerbuild。-tqianduanwanjianke然后检查我们创建的镜像是否存在?创建镜像后,我们现在准备从镜像构建一个容器来运行我们的应用程序:#--name我们给容器起了一个名字,叫做qianduanwanjianke-container#-p标志设置来自我们主机(我们的计算机)的端口)环境的3001端口映射到容器环境的8080端口,当然也可以是8080:8080。dockerrun-p3001:8080--nameqianduanwanjianke-containerqianduanwanjianke大功告成,我们访问http://localhost:3001/看看是否成功。结论在这里,我们通过Node应用程序介绍Docker,并创建我们的第一个自定义Docker映像和容器,并在其中运行我们的应用程序!这是一篇面向Javascript开发者的Docker介绍,从Node程序开始。文章的内容对于熟悉Docker的后端开发者来说可能比较通俗易懂,对于我们前端开发者来说应该是一个不错的入门教程。由于文章篇幅,决定引入DockerVolume(将容器内的程序副本与项目目录下的副本“连接”起来,更新同步)并引入数据库,分析数据库托管服务器的区别,如何创建分离,DockerCompose等。放在下一篇介绍。过程中踩过的坑1.拉取镜像时报错,报错信息:errorduringconnect:Thiserrormayindicatethedockerdaemonisnotrunning...解决方法:#ElevateaccessrightsinPowershell解决这个问题cd"C:\ProgramFiles\Docker\Docker"./DockerCli.exe-SwitchDaemon2.创建应用程序容器时,执行dockerbuild。-tmy-node-app,错误消息:清单列表条目中没有适用于windows/amd6410.0.18363的匹配清单?解决方法:打开DockerDevlop软件,settiong->DockerEngine,设置experimental为true,重启Docker