很多朋友喜欢用nodejs语言编写服务器程序,因此国产thinkjs架构应用也比较广泛,使用 Docker 部署 ThinkJS 相关的项目,因此仍是拿出来讲说吧。须要提早说明的是本文并非 Docker 的基础教程,默认你们都是了解 Docker 的。为 ThinkJS 项目构建和部署过程当中可能须要注意的点,咱们先说说如何构建镜像,而后再说一下可能出现的问题。
构建镜像
基础镜像
FROM mhart/alpine-node:8.9.4
首先推荐你们基于 mhart/alpine-node 的镜像来构建,由于真的很小(20M左右)!不过由于小有不少的构建工具都不是很全,若是赶上一些安装时须要编译的模块时可能会缺乏环境,这个时候你能够选择手动去安装环境,固然也能够选择使用 Docker 官方的 library/node 镜像(800M左右),为了省事推荐这种状况下仍是使用后者比较好。前端
依赖安装
COPY package.json /animaris/package.json
RUN npm i --production --registry=https://registry.npm.taobao.org
选好了基础镜像以后下面就须要拷贝项目文件了。这里推荐你们先把 packge.json 文件 COPY 进来而后安装依赖。由于依赖的变化比较小,能够认为一段时间内这部分的镜像层都是稳定的。而项目代码会随着需求变动而常常变化。综上所述,咱们选择让不变的镜像层优先打包保证镜像层的最大可复用性。node
拷贝项目
一个正常的 ThinkJS 项目其实线上运行只须要如下几个文件:nginx
app/:项目原始码文件夹,若是是未编译项目的话对应的是 src/ 目录
view/:前端模板文件夹
www/:前端静态资源文件夹
production.js:ThinkJS 启动脚本
因此只要按照顺序把这些文件 COPY 进去就能够了。git
启动项目
你们日常都习惯使用 PM2 来启动 NodeJS 项目,它最大的好处就是可以帮咱们守护项目进程,当进程被杀死的时候能帮咱们自动重启。不过 Docker 自己就是有自动重启的特性的,因此在不少层面上 Docker 和 PM2 一块使用都有点冲突。其实由于 Docker 充当了守护的角色,咱们彻底能够直接使用 node production.js 命令去启动。如下是一个完整的 ThinkJS 项目 Dockerfile 示例:github
FROM mhart/alpine-node:8.9.4
WORKDIR /animaris
COPY package.json /animaris/package.json
RUN npm i --production --registry=https://registry.npm.taobao.org
COPY src /animaris/src
COPY view /animaris/view
COPY www /animaris/www
COPY production.js /animaris/production.js
ENV DOCKER=true
EXPOSE 8360
CMD [ "node", "/animaris/production.js" ]
使用以下命令进行构建:docker
docker build -t lizheming/animaris ./Dockerfile
以后使用以下命令运行镜像,便可使用 http://localhost:8360 访问网站:shell
docker run -p 8360:8360 lizheming/animaris
注意事项
本地文件
使用 Docker 必定不能忘记的特性就是容器销毁后容器内的全部资源都是会被销毁的,下回会从新初始化,因此若是是须要持久化保存的应避免写到容器中,须要选择外部的持久化存储,例如 Volume 共享卷或者 S3 等相关服务。npm
ThinkJS 项目启动后通常会有 logs, runtime 两个目录会写入文件。其中 logs 是用来存储线上日志用的,这个最好使用共享卷的形式外载出来,方便以后排查问题。runtime 这个是 ThinkJS 运行时临时文件的存储地方,例如 cache 和 session 等。session 会话默认是使用文件类型存储的,若是使用 Docker 的话推荐选择 MySQL 等外部存储。其它的功能有相关需求也能够参考 session 服务。固然若是懒得用直接把 runtime 共享卷出来也是能够的。json
还有就是若是有用户上传类的需求会上传到本地文件夹上也要记得共享出来,不然丢数据就完蛋叻!
静态资源
ThinkJS 一直主张在生产环境中使用 Nginx 来处理静态资源,这样不须要通过 Node 层直接 Server 转发性能会更高。不过这样就给镜像打包形成了必定的麻烦,由于静态资源也被打包到项目镜像里去了,而 Nginx 镜像正常是没办法跨镜像读取到文件的,因此就死解了。
在 ThinkJS 中是利用 think-resource 这个中间件来处理静态资源的访问的,而后它在线上环境的状态是 enabled: false。其实静态资源过一层 Node 并消耗不了多少资源,除非对性能有严苛要求的,我建议均可以直接把这个功能打开。这样全部的请求都统一成 Nginx 转发到 Node 镜像,解决了 Nginx 须要跨镜像读取文件的问题。具体可参考官方文档的“为何上线后静态资源访问不了?”
module.exports = [
...
{
handle: 'resource',
enable: true // 始终开启,默认为 enable: isDev
表示只再开发环境下开启
},
...
]
固然若是真的要在打包成一个镜像的状况下用 Nginx 处理静态资源也不是没有办法,咱们能够利用共享卷来操做。Node 镜像经过将镜像文件共享卷的形式映射到本地,而后 Nginx 镜像经过共享卷的形式将以前本地映射的文件再映射到镜像中。这样经过本地的一层转发便可实现 Nginx 的跨镜像访问静态资源。
ThinkJS 镜像
docker run
-v ./www:/app/www
-p 8360:8360
lizheming/animaris
Nginx 镜像
docker run
-v ./nginx.conf:/etc/nginx/conf.d/animaris.conf
-v ./www:/var/www/animaris/www
-p 80:80
nginx
server {
listen 80;
server_name animaris.eming.li;
root /var/www/animaris/www;
location ~ /static/ {
etag on;
expires max;
}
}
环境变量
日常咱们是使用 development.js 和 production.js 来区分开发环境和生产环境的,然鹅这么打包以后发现都是生产环境了。这样有时候咱们须要不一样环境不一样配置就不太好弄了。这里推荐你们使用环境变量来区分。
think.env = process.ENV.ENV;
docker run -e ENV=test -p 8360:8360 lizheming/animaris
终端日志
有用户提出疑问 #1106,说“网站500了为啥 logs 里没看到日志?”。这是由于虽然 ThinkJS 内部的日志都是用 think-logger 模块处理了,可是由于跨模块或者启动时机的问题,有一些日志没办法走日志模块记录并存储到文件,会直接打到终端里。因此当没有日志的时候咱们能够考虑去 docker logs 中捞一下终端的日志,说不定有意外的惊喜。
通过docker查看log日志
通过docker logs命令可以查看容器的日志。
命令格式:
$ docker logs [OPTIONS] CONTAINER
Options:
--details 显示更多的信息
-f, --follow 跟踪实时日志
--since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
--tail string 从日志末尾显示多少行日志, 默认是all
-t, --timestamps 显示时间戳
--until string 显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)
例子:
查看指定时间后的日志,只显示最后100行:
$ docker logs -f -t --since="2018-02-08" --tail=100 CONTAINER_ID
查看最近30分钟的日志:
$ docker logs --since 30m CONTAINER_ID
查看某时间之后的日志:
$ docker logs -t --since="2018-02-08T13:23:37" CONTAINER_ID
查看某时间段日志:
$ docker logs -t --since="2018-02-08T13:23:37" --until "2018-02-09T12:23:37" CONTAINER_ID