在Docker中建立Node.js应用的经验与技巧
这篇教程中展示在Docker中开发和部署node.js的web应用的经验和教训,以在docker中设置 socket.io chat example应用为案例,说明如何实现产品准备阶段的工作,具体有:
- 真正从node在docker起步开始
- 不要以root运行任何事情
- 在开发阶段使用bind保持你的test-edit-reload短循环.
- 在容器中管理node_modules以便更加rebuild
- 使用 npm shrinkwrap确保可重复的构建.
- 在开发阶段和产品阶段共享一个Dockerfile 文件
本教程假设你有一些Docker和Node.js基础。
起步
我们将开始设置 github 这个项目,这里是起步设置文件Dockerfile和docker-compose.ym。
如果没有使用Docker,我们会首先安装Node和其他依赖,然后运行npm init创建新的包,但是如果从docker开始,我们将从创建一个启动容器开始,在这个启动容器中已经安装了node,我们将使用它来设置npm包。
我们需要编写两个文件Dockerfile 和 docker-compose.yml,首先加入下面配置:
FROM node:4.3.2
RUN useradd --user-group --create-home --shell /bin/false app &&\
npm install --global npm@3.7.5
ENV HOME=/home/app
USER app
WORKDIR $HOME/chat
虽然这些配置比较短,但是包含重要几点:
-
第一行这里指定一个版本,而不是使用‘floating’标签:node:argon 或 node:latest, 这样,如果你或其他人在不同机器上建立这个image,他们会得到相同版本,而不是突然遭遇立即更新伴随让人抓狂的问题出现
- 第二行创建了一个普通用户在容器中来调用应用,如果你不这么做,容器中过程将作为root运行,有违背安全规则,许多docker教程为了简单都忽视这个设置,这非常重要。
- 安装最新NPM最新版本. 这是严格必须的,最好在在配置中指定一个准确的版本。.
- 注意到我们用一行RUN命令执行了useradd和npm install两个本应单行命令,这会降低结果image中层次数量,节省磁盘空间和下载时间,节省中间过程导致的空间浪费。
再看看启动文件docker-compose.yml:
chat:
build: .
command: echo 'ready'
volumes:
- .:/home/app/chat
这是定义了是从Dockerfile中构建的一个服务,所做的是echo ready并退出,.:/home/app/chat是告诉docker安装当前主机应用目录"."到/home/app/chat目录下,这样能够使得当前主机上源文件自动映射到容器中,对于尽可能在开发阶段保持 test-edit-reload是很重要的。
现在当我们运行docker-compose up时,Docker将按照Dockerfile文件创建带有nodee的image,。它会启动一个容器,然后运行echo命令,显示一切设置OK:
$ docker-compose up
Building chat
Step 1 : FROM node:4.3.2
---> 3538b8c69182
...
lots of build output
...
Successfully built 1aaca0ac5d19
Creating dockerchatdemo_chat_1
Attaching to dockerchatdemo_chat_1
chat_1 | ready
dockerchatdemo_chat_1 exited with code 0
现在我们在容器中运行一个交互shell,在shell中设置初始包:
$ docker-compose run --rm chat /bin/bash
app@e93024da77fb:~/chat$ npm init --yes
... writes package.json ...
app@e93024da77fb:~/chat$ npm shrinkwrap
... writes npm-shrinkwrap.json ...
app@e93024da77fb:~/chat$ exit
至此完成,下面是我们主机的情况:
$ tree
.
├── Dockerfile
├── docker-compose.yml
├── npm-shrinkwrap.json
└── package.json
下一步是安装依赖包