1 Node应用Docker化

  • 创建Dockerfile脚本文件

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    # 下载一个含有node12的操作系统
    FROM node:12
    # 创建工作路径
    WORKDIR /usr/src/app
    # 将本地的package.json复制到工作目录
    COPY package.json ./
    COPY yarn.lock ./
    RUN yarn install
    # 将本地根目录下的全部文件都拷贝至工作目录
    COPY . .
    # 暴露3000端口
    EXPOSE 3000
    # 运行命令
    CMD [ "yarn", "start"]
    
  • .dockerignore

    1
    2
    
    node_modules
    *.log
    
  • 构建用于部署的操作系统镜像

    1
    2
    3
    4
    
    // 构建之前应将项目打包为next服务
    $ yarn build
    $ docker build -t gsq/next-web-app .
    // 利用当前目录(.)下的Dockerfile构建名为“gsq/next-web-app”的镜像
    
  • 运行镜像构建容器

    1
    2
    
    $ docker run -p 3000:3000 -d gsq/next-web-app
    // 以gsq/next-web-app为镜像创建一个新容器并运行,端口映射3000:3000,同时返回容器id
    
    • 访问网址后,出现访问数据库失败的bug:

      1
      
      Error: connect ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16)
      
    • 解决1:ormconfig.json中的host更改为宿主机的ip地址

      1
      
      "host": "10.30.36.113",
      
    • 解决2:给docker run添加--network=host选项,使容器共享宿主机网络栈,并且容器不会分配自己的 IP 地址。(在本机无效)

2 购买阿里云服务器

云服务器ECS_云主机_服务器托管_弹性计算-阿里云 (aliyun.com)

  • 安装ubuntu18.04系统即可,完成创建实例后,如未设置实例密码需在管理页面进入“重置实例密码”

image-20220303103856263

  • 记录公网ip,打开终端,使用ssh连接远程机器
1
$ ssh root@47.99.70.28
  • 输入密码后则登录成功,为了防止每次登录都要输入密码,可以将本机的publickey上传至远程机器中
1
$ ssh-copy-id root@47.99.70.28
  • 可以将远程机器的ip地址放到本机hosts中,方便登录
1
2
3
4
// hosts
47.99.70.28 dev
// 登录时可简写
$ ssh root@dev
  • 如果要新增成员,可以进入~/.ssh中,vi authorized_keys编辑授权的key文件,在下方将新成员的publickey复制过来即可

3 配置应用环境

3.1 为应用创建单独的user

  • 创建一个blog用户,后续一直回车即可。会在home下创建一个blog文件夹(pwd查看当前路径)
1
$ adduser blog
  • 切换登录用户
1
$ su - blog
  • 将publickey也上传到blog用户下
1
$ ssh-copy-id blog@dev

3.2 用root用户安装docker

Install Docker Engine on Ubuntu | Docker Documentation

  • 按照步骤安装即可
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ sudo apt-get update
$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
$ sudo docker run hello-world 
  • 将blog用户添加至docker分组中
1
$ usermod -a -G docker blog

3.3 安装nodejs与yarn

1
2
3
4
# Using Ubuntu
$ curl -fsSL https://deb.nodesource.com/setup_12.x | sudo -E bash -
$ sudo apt-get install -y nodejs
$ sudo apt-get install gcc g++ make
  • 安装yarn
1
2
3
$ curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null
$ echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
$ sudo apt-get update && sudo apt-get install yarn
  • su - blog切换到blog用户,which nodejswhich yarn来验证是否安装成功并可以使用

3.4 配置bash的环境变量

1
2
3
4
$ vi ~/.bashrc
// 在第一行加入NODE环境变量
export NODE_EMV=production
// 配置完成后退出重连服务器

4 构建镜像与容器

4.1 调整源码

  • 处理生产环境下的数据库连接配置lib/getDatabaseConnection.tsx,重写host属性与database属性
1
2
3
4
5
6
7
8
9
const create = async () => {
  // @ts-ignore
  return createConnection({
    ...config,
    host: process.env.NODE_ENV === "production" ? "localhost" : config.host,
    database: process.env.NODE_ENV === "production" ? "blog_production" : "blog_development",
    entities: [Post, User, Comment],
  });
};

4.2 构建并运行镜像

  • 调整源码后,就可以使用git来拉取博客项目了
1
2
3
$ mkdir app
$ cd app
$ git clone https://github.com/GSemir0418/nextjs-blog.git
  • 由于我们为了数据安全并没有把.env.local文件上传至git,此时执行打包命令会报错
  • 所以用两种方式在服务器项目创建.env.local文件
1
2
3
4
5
// 法一
$ touch .env.local
$ vi .env.local
// 法二
$ echo 'SECRET_COOKIE_PASSWORD=56da34b1-fa9c-4c82-868f-0d8b349f797d' > .env.local
  • 构建镜像并运行(run 后一定要加 –network=host),开启前后端项目
1
2
3
4
5
6
$ cd app/nextjs-blog
// 不知为什么 需要root用户才能成功安装所有依赖
$ yarn
$ yarn build
$ docker build -t gsq/next-app .
$ docker run --network=host -p 3000:3000 -d gsq/next-app

4.3 创建并运行数据库容器

  • 在根目录创建blog-data文件夹
  • 直接使用docker run命令创建数据库容器
  • 将路径映射改为绝对路径,并添加--network=host选项
1
$ docker run --network=host -v /home/blog/blog-data/:/var/lib/postgresql/data -p 5432:5432 -e POSTGRES_USER=blog -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:12.2

4.4 --network=host命令

  • 该属性意味着容器共享宿主机网络栈,双方在网络名称空间并没有隔离(只在Linux操作系统主机上可用,不支持Mac、Windows。)

5 创建数据库

  • 当两个容器启动后,使用curl -L http://localhost:3000验证是否连接成功,此时docker会报找不到数据库的错误
  • 进入容器创建数据库
1
2
3
$ docker exec -it 586 bash
$ psql -U blog
$ create database blog_production encoding 'UTF8' lc_collate 'en_US.utf8' lc_ctype 'en_US.utf8';

6 创建数据表

  • 进入项目目录,执行yarn dev,利用babel将数据库相关代码编译为js
  • 执行同步数据库命令yarn m:run即可
  • 此时由于typeorm在migration时读取的是omrconfig.json文件,所以还需要用vim编辑配置文件
1
2
3
4
5
6
7
{
  ...
  "host": "localhost",
 	...
  "database": "blog_production",
  ...
}
  • 期间会报错,因为getDatabaseConnection模块未找到,需要用vim编辑User.ts文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 注释这两部分
...
// import { getDatabaseConnection } from "lib/getDatabaseConnection";
...
    // const hasUser = await (
    //   await getDatabaseConnection()
    // ).manager.find(User, { username: this.username });
    // if (hasUser.length > 0) {
    //   this.errors.username.push("用户名已存在");
    // }

  • 同步数据表
1
$ yarn m:run

7 阿里云安全策略

  • 目前我们服务器的本地端口3000是可以访问的,但3000端口未对公网开放,还需要进行安全策略配置

  • 配置安全组规则-配置规则-手动添加

image-20220306221916216