Bootstrap

【docker 总结】第七篇 - nodejs项目部署

node 项目部署

项目介绍

  • nodeapp 是一个用 Docker 搭建的本地 Node.js 应用开发与运行环境。

服务分类

  • db:使用 mariadb 作为应用的数据库(mariadb 开源版 MySql)

  • node:启动 node 服务

  • web:使用 nginx 作为应用的 web 服务器

app 目录结构

├── docker-compose.yml
└── images
    ├── nginx
    │   └── config
    │       └── default.conf
    └── node
        ├── Dockerfile
        └── web
            ├── package.json
            ├── public
            │   └── index.html
            └── server.js

创建项目

根据以上目录结构和服务的规划,创建项目

BravedeMacBook-Pro:~ brave$ mkdir docker-demo
BravedeMacBook-Pro:~ brave$ cd docker-demo
BravedeMacBook-Pro:docker-demo brave$ mkdir nodeapp
BravedeMacBook-Pro:docker-demo brave$ cd nodeapp/
BravedeMacBook-Pro:nodeapp brave$ mkdir images
BravedeMacBook-Pro:nodeapp brave$ touch docker-compose.yml
BravedeMacBook-Pro:nodeapp brave$ ls
docker-compose.yml	images

docker-compose.yml 的命名是固定死的,每当执行 docker compose up 时,会去当前目录下找到 docker-compose.yml 文件去启动

镜像的种类

  • node 镜像(自己写)

  • nginx 镜像(直接用)

  • mysql 镜像(直接用)

BravedeMacBook-Pro:nodeapp brave$ cd images
BravedeMacBook-Pro:images brave$ mkdir node   // node 镜像
BravedeMacBook-Pro:images brave$ mkdir nginx	// 放 nginx 配置文件
BravedeMacBook-Pro:images brave$ tree
.
|____nginx
|____node   

node 目录中创建 web 文件夹

BravedeMacBook-Pro:images brave$ cd node
BravedeMacBook-Pro:node brave$ mkdir web
BravedeMacBook-Pro:node brave$ cd web/

前提:安装 node

BravedeMacBook-Pro:web brave$ npm -v
6.14.6

初始化 node 项目

BravedeMacBook-Pro:web brave$ npm init -y
Wrote to /Users/brave/docker-demo/nodeapp/images/node/web/package.json:

{
  "name": "web",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

   ╭───────────────────────────────────────────────────────────────╮
   │                                                               │
   │      New major version of npm available! 6.14.6 → 8.3.0       │
   │   Changelog: https://github.com/npm/cli/releases/tag/v8.3.0   │
   │               Run npm install -g npm to update!               │
   │                                                               │
   ╰───────────────────────────────────────────────────────────────╯

创建 server.js

vi server.js

let http = require('http');
var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'db',
  user     : 'root',
  password : '123456',
  database : 'nodeapp'
});

connection.connect();
http.createServer(function(req, res){
  connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
    if (error) throw error;
    console.log('The solution is: ', results[0].solution);
    res.end("solution:" + results[0].solution)
  });
}).listen(3000, function(){
  console.log('node server started at port 3000');
});

安装 mysql

// mysql 生产依赖
BravedeMacBook-Pro:web brave$ npm install mysql -S
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN web@1.0.0 No description
npm WARN web@1.0.0 No repository field.

+ mysql@2.18.1
added 11 packages from 15 contributors and audited 11 packages in 14.514s
found 0 vulnerabilities

添加 node 服务启动脚本:

vi package.json

{
  "name": "web",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node server.js"   // 启动脚本
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "mysql": "^2.18.1"
  }
}

创建 public 目录,查看nodeapp 项目目录结构:

BravedeMacBook-Pro:web brave$ mkdir public
BravedeMacBook-Pro:web brave$ cd public/

BravedeMacBook-Pro:public brave$ echo index.html > index.html
BravedeMacBook-Pro:public brave$ ls
index.html

BravedeMacBook-Pro:public brave$ pwd
/Users/brave/docker-demo/nodeapp/images/node/web/public

BravedeMacBook-Pro:public brave$ cd ..
BravedeMacBook-Pro:web brave$ cd ..
BravedeMacBook-Pro:node brave$ cd ..
BravedeMacBook-Pro:images brave$ cd ..
BravedeMacBook-Pro:nodeapp brave$ tree
.
|____docker-compose.yml
|____images
| |____nginx
| |____node
| | |____web
| | | |____package.json
| | | |____package-lock.json
| | | |____public
| | | | |____index.html
| | | |____server.js

访问静态页面,进入 public 目录

访问服务,进入 server.js 处理

服务写好了,我们需要将这个 node 服务制作成为一个镜像(mysql 和 nginx 使用现成的镜像就可以)

制作镜像

创建 DockerFile 文件

BravedeMacBook-Pro:nodeapp brave$ ls
docker-compose.yml	images
BravedeMacBook-Pro:nodeapp brave$ cd images/
BravedeMacBook-Pro:images brave$ cd node/
BravedeMacBook-Pro:node brave$ vi Dockerfile

// Dockerfile
From node        // 基于 node 镜像创建新镜像
MAINTAINER Brave // 指定维护者
COPY web /web    // 拷贝项目:将当前项目中的 web 目录拷贝到镜像中
// 注意文件拷贝规则:当/web 不存在时,会将web拷贝过去,如果存在/web 会将 web 放到/web 目录下
WORKDIR /web     // 指定工作目录为 web
RUN npm install  // 在编译镜像时执行的命令:安装依赖
CMD npm start    // 在运行容器时执行的命令:启动 node 服务  (docker run 时执行)

回到 nodeapp 目录层级下,编写 docker-compose.yml

依赖关系:先启动 db 服务,再启动 node 服务,再启动 web 服务;

BravedeMacBook-Pro:node brave$ cd ..
BravedeMacBook-Pro:images brave$ cd ..
BravedeMacBook-Pro:nodeapp brave$ vi docker-compose.yml

// docker-compose.yml
version: "2"                    // 版本号,注意冒号后面需要有一个空格,否则执行会报错
services:                       // 声明服务
  db:                           // db 服务
    image: mariadb              // 指定 db 服务使用的镜像
		environment:								// 设置环境变量
		  MYSQL_ROOT_PASSWORD: "123456"
			MYSQL_DATABASE: "nodeapp"
			MYSQL_USER: "root"
			MYSQL_PASSWORD: "123456"
    volumes:										// 指定 db 服务使用的数据卷
			- dbdata:/var/lib/mysql   // 将容器的 /var/lib/mysql 映射到 宿主机的 dbdata 目录
  node:				                  // node 服务
    build:                      // 需要构建镜像 镜像如果存在就不会编译了  需要加 --build
      context: "./images/node"	// 指定构建的上下文,构建时,基于哪个文件夹作为上下文目录
      dockerfile: Dockerfile    // 会去找 ./images/node/Dockerfile 文件
  depends_on:                   // 依赖的容器
    - db 
  web:
    image: nginx
    ports:
      - "8080:80"
    depends_on:                   // 依赖的容器
      - node
    volumes:
		  - "./images/nginx/conf.d:/etc/nginx/conf.d"     // nginx 配置文件
		  - "./images/node/web/public:/public"                // 静态文件
volumes:											 // 声明数据卷
	dbdata:
		driver: local

编写 nginx 配置文件 conf.d/default.conf,配置静态/动态请求的处理规则

BravedeMacBook-Pro:nodeapp brave$ ls
docker-compose.yml	images
BravedeMacBook-Pro:nodeapp brave$ cd images/
BravedeMacBook-Pro:images brave$ cd nginx/
BravedeMacBook-Pro:nginx brave$ mkdir conf.d
BravedeMacBook-Pro:nginx brave$ cd conf.d/
BravedeMacBook-Pro:conf.d brave$ vi default.conf

// default.conf
server {
  listen 80;
  server_name localhost http://127.0.0.1;
  // 静态
  location / {
    root /public; // 注意:nginx 容器的 /public 目录已经映射到宿主机的 ./images/node/web/public
    index index.html;
  }
  // 动态
	location /api { // 以 /api 开头的请求
    proxy_pass http://127.0.0.1:3000;   // 为什么写http://node:3000 不行
  }
}

查看当前目录结构:

BravedeMacBook-Pro:nodeapp brave$ tree
.
|____docker-compose.yml
|____images
| |____nginx
| | |____conf.d
| | | |____default.conf
| |____node
| | |____Dockerfile
| | |____web
| | | |____package.json
| | | |____package-lock.json
| | | |____public
| | | | |____index.html
| | | |____server.js
| | | |____node_modules

启动 docker compose:会先下载镜像,编译镜像,

docker compose up
docker compose up --build  // 重新 build 否则修改不会生效

备注:修改镜像后,需要重新编译才能生效

关闭防火墙,防火墙配置变更后需要重启 docker

centos:

systemctl stop firewalld.service
systemctl disable firewalld.service

BravedeMacBook-Pro:nodeapp brave$ docker compose up --build
[+] Building 1.2s (9/9) FINISHED                                                                                                                                                   
 => [internal] load build definition from Dockerfile                                                                                                                          0.0s
 => => transferring dockerfile: 31B                                                                                                                                           0.0s
 => [internal] load .dockerignore                                                                                                                                             0.0s
 => => transferring context: 2B                                                                                                                                               0.0s
 => [internal] load metadata for docker.io/library/node:latest                                                                                                                1.0s
 => [internal] load build context                                                                                                                                             0.0s
 => => transferring context: 11.01kB                                                                                                                                          0.0s
 => [1/4] FROM docker.io/library/node@sha256:13621aa823b6b92572d19c08a75f7b1a061633089f37873f8b5bedb5e900e657                                                                 0.0s
 => CACHED [2/4] COPY web /web                                                                                                                                                0.0s
 => CACHED [3/4] WORKDIR /web                                                                                                                                                 0.0s
 => CACHED [4/4] RUN npm install                                                                                                                                              0.0s
 => exporting to image                                                                                                                                                        0.0s
 => => exporting layers                                                                                                                                                       0.0s
 => => writing image sha256:d0959f1669b0d14025f002e95fda0c78fb42fda35cfe6b7d9d32b889589b1e2c                                                                                  0.0s
 => => naming to docker.io/library/nodeapp_node                                                                                                                               0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
[+] Running 3/0
 ⠿ Container nodeapp-web-1   Created                                                                                                                                          0.0s
 ⠿ Container nodeapp-db-1    Created                                                                                                                                          0.0s
 ⠿ Container nodeapp-node-1  Created                                                                                                                                          0.0s
Attaching to nodeapp-db-1, nodeapp-node-1, nodeapp-web-1
nodeapp-db-1    | 2021-12-15 12:20:07+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.6.5+maria~focal started.
nodeapp-web-1   | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nodeapp-web-1   | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nodeapp-web-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nodeapp-web-1   | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nodeapp-web-1   | 10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf differs from the packaged version
nodeapp-web-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nodeapp-web-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nodeapp-web-1   | /docker-entrypoint.sh: Configuration complete; ready for start up
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: using the "epoll" event method
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: nginx/1.21.4
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: OS: Linux 5.10.76-linuxkit
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: start worker processes
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: start worker process 31
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: start worker process 32
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: start worker process 33
nodeapp-web-1   | 2021/12/15 12:20:08 [notice] 1#1: start worker process 34
nodeapp-db-1    | 2021-12-15 12:20:08+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
nodeapp-db-1    | 2021-12-15 12:20:08+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.6.5+maria~focal started.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] mariadbd (server 10.6.5-MariaDB-1:10.6.5+maria~focal) starting as process 1 ...
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Number of pools: 1
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Using crc32 + pclmulqdq instructions
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] mariadbd: O_TMPFILE is not supported on /tmp (disabling future attempts)
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Using Linux native AIO
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Initializing buffer pool, total size = 134217728, chunk size = 134217728
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Completed initialization of buffer pool
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: 128 rollback segments are active.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Creating shared tablespace for temporary tables
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: 10.6.5 started; log sequence number 42683; transaction id 14
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] Plugin 'FEEDBACK' is disabled.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Warning] You need to use --log-bin to make --expire-logs-days or --binlog-expire-logs-seconds work.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] Server socket created on IP: '0.0.0.0'.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] Server socket created on IP: '::'.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] InnoDB: Buffer pool(s) load completed at 211215 12:20:08
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Warning] 'proxies_priv' entry '@% root@4fcb1b050b06' ignored in --skip-name-resolve mode.
nodeapp-db-1    | 2021-12-15 12:20:08 0 [Note] mariadbd: ready for connections.
nodeapp-db-1    | Version: '10.6.5-MariaDB-1:10.6.5+maria~focal'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
nodeapp-node-1  | 
nodeapp-node-1  | > web@1.0.0 start
nodeapp-node-1  | > node server.js
nodeapp-node-1  | 
nodeapp-node-1  | node server started at port 3000

测试动态,静态资源访问,链路是否通常(nginx->node->mysql):

动态:

// 通过 nginx 访问 node 服务
BravedeMacBook-Pro:nodeapp brave$ curl http://localhost:8080/api
solution:2

日志:

nodeapp-node-1  | The solution is:  2
nodeapp-web-1   | 172.28.0.1 - - [15/Dec/2021:13:19:18 +0000] "GET /api HTTP/1.1" 200 20 "-" "curl/7.64.1" "-"

访问静态资源 index.html:

、BravedeMacBook-Pro:nodeapp brave$ curl http://localhost:8080/index.html
index.html

日志

nodeapp-web-1   | 172.28.0.1 - - [15/Dec/2021:13:20:48 +0000] "GET /index.html HTTP/1.1" 200 11 "-" "curl/7.64.1" "-"