我们的服务,需要稳定运行在服务器上,最好是个linux机器。这时就不能再用deno run mod.ts来启动了,因为我们断掉 SSH 连接后服务就终止了。
部署方式这里介绍2种。
pm2
pm2 是 Node.js 下的生产环境进程管理工具,就是我们常说的进程守护工具,可以用来在生产环境中进行自动重启、日志记录、错误预警等等。
因为Deno官方没有提供类似的工具,所以我们暂时可以使用pm2来管理我们的Deno程序。
全局安装pm2:
bash
npm install pm2 -g
执行以下命令以启动服务:
bash
pm2 start --name deno_blog src/main.ts --interpreter='deno' --interpreter-args='run --allow-net --allow-run --allow-env --allow-write --allow-read --importmap import_map.json --unstable'
interpreter
和interpreter-args
这里就是Deno的命令,其实pm2还支持其它编程语言比如Python
,只是支持有限罢了。
这时看到控制台打印:
systemverilog
┌─────┬───────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├─────┼───────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ deno_blog │ default │ N/A │ fork │ 27086 │ 3m │ 0 │ online │ 0% │ 79.5mb │ root │ disabled │
└─────┴───────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
访问http://localhost:8000来验证功能。
pm2 常用命令:
pm2 start/stop
: 启动/停止程序pm2 reload/restart [id|name]
: 重启程序pm2 logs [id|name]
: 查看日志pm2 l/list
: 列出程序列表pm2 monit
: 监控程序控制台打印信息
更多命令请使用 pm2 -h
查看。或者参看这篇文章《PM2使用记录》。
docker
容器化部署是近年来的趋势,一大优点是宿主机不需要关注具体服务复杂的部署环境,也就是说你的服务是Java的,你的容器就负责把jdk等依赖项都安装好,宿主机直接运行这个容器就可以了。
对于我们的服务而言,我们的容器就是依赖于Deno。如果你对docker不熟悉,可先看遍《菜鸟教程》。
docker-compose本地运行
在根目录下创建Dockerfile,内容如下:
dockerfile
FROM denoland/deno:alpine-1.20.6
EXPOSE 8000
WORKDIR /app
# Prefer not to run as root.
RUN chown -R deno /app
RUN chmod 755 /app
USER deno
COPY . .
RUN deno cache --import-map import_map.json src/main.ts
CMD deno run --allow-net --allow-env --allow-write --allow-read --importmap import_map.json src/main.ts
其中,第一行是Deno的镜像,alpine是官方提供的包含完整运行环境的最小镜像。根据你当前使用的Deno版本更改这里的版本号。
deno cache这一句将把src/main.ts的所有依赖项都先下载。如果没有这一句,则服务运行时才下载依赖,将会严重影响服务启动速度。
新建.dockerignore,把不需要打入镜像的文件路径写进去:
arduino
.git
.vscode
logs
*.md
public/img
新建docker-compose.yml,用它来构建和启动镜像服务:
yaml
version: '3'
services:
server:
build:
context: ./
dockerfile: Dockerfile
ports:
- "8001:8000"
environment:
TZ: Asia/Shanghai
volumes:
- ./config.yaml:/app/config.yaml
其中,ports前面的端口号是宿主机要使用的,后面是容器内部暴露的。
environment
这里设置中国时区,这样打印出来的时间看起来就正常了。也可以选择把它直接设置到Dockerfile里,见仁见智。
volumes是映射宿主机的配置文件到容器内,这个在生产中是常见的,因为数据库地址、日志级别这些配置项通常是要修改的。如果你的配置文件中包含敏感信息,千万不要提交到git,也不要打包到镜像中。
使用docker-compose build构建镜像,构建完成后再使用docker-compose up来启动服务。到生产时使用docker-compose up -d使用服务运行在后台。
当然,真正的生产中,更多可能是使用K8S来管理运行我们的镜像,那是一个更复杂难喻的工程,这里就不说了。
服务启动之后,在浏览器里请求http://localhost:8001来验证,这时你会看到:
所有人的图片都不见了,这也是正常的,因为我们没有把public/img文件夹复制到镜像中。那么我们应该怎么做呢?
在volumes中把这个目录挂载即可:
yaml
volumes:
- ./config.yaml:/app/config.yaml
- ./public/img:/app/public/img
重启服务,就能看到页面正常了。
看到这里,你应该能够意识到,生产中你要备份好你配置的volumes文件(一般还有logs目录),这也是把它们挂载出来的目的之一,不然镜像版本升级之后,这些文件就随着上个容器的销毁而丢失了。
发布镜像
如果你的镜像只是自己单机使用,上面的教程应该就够用了。
但如果你打算在云环境使用的话,就需要把你的这个镜像发布到Docker Hub,也可以发布到阿里云之类私云上。怎么发布请自行百度。
要使用这个镜像,只需要修改docker-compose.yml,注释掉build部分,换成image即可。
yaml
image: 你的镜像地址:版本号
# build:
# context: ./
# dockerfile: Dockerfile
作业
怎么部署服务到公网环境、绑定域名,不在本节讲解范围,读者可自行尝试。
本来到这里,本书就该结束了。但你思考下,我们的部署环节中是否还有什么制约点,影响我们后续服务的迭代上线?