如何用pm2部署java全栈项目

标题说的java全栈项目特指前端采用vue/react/angular等前端框架,后端采用java技术栈开发的项目。

一直以来我走的技术路线都是全栈路线,从2014-2015年左右特别火的MEAN(mongodb+expressjs+angularjs+nodejs)框架到现在的vue+java技术栈,包括服务器部署和运维都是自己在做。说到项目部署,之前用过很长一段时间简单但不粗暴的screen命令,比如screen -L -S some_awesome_project_namescreen -r pidscreen -list都是常用的几个,当然还有ctrl+a+d,这个是退出项目的日志终端但是不杀掉该进程的命令,这套部署方案没什么不好,只是功能太少,只适合于demo项目或者测试环境,正式项目或者对项目质量要求比较高的场景下并不适合。然后用过一小段docker技术栈,docker从2013年发布起就非常火,周边生态也越来越壮大,基于容器的各种持续集成和持续交付的架构方案也出现很多,现在最火的要数kubernete了。但是缺点就是比较耗资源,一个镜像文件少则800M,多则几个g。当然如果项目预算比较充足,采用docker容器集群作为架构方案的话,也就不在乎资源问题了,如果是单机的话,还是有种杀鸡用牛刀的感觉。虽然docker和kubernete是时下最热门的技术,但是考虑自己公司的情况和项目的实际需求,我最终还是决定用pm2部署。

服务器初始化

写了一个脚本,分享出来。

#!/bin/bash

# install jdk
sudo apt-get update
sudo apt-get install -y openjdk-8-jdk
java -version

# install mvn
cd ~
wget https://mirrors.ocf.berkeley.edu/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz
sudo tar -xvzf apache-maven-3.5.4-bin.tar.gz
sudo mv apache-maven-3.5.4 /opt
sudo ln -s /opt/apache-maven-3.5.4/bin/mvn /usr/bin/mvn
mvn -version

# install nodejs and pm2
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y build-essential
node -v
npm -v
sudo npm install -g pm2 --registry=https://registry.npm.taobao.org
pm2 l

# install git
sudo apt install -y git
ssh-keygen -t rsa -C $1
cat ~/.ssh/id_rsa.pub

使用方式是命令行执行:

./setup.sh "anythingcanputhere"

解释一下:

  • 参数"anythingcanputhere"会替换脚本里的$1,用于生成ssh公私钥
  • 第一部分是安装jdk,Oracle的jdk越来越不好安装了,以后用openjdk好了。apt-get install后面加上-y可以一直执行到完,不会提示你确认yes or no而中断执行了
  • 第二部分是安装maven,注意sudo ln -s /opt/apache-maven-3.5.4/bin/mvn /usr/bin/mvn这行命令是新建软连接,如果没有这步,后面执行pm2 deploy命令的时候会提示找不到mvn命令而退出
  • 第三部分是安装nodejs和pm2
  • 第四部分是安装git和生成ssh公私钥。服务器需要用git命令从代码仓库拉取代码。生成公私钥以后,需要把~/.ssh/id_rsa.pub文件里的内容拷贝到你的代码仓库的设置 -> SSH公钥里。如果你的代码仓库里没有这台服务器的ssh公钥,拉取代码就会失败

配置文件

执行pm2 deploy部署命令时需要指定配置文件。分享一个例子:

const ENV = {
  "env_dev": {
    "PROFILE": "dev"
  },
  "env_prod": {
    "PROFILE": "prod"
  },
  "env_test": {
    "PROFILE": "test"
  }
};

module.exports = {
  apps: [
    {
      "name": "pm2-demo-project",
      "script": "/usr/bin/java",
      "args": [
        "-Xms128m",
        "-Xmx256m",
        "-Djava.security.egd=file:/dev/./urandom",
        "-jar",
        "pm2-demo-project/target/pm2-demo-project-0.0.1-SNAPSHOT.jar"
      ],
      "exec_interpreter": "",
      "exec_mode": "fork",
      ...ENV
    },
  ],
  deploy: {
    test: {
      host: ['192.168.1.103'],
      user: 'wubin',
      ssh_options: "StrictHostKeyChecking=no",
      ref: 'origin/test',
      repo: "[email protected]:wubin/pm2-demo-project.git", 
      path: "/home/demo/deploy/demo/pm2-demo-project",
      "post-deploy": "sh deploy.sh test",
    }
  }
};

解释一下:

  • apps部分是配置启动某个应用的命令,包括可执行文件和参数,以及自定义的环境变量
  • deploy部分是服务器的信息。如果到这里还需要执行一步命令:
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

即设置免密码登录。这样就不必每次部署都要输入服务器密码了,这不是必须的,只是为了更方便。post-deploy是配置实际启动服务的命令

下面我们看看deploy.sh里有什么:

#!/bin/bash
mvn clean install
pm2 reload ecosystem.config.js --env $1

解释一下:

  • $1接受执行脚本时的第一个传参,--env指定了当前的环境是配置文件里的env_devenv_prodenv_test的其中之一,注意传参的时候把前缀env_去掉,相应的自定义环境变量就会生效
  • pm2 reload表示重启配置文件里的apps属性的服务。如果原来就没有,那就会启动。需要注意的是,如果之前没有采用pm2 deploy的方式部署,而是手动在服务器执行pm2 start命令并且项目代码的路径不是/home/demo/deploy/demo/pm2-demo-project的话,必须先用pm2 delete命令把已经存在的服务删掉,否则pm2 reload重启的jar包还是之前路径下的jar包

部署

理解了上面的内容,部署就容易了:

  • 第一步需要初始化部署路径下的目录结构,包括拉取代码,只需初始化一次:
pm2 deploy ecosystem.config.js test setup
  • 第二步执行:
pm2 deploy ecosystem.config.js test update

输出示例:

➜  pm2-demo-project git:(test) pm2 deploy ecosystem.config.js test update
--> Deploying to test environment
--> on host 192.168.1.103
fatal: no upstream configured for branch 'test'
  ○ deploying origin/test
  ○ executing pre-deploy-local
  ○ hook pre-deploy
  ○ fast forward test
已经位于 'test'
您的分支与上游分支 'origin/test' 一致。
来自 code.xxx.com:wubin/pm2-demo-project
 * branch            test      -> FETCH_HEAD
Already up-to-date.
  ○ executing post-deploy `sh deploy.sh test`
[INFO] Scanning for projects...
// 省略
.
.
.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] pm2-demo-project 0.0.1-SNAPSHOT .................... SUCCESS [  0.422 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 20.120 s
[INFO] Finished at: 2020-05-21T13:43:09+08:00
[INFO] ------------------------------------------------------------------------
[PM2] Applying action reloadProcessId on app [pm2-demo-project](ids: 0)
[PM2] [pm2-demo-project](0) ✓
  ○ hook test
  ○ successfully deployed origin/test
--> Success

pm2是非常好用的部署工具,但有时也会遇到一些小坑。有任何疑问,欢迎一起探讨。

你可能感兴趣的:(如何用pm2部署java全栈项目)