在本地电脑上开发 Node.js 应用,需要安装一个 Node.js,还有就是准备一个应用需要的数据库管理系统。在本地安装 Node.js 你可以直接下载使用安装包,这样你的系统里只会包含一个版本的 Node.js。如果想同时拥有多个版本的 Node.js,可以使用 NVM 这个工具来管理安装在电脑上的多个版本的 Node.js,你可以在不同版本之间来回切换。
另外还有一种搭建 Node.js 应用开发环境的方法,就是使用 Docker。下面我介绍一下在本地电脑上使用 Docker 与 Docker Compose 搭建一个 Node.js 的开发环境。我会用 Nest.js 这个应用框架作为演示。
需求
在本地使用 Docker 可以去安装一个 Docker 桌面版,比如 Docker for Windows 或 Docker for Mac。在 Mac 电脑上使用 Docker 桌面版不会有太大问题,但是在 Windows 上运行 Docker 桌面版会有一些需求。
系统必须是 Windows 10 专业版或企业版,普通的 Windows 10 不行,而且需要在系统里启用 Hyper-V。
准备
下载安装 Docker 桌面版,体积挺大,需要下一会儿,下载之前你需要使用 Docker Hub 帐号登录一下才行。
- Windows:https://docs.docker.com/docker-for-windows/install/
- macOS:https://docs.docker.com/docker-for-mac/install/
Docker 的大部分操作需要在命令行界面下完成,所以你需要准备一个命令行界面,macOS 用户可以使用系统自带的终端(Terminal),Windows 用户建议下载安装完整版的 Cmder,然后新建一个 Bash as admin 的命令行。
配置
Docker 在创建容器的时候,需要用到一些镜像,也就是如果你的系统上还没有这些镜像的话,Docker 会自动到一个地方去下载这个镜像,保存在你的电脑上,然后基于这个镜像去创建你需要的容器。
下载这些镜像的地方默认在国外,所以我们在国内有时会比较慢,解决的方法是配置一下 Docker 让它使用国内的镜像加速地址。比如阿里云暂时就提供了这个服务,你可以使用自己的阿里云帐号登录到阿里云的容器镜像服务,在里面你会找到一个镜像加速地址,看起来像这样:https://wgaccbzr.mirror.aliyuncs.com
把你在阿里云容器镜像服务上找到的加速地址,配置到你的 Docker 的 Registry Mirrors 里面。
Nest.js 开发环境
下面我们用 Docker Compose 搭建一个在本地可以运行 Nest.js 应用的开发环境。
docker-compose.yml
Docker Compose 允许我们在一个文件里描述应用需要的服务(容器),为你要开发的项目新建一个目录,然后在根目录下创建一个 docker-compose.yml 文件。里面先添加两行代码:
version: '3'
services:复制代码
用 version
设置了一下要使用 Docker Compose 版本,一会儿开发环境需要的几个服务会在 services
下面定义。
.env
在 docker-compose.yml 文件里定义的服务可以使用一些环境变量,这些环境变量还有对应的值可以单独放在一个叫 .env
的文件里面,这个文件就相当于是一个配置文件。在项目根目录下面创建一个空白的文件叫:.env
。
准备 Nest.js 应用的命令行工具
你打算开发基于 Nest.js 框架的 Node 应用,可以先去安装这个框架提供的命令行工具(@nestjs/cli),它可以让我们使用命令去创建全新的应用还有应用里需要的一些组件。不过因为我们打算用 Docker 的方式搭建应用的开发环境,所以就不直接在电脑上去安装这个工具了,因为这需要你在电脑上安装 Node.js。
在 docker-compose.yml
文件里定义一个服务,它的作用就是让我们可以使用 Nest.js 框架里提供的命令行工具,打开 docker-compose.yml
文件,在 services
下面添加一个命令行工具服务:
version: '3'
services:
cli:
image: nestjs/cli
volumes:
- ./app:/workspace
tty: true复制代码
上面定义了一个叫 cli
的服务,这个名字你可以随便定义,这个服务用的 image
,也就是镜像是 nestjs/cli
,volumes
设置了一下数据卷的功能,意思就是让当前目录下的 app 这个目录,对应容器里的 /workspace
这个位置。把 tty
设置成 true
是为了让这个容器一直运行。
打开系统的终端(Terminal),Windows 用户推荐使用 Cmder。进入到 docker-compose.yml
文件所在的目录,然后运行服务:
cd ~/desktop/ninghao-nestjs
docker-compose up -d cli复制代码
上面执行了两条命令,第一行是进入到了 docker-compose.yml
文件所在的目录,第二行命令是在后台运行了在 docker-compose.yml
文件里定义的一个叫 cli
的服务。验证一下服务是否运行:
docker-compose ps
Name Command State Ports
-------------------------------------------------
ninghao-nestjs_cli_1 /bin/sh Up 3000/tcp复制代码
注意服务的 State 是 Up 表示正在运行,下面可以登入这个 cli
服务:
docker-compose exec cli /bin/sh复制代码
进来以后你的命令提示符会像这样:
/workspace #复制代码
在这个容器里我们可以使用 Nest.js 应用里的命令行工具,执行:
nest复制代码
会出现一些帮助信息:
Usage: nest [options] [command]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
new|n [options] [name] Generate Nest application
generate|g [options] [name] [path] Generate a Nest element
Available schematics:
复制代码
用 Nest 命令行工具创建应用
进入到创建的 cli
这个容器里面以后,可以执行 nest
命令,下面我们用这个命令去创建一个 Nest.js 项目。执行:
nest new app复制代码
会出现类似的东西:
⚡ We will scaffold your app in a few seconds..
CREATE /app/.prettierrc (51 bytes)
CREATE /app/README.md (3370 bytes)
CREATE /app/nest-cli.json (84 bytes)
...复制代码
上面就是用了 nest new
命令创建了一个项目,放在 app
目录的下面,虽然是在 cli
容器里创建的这个项目,但是我们配置了这个服务的数据卷,所以创建的项目文件也会在本地电脑上看到。也就是你在本地电脑上这个 docker-compose.yml
文件所在的目录的下面,会看到一个 app
目录,这里的东西就是创建的 Nest.js 项目。
在开发应用的时候,如果你要使用 nest
命令行工具生成项目需要的文件,你就可以进入到这个 cli
服务容器里面,然后使用 nest
命令去创建你需要的东西。
创建的项目的时候可能会提示:
Failed to execute command: git init
Git repository has not been initialized复制代码
这是因为创建完项目之后,nest
命令会去初始化一个代码仓库,但是在这个容器里并没有安装 git
,所以执行相关命令的时候就会出现问题。你可以在本地用 Git 对项目做源代码管理。
注意如果你觉得创建项目的时候速度慢,可以在进入 cli
服务里面以后,执行一下:
npm config set registry https://registry.npm.taobao.org复制代码
定义应用服务
在 docker-compose.yml
文件里,再定义一个运行 Nest.js 应用的服务:
nest:
image: node:${NODE_VERSION}
working_dir: /home/node/app
command: npm config set registry https://registry.npm.taobao.org
command: npm run start:dev
volumes:
- ./app:/home/node/app
ports:
- ${APP_PORT}:3000复制代码
上面定义了一个叫 nest
的服务,因为我们创建的应用是基于 Nest.js 框架的,所以这个服务的名字叫 nest
,你也可以换成自己喜欢的名字。
nest
这个服务用的 image
是 node
,具体的版本用了一个环境变量,NODE_VERSION
,这个环境变量还有对应的值要在 .env
文件里设置一下。
working_dir
进入到工作目录,然后执行了两个 command
,一个是设置了一下 npm
的安装源,这样以后安装包的时候会快一些,第二个 command
是运行了项目的开发服务。
volumes
设置了数据卷,让当前目录下的 app
这个目录,对应 nest
这个服务容器里的 /home/node/app
,我们在这个服务的这个目录的下面,执行了 npm run start:dev
,这也就会运行这个 Nest.js 项目的开发服务。
ports
设置了公开的端口,就是设置一个主机(本地电脑)上的端口,让这个端口对应这个容器里的某个端口。运行了 Nest 应用的开发服务以后,会使用 3000
这个端口提供服务。${APP_PORT}
这里用了一个叫 APP_PORT
的环境变量,具体的值要在 .env
文件里设置一下:
NODE_VERSION=11.13
APP_PORT=3000复制代码
注意在 .env
文件里,我们让 APP_PORT
这个环境变量的值等于 3000
,也就是公开的端口应该就是 3000:3000
,也就是本地电脑上的 3000
端口对应的是这个服务里的 3000
端口。
有了这个新的 nest
服务,要再去运行一下:
docker-compose up -d nest复制代码
如果一切正常,打开浏览器,访问 http://localhost:3000,你应该会看到一个 “Hello World”。
以后你需要用 npm install
给项目安装一些 Package 的时候,可以进入到这个 nest
服务里面,使用 npm
。进入这个服务可以执行:
docker-compose exec nest bash复制代码
定义数据服务
开发 Nest.js 应用支持使用多种不同类型的数据库,需要哪种数据库系统,你就去创建一个对应的服务就行了。比如我要在应用里使用 MySQL 这种数据库,所以可以在 docker-compose.yml
里面,再去定义一个 mysql
服务:
mysql:
image: mysql:${MYSQL_VERSION}
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
restart: always
ports:
- ${MYSQL_PORT}:3306
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}复制代码
服务里面用到了一些环境变量,打开 .env
,在文件里去定义这些环境变量还有对应的值:
MYSQL_VERSION=5.7
MYSQL_PORT=3306
MYSQL_DATABASE=nest
MYSQL_USER=nest
MYSQL_ROOT_PASSWORD=root
MYSQL_PASSWORD=password复制代码
主要就是设置一下要使用的 MySQL 系统的版本,在本地主机上访问这个数据服务用的端口是什么,还有创建的数据库的名字、用户还有密码是什么。你可以修改 .env
文件里的这些环境变量的值,来改变数据库的配置。
上面会创建一个 5.7
版本的 MySQL,在本地主机上使用这个数据服务用的端口是 3306
,数据库系统里会创建一个叫 nest
的数据库,操作这个数据库可以使用 nest
用户,对应的密码是 password
,另外设置了一下数据库系统的 root
用户的密码为 root
。
定义好这个数据服务,需要去运行一下:
docker-compose up -d mysql复制代码
查看日志
查看容器里的输出的日志,可以执行:
docker-compose logs --follow复制代码
附录
docker-compose.yml:
version: '3'
services:
cli:
image: nestjs/cli
volumes:
- ./:/workspace
tty: true
nest:
image: node:${NODE_VERSION}
working_dir: /home/node/app
command: npm config set registry https://registry.npm.taobao.org
command: npm run start:dev
volumes:
- ./app:/home/node/app
ports:
- ${APP_PORT}:3000
mysql:
image: mysql:${MYSQL_VERSION}
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
restart: always
ports:
- ${MYSQL_PORT}:3306
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
复制代码
.env:
NODE_VERSION=11.13
APP_PORT=3000
MYSQL_VERSION=5.7
MYSQL_PORT=3306
MYSQL_DATABASE=nest
MYSQL_USER=nest
MYSQL_ROOT_PASSWORD=root
MYSQL_PASSWORD=password复制代码