使用docker一键部署node.js+mysql服务

虚拟机建站

之前整理过一篇虚拟机的建站教程:阿里云服务器建站指南,包含了node.js、mysql、redis、nginx的部署,搭建起了一个基础的后端应用。

但是这种部署方式迁移机器每次都需要执行很多操作,费时费力,所以决定用docker来替代它。

什么是docker?

docker是创建和管理容器的一种技术。

那什么是容器呢?容器的功能与虚拟机很近似,都是在一个物理主机上运行多个操作系统的技术。最大的不同之处在于,虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

docker的基本概念

镜像

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。我们可以通过命令或者一些基础镜像,构建自己需要的镜像。

容器

容器可以看作镜像的实体,容器可以被创建、启动、停止、删除、暂停等。

docker的安装和启动

我的是阿里云机器,系统是CentOS。

所以执行以下命令安装docker

1
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

安装后验证一下

1
2
[root@iZ8vb55rs42xic2s53uc3yZ nodejs]# docker -v
Docker version 20.10.5, build 55c4c88

然后启动docker

1
systemctl start docker

使用docker部署node.js应用

部署一个node.js应用需要node.js环境、安装依赖包、执行启动命令等等。

这些docker都支持,我们直接来看最终编写完成的Dockerfile。

Dockerfile是用来构建镜像的文本文件,包含了构建镜像所需的指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 它是基于node:12.22.1-alpine3.10基础镜像的,这些镜像可以在[官网](https://hub.docker.com/_/node) 找,你可以选择你想要的node.js版本。
FROM node:12.22.1-alpine3.10
# ADD这行命令是将工程下所有文件都加到镜像中,因为镜像的构建是B/S架构,它无法直接获取工程里的文件
ADD . /nodejs
# WORKDIR这行命令是设置工作目录,这里类似于cd到工程的根目录
WORKDIR /nodejs
# RUN可以执行一些命令,这里安装了工程的依赖包。
RUN npm --registry=https://registry.npm.taobao.org \
--cache=$HOME/.npm/.cache/cnpm \
--disturl=https://npm.taobao.org/dist \
--userconfig=$HOME/.cnpmrc install
# EXPOSE定义了应用的端口
EXPOSE 3000
# CMD为程序启动命令,这里使用了pm2为应用提供进程守护
CMD ./node_modules/.bin/pm2 start pm2.json --no-daemon --env production

构建镜像

有了Dockerfile,我们直接执行以下命令就可以构建镜像了

1
docker build -t nodejs .

nodejs是镜像名,你也可以修改成其它名字。

运行后的结果为

1
2
3
...
Successfully built 621c07eeba87
Successfully tagged nodejs:latest

说明镜像已经构建成功了。

启动容器

执行以下命令启动容器

1
docker run --name nodejs -it -p 3000:3000 nodejs

第1个nodejs是容器名,第2是镜像名,这行命令的含义是使用nodejs镜像(就是前面构建的镜像)运行一个容器,端口为3000。

这样node.js服务就启动了,你通过ip+端口号(3000)就可以访问应用了。

使用docker部署mysql

部署mysql也是类似的。

获取镜像

mysql有现成的镜像,所以不需要通过Dockerfile构建

执行命令拉取镜像

1
docker pull mysql/mysql-server:5.7

运行容器

执行命令

1
docker run --name mysql -d -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 mysql/mysql-server:5.7

这样mysql就运行起来了。

添加从外部访问数据库的权限

MySQL默认只能使用本地IP(127.0.0.1)访问,不能从外部网络访问。所以需要设置一下,运行node.js的容器才能访问运行MySQL服务的容器。

首先进入MySQL容器

1
docker exec -it mysql bash

进入Mysql服务

1
mysql -uroot -ppassword

password就是之前运行容器时设置的密码

最后添加外部访问权限

1
2
3
4
5
6
-- 切换数据库
USE mysql;
-- 给root账户开放所有ip访问权限
GRANT ALL PRIVILEGES ON *.* TO "root"@"%" IDENTIFIED BY "password";
-- 更新权限设置
FLUSH PRIVILEGES;

这样,你的node.js服务就可以通过用户名、密码连接访问mysql数据库了。

Docker Compose

前面我们其实运行了两个服务(node.js和mysql),那么有没有什么方式可以一键启动所有服务呢?答案是Docker Compose,它使用 YML 文件来配置应用程序需要的所有服务,并且可以一键启动它们。

直接来看最终的docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Docker Compose版本
version: "3"

services:
nodejs:
# 使用前面介绍的Dockerfile来构建镜像
build:
context: .
dockerfile: Dockerfile
# 镜像名
image: nodejs
# 容器名
container_name: nodejs
restart: unless-stopped
ports:
- "3000:3000"
# 依赖mysql,也就是说需要先启动mysql服务
depends_on:
- "mysql"
networks:
- app-network
mysql:
network_mode: "host"
environment:
MYSQL_ROOT_PASSWORD: "password"
image: "docker.io/mysql:5.7"
container_name: mysql
restart: always
volumes:
- "./mysql/conf/my.cnf:/etc/my.cnf"
- "./mysql/init:/docker-entrypoint-initdb.d/"
# 解决了/var/log/mysql没有权限的问题
entrypoint: bash -c "chown -R mysql:mysql /var/log/mysql && exec /entrypoint.sh mysqld"
ports:
- "3306:3306"

networks:
app-network:
driver: bridge

可以看到它有两个services,分别是nodejs和mysql。

其中有两行还需要解释一下

1
2
- "./mysql/conf/my.cnf:/etc/my.cnf"
- "./mysql/init:/docker-entrypoint-initdb.d/"

它可以让你自定义mysql的my.cnf以及执行一些初始化的sql(或脚本)

在工程中的目录结构如下,与命令中目录结构是关联的。

1
2
3
4
5
mysql
- conf
- my.cnf
- init
- init.sql

我们看一下init.sql的内容

1
2
3
USE mysql;
GRANT ALL PRIVILEGES ON *.* TO "root"@"%" IDENTIFIED BY "password";
FLUSH PRIVILEGES;

这样,之前添加从外部访问数据库权限的命令就可以自动执行了。

一键部署node.js+mysql服务

介绍到现在,我们此时的目录结构已经是这样的了,文件里的内容前面都介绍了

1
2
3
4
5
6
7
8
your-nodejs-project
- mysql
- conf
- my.cnf
- init
- init.sql
- docker-compose.yml
- Dockerfile

最后我们只要在工程的根目录执行以下命令,就可以一键部署node.js+mysql服务了。

1
docker-compose up -d

如果没有镜像(执行docker-compose命令前我把之前构建好的node.js镜像删除了),它会构建(node.js)或拉取(mysql)镜像

1
2
3
4
5
6
7
Building nodejs
Step 1/6 : FROM node:12.22.1-alpine3.10
...
Successfully built 90227eea977f
Successfully tagged nodejs:latest
Creating mysql ... done
Creating nodejs ... done

可以看到两个服务都创建完成了。

并且都成功运行了。

1
2
3
4
[root@iZ8vb55rs42xic2s53uc3yZ blog-server]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f9dbd102678f nodejs "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:3000->3000/tcp nodejs
f91b47be9d02 mysql:5.7 "bash -c 'chown -R m…" About an hour ago Up About an hour mysql

如果再执行一遍同样的docker-compose up -d命令,因为是完全相同的,且已经有镜像了,所以会很快地返回结果:

1
2
3
[root@iZ8vb55rs42xic2s53uc3yZ blog-server]# docker-compose up -d
mysql is up-to-date
nodejs is up-to-date

至此,我们成功地使用docker部署了node.js+mysql应用,以后在其它虚拟机上迁移我们的服务就方便多了,因为它可以实现一键部署。

同样的nginx、redis这些都有相应的成熟的镜像,部署的操作大同小异,这里就不再做介绍了。

0%