一步步教你利用Docker设置Node.js


Posted in Javascript onNovember 20, 2018

前言

docker是一个开源的应用容器引擎,可以为我们提供安全、可移植、可重复的自动化部署的方式。docker采用虚拟化的技术来虚拟化出应用程序的运行环境。如上图一样。docker就像一艘轮船。而轮船上面的每个小箱子可以看成我们需要部署的一个个应用。使用docker可以充分利用服务器的系统资源,简化了自动化部署和运维的繁琐流程,减少很多因为开发环境中和生产环境中的不同引发的异常问题。从而提高生产力。

docker三个核心概念如下:

  • 镜像(images):一个只读的模板,可以理解为应用程序的运行环境,包含了程序运行所依赖的环境和基本配置。相当于上图中的每个小箱子里面装的东西。
  • 仓库(repository):一个用于存放镜像文件的仓库。可以看做和gitlab一样。
  • 容器(container):一个运行应用程序的虚拟容器,他和镜像最大的区别在于容器的最上面那一层是可读可写的。 相当于上图中的每个小箱子里。

本文主要是教大家了解如何在Docker容器中设置Node JS:

有一个可运行工作的NodeJS应用程序

通过确保进程在出错时不退出,使节点应用程序具有弹性

通过在代码更改时自动重新启动服务器,使Node应用程序易于使用

利用Docker:

  • 快速设置与生产相同的开发环境。
  • 轻松地能够在本地和服务器上切换节点版本
  • Docker的所有其他 好处

先决条件

Docker已经安装好了

至少入门级节点知识和NPM

1.获取一个简单的Node应用程序

我们将使用Express,因为它的设置是容易的。

在一个干净的目录中,让我们从初始化NPM开始,继续运行此命令并按照提示进行操作:

npm init

安装Express:

npm install --save-prod express

编制代码src/index.js

<b>const</b> express = require('express')
<b>const</b> app = express()
<b>const</b> port = 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => {console.log(`Example app listening on port ${port}!`))

启动一个侦听端口3000并使用Hello World响应的"/"这个URL路由。

2.设置Docker以运行我们的Node应用程序

我们将使用docker-compose.yml文件来启动和停止我们的Docker容器,而不是键入长长的Docker命令。您可以将此文件视为多个Docker容器的配置文件。

docker-compose.yml:

version: "3"
services:
 app:
 container_name: app # How the container will appear when listing containers from the CLI
 image: node:10 # The <container-name>:<tag-version> of the container, in this case the tag version aligns with the version of node
 user: node # The user to run as in the container
 working_dir: "/app" # Where to container will assume it should run commands and where you will start out if you go inside the container
 networks:
 - app # Networking can get complex, but for all intents and purposes just know that containers on the same network can speak to each other
 ports:
 - "3000:3000" # <host-port>:<container-port> to listen to, so anything running on port 3000 of the container will map to port 3000 on our localhost
 volumes:
 - ./:/app # <host-directory>:<container-directory> this says map the current directory from your system to the /app directory in the docker container
 command: "node src/index.js" # The command docker will execute when starting the container, this command is not allowed to exit, if it does your container will stop

networks:
 app:

让我们用这个命令启动docker容器。在后台运行(-d)

docker-compose up -d

在浏览器中访问http://localhost:3000并看到 Hello World!

3. 使得应用变得弹性

如果您之前使用过Node,那么您可能知道如果应用程序中发生错误(如未捕获的异常),那么它将关闭该Node进程。这对我们来说真的是个坏消息,因为我们的代码中肯定会有一个错误,并且无法保证我们的代码100%无错误。此问题的解决方案通常是另一个监视我们的Node应用程序并在其退出时重新启动它的过程。有这么多的解决方案,比如linux的supervisord,NPM包永远和PM2等......我们只需要为本指南选择一个。

将专注于 PM2, 因为我最熟悉它,除了进程管理之外还有一些其他功能,例如文件监视,这将在下一节中派上用场。

安装PM2

npm install --save-prod pm2

PM2可以通过命令行使用,但我们将设置一个简单的配置文件,就像我们使用docker-compose.yml文件一样,以防止我们重复输入长命令

ecosystem.config.js:

const path = require('path')

module.exports = {
 apps: [{
 name: 'app',
 script: 'src/index.js', // Your entry point
 instances: 1,
 autorestart: true, // THIS is the important part, this will tell PM2 to restart your app if it falls over
 max_memory_restart: '1G'
 }]
}

现在我们应该更改docker-compose.yml文件以使用PM2启动我们的应用程序,而不是直接从index.js启动它。

docker-compose.yml(仅更改了的选项)

version: "3"
services:
 app:
 container_name: app # How the container will appear when listing containers from the CLI
 image: node:10 # The <container-name>:<tag-version> of the container, in this case the tag version aligns with the version of node
 user: node # The user to run as in the container
 working_dir: "/app" # Where to container will assume it should run commands and where you will start out if you go inside the container
 networks:
 - app # Networking can get complex, but for all intents and purposes just know that containers on the same network can speak to each other
 ports:
 - "3000:3000" # <host-port>:<container-port> to listen to, so anything running on port 3000 of the container will map to port 3000 on our localhost
 volumes:
 - ./:/app # <host-directory>:<container-directory> this says map the current directory from your system to the /app directory in the docker container
 command: "npx pm2 start ecosystem.config.js --no-daemon" # The command docker will execute when starting the container, this command is not allowed to exit, if it does your container will stop

networks:
 app:

更改docker-compose.yml文件不会影响已经运行的容器。为了进行更改,您应该重新启动容器:

docker-compose restart

4.使我们的应用程序易于开发

您可能已经注意到,一旦Node进程启动,那么在重新启动Node进程之前,更改代码实际上并没有做任何事情,对于我们而言,每次都会涉及重新启动Docker容器以激活我们做出的改变。如果我们在进行代码更改时自动为我们重新启动Node进程,那将是理想的选择。

在过去,我已经完成了诸如引入文件监视实用程序和使用该文件监视实用程序来重新启动Docker进行文件更改之类的操作,或者我会使用Nodemon但是在使用Docker时会有一些警告。

最近,当文件发生变化时,我一直在使用PM2来重新启动我的Node进程,而且由于我们已经从上一步中获取了它,因此我们不必安装另一个依赖项。

ecosystem.config.js(仅添加了watch选项):

const path = require('path')

module.exports = {
 apps: [{
  name: 'app',
  script: 'src/index.js',
  instances: 1,
  autorestart: true,
  watch: process.env.NODE_ENV !== 'production' ? path.resolve(__dirname, 'src') : false,
  max_memory_restart: '1G'
 }]
}

如果我们没有将NODE_ENV环境变量设置为production,则上面的配置文件现在将监视src目录。您可以通过更改index.js文件来测试它,除了Hello World之外还可以将其他内容打印到浏览器中!。在此之前,您需要重新启动Docker容器,因为您更改了PM2运行容器的方式:

docker-compose restart

重新启动Node进程可能需要一秒钟才能完成,如果你想观察它何时完成,你可以看到你的Docker日志告诉PM2何时完成重启你的Node Process:

docker-compose logs -f

总结

  • 我们的目标之一是能够轻松更改Node版本,您可以通过更改docker-compose.yml文件中的image选项来完成此操作。
  • 本地安装依赖项是使用本地NPM和Node版本完成的,如果您的本地版本与Dockers不同,有时可能会导致冲突。使用相同的Docker容器来安装依赖项更安全。您可以使用此命令来使用该容器来安装依赖项,然后将其删除
docker run --rm -i -v <absolute-path-to-your-project-locally>:/app -w /app node:10 npm install
  • 如上所述,具有与Docker运行的Node不同的本地版本可能是有问题的。最好在容器内部运行命令以保持一致性。你可以进入一个容器
docker exec -it app bash

上面的命令将把你放到容器中,这样你就可以继续从里面运行命令,即npm run start或npm run test

如果您不想进入容器内部,可以运行这样的命令

docker exec -t app bash -c "npm run start"

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
jquery.validate使用攻略 第三部
Jul 01 Javascript
JavaScript 的继承
Oct 01 Javascript
关于javaScript注册click事件传递参数的不成功问题
Jul 18 Javascript
JavaScript对表格或元素按文本,数字或日期排序的方法
May 26 Javascript
ui组件之input多选下拉实现方法(带有搜索功能)
Jul 14 Javascript
Angular2中Bootstrap界面库ng-bootstrap详解
Oct 18 Javascript
Jquery Easyui选项卡组件Tab使用详解(10)
Dec 18 Javascript
angularjs过滤器--filter与ng-repeat配合有奇效
Apr 20 Javascript
ES6深入理解之“let”能替代”var“吗?
Jun 28 Javascript
详谈Object.defineProperty 及实现数据双向绑定
Jul 18 Javascript
如何使用JS console.log()技巧提高工作效率
Oct 14 Javascript
node使用async_hooks模块进行请求追踪
Jan 28 Javascript
JS滚轮控制图片缩放大小和拖动的实例代码
Nov 20 #Javascript
vue中的适配px2rem示例代码
Nov 19 #Javascript
JS监听事件的叠加和移除功能
Nov 19 #Javascript
微信小程序自定义弹窗wcPop插件
Nov 19 #Javascript
Vue.js 使用v-cloak后仍显示变量的解决方法
Nov 19 #Javascript
Vue.js 中的 v-cloak 指令及使用详解
Nov 19 #Javascript
浅析Vue.js 中的条件渲染指令
Nov 19 #Javascript
You might like
使用 php4 加速 web 传输
2006/10/09 PHP
海河写的 Discuz论坛帖子调用js的php代码
2007/08/23 PHP
PHP二维数组排序的3种方法和自定义函数分享
2014/04/09 PHP
php操作redis缓存方法分享
2015/06/03 PHP
浅析Yii2 GridView实现下拉搜索教程
2016/04/22 PHP
php实现微信发红包功能
2018/07/13 PHP
PHP7 标准库修改
2021/03/09 PHP
理解Javascript_13_执行模型详解
2010/10/20 Javascript
设为首页加入收藏兼容360/火狐/谷歌/IE等主流浏览器的代码
2013/03/26 Javascript
javascript判断两个IP地址是否在同一个网段的实现思路
2013/12/13 Javascript
js返回上一页并刷新的多种实现方法
2014/02/26 Javascript
javascript进行四舍五入方法汇总
2014/12/16 Javascript
浅谈JavaScript字符串与数组
2015/06/03 Javascript
基于HTML+CSS,jQuery编写的简易计算器后续(添加了键盘监听)
2016/01/05 Javascript
关于iframe跨域POST提交的方法示例
2017/01/15 Javascript
jquery实现联想词搜索框和搜索结果分页的示例
2018/10/10 jQuery
vue中将html字符串转换成html后遇到的问题小结
2018/12/10 Javascript
15 分钟掌握vue-next响应式原理
2019/10/13 Javascript
js中forEach,for in,for of循环的用法示例小结
2020/03/14 Javascript
vue实现导航菜单和编辑文本的示例代码
2020/07/04 Javascript
[02:36]DOTA2英雄基础教程 斯拉克
2013/11/29 DOTA
[33:42]LGD vs OG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python操作列表的常用方法分享
2014/02/13 Python
PyCharm使用教程之搭建Python开发环境
2016/06/07 Python
python 实现一个贴吧图片爬虫的示例
2017/10/12 Python
Django生成PDF文档显示在网页上以及解决PDF中文显示乱码的问题
2019/07/04 Python
Nordgreen美国官网:在线购买极简主义斯堪的纳维亚手表
2019/07/24 全球购物
自我鉴定200字
2013/10/28 职场文书
食品安全责任书
2014/04/15 职场文书
技术负责人任命书
2014/06/05 职场文书
党员应该树立反腐倡廉的坚定意识思想汇报
2014/09/12 职场文书
机关党员三严三实心得体会
2014/10/13 职场文书
青年岗位能手事迹材料
2014/12/23 职场文书
2015年行政人事工作总结
2015/05/21 职场文书
Pytest中skip和skipif的具体使用方法
2021/06/30 Python
解析python中的jsonpath 提取器
2022/01/18 Python