PM2のデプロイのイメージ
pm2はforeverと類似のプロセスマネージャですが、foreverと比べると以下のようなメリットがあります。
というわけで今回、Gitリポジトリからのデプロイ機能をexpress(typescript)で構築したサーバで試してみました。デプロイのイメージは以下のような感じです。
基本として、pm2でデプロイを行う場合の注意点としてNodeのモジュールはすべてアプリケーションにローカルインストールし、node_modulesディレクトリをGitリポジトリにコミットしておく必要がありますが、以下の手順では、毎回npm installを実行してオンラインから必要なNodeのモジュールをインストールしています。
環境
開発クライアント
- Windows 10 build 19042
- Visual Studio Code 1.57.1
- Node.js v14.16.1
- pm2 2.4.5
- git 2系
デプロイするサーバ
テスト用プロジェクトを作成
プロジェクトフォルダの作成
mkdir work
cd work
必要なモジュールのインストール(Typescript使うため)
tsc, ts-nodeをインストールして、tsconfig.jsonも生成しておきます。
npm init -y
npm install -D typescript
npm install -D @types/node
npm install -D ts-node
npx tsc --init
expressのインストール
expressとtypesをインストールします。
npm install express
npm install -D @types/express
テストコードの実装
色々実装です。とりあえず実装用のファイルを作成。
touch index.ts
index.tsに以下の記述をします。とりあえずGETだけ実装。
ここで利用したAPIを再利用。
index.ts
import express from 'express'
const app: express.Express = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
//CROS対応(というか完全無防備:本番環境ではだめ絶対)
app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "*")
res.header("Access-Control-Allow-Headers", "*");
next();
})
app.listen(3000, () => {
console.log("Start on port 3000.")
})
type User = {
id: number
name: string
email: string
};
const users: User[] = [
{ id: 1, name: "User1", email: "user1@test.local" },
{ id: 2, name: "User2", email: "user2@test.local" },
{ id: 3, name: "User3", email: "user3@test.local" }
]
//一覧取得
app.get('/users', (req: express.Request, res: express.Response) => {
res.send(JSON.stringify(users))
})
ビルド後の出力先の変更
tsconfig.jsonの編集します。
{
"compilerOptions": {
:
"outDir": "./dist", /* Redirect output structure to the directory. */
:
}
}
package.jsonの編集します。
{
:
"main": "dist/index.js",
:
}
実行と動作確認
では動作確認。
実行
expressの実行は下記の通り。
npm run build
npm start
Start on port 3000.
とりあえずcurlで動作確認。
curl -s -X GET http://localhost:3000/users | python -mjson.tool
[
{
"email": "user1@test.local",
"id": 1,
"name": "User1"
},
{
"email": "user2@test.local",
"id": 2,
"name": "User2"
},
{
"email": "user3@test.local",
"id": 3,
"name": "User3"
}
]
ローカルポジトリの作成(Git)
gitでローカルポジトリ作成し、上で作成したテスト用プロジェクトを登録します。
git init --initial-branch main
git add .
git commit -m "initial commit"
注意)Gitのバージョン 2.28 からconfigでgit init
で作成するリポジトリのデフォルト・ブランチ名を設定できるようになっています。たとえば、以下のコマンドでデフォルト・ブランチ名をmain
に設定できます。
git config --global init.defaultBranch main
これでgit init
コマンドでリポジトリを作成する際に作られるブランチ名がmain
になります。
リモートポジトリの作成(Github)
ローカルリポジトリからリモートリポジトリに移動させる時に、受け皿つくります。
githubにログインし、左上の赤枠で囲まれたプラスをクリックします。
プルダウンでメニューが出てくるので、New repositoryをクリックします。
リポジトリの作成の画面になります。
Privateを選択し、Initialize this repository with a READMEはチェックしないで、「Create repository」をクリックします、github上での受け皿が完成します。
リモートポジトリへ登録(Github)
コマンドプロンプトに移動して以下のようなコマンドを打ちます。
git remote add origin [リモートリポジトリ情報]
コマンドにて、githubへプッシュします。
git push origin main
githubのページをリロードすると、しっかり反映が確認できます。
PM2+デプロイ環境の作成
パッケージのインストール
npm install -g pm2
その他パッケージのインストール
npm install dotenv
envファイルを作成(.gitignoreでgithubへは登録されません)
touch .env
envファイルを以下のように編集します。GITHUB_PASSWORDはgithubのkeyをします。
GITHUB_USER=tokuda
GITHUB_PASSWORD=xxxxxxxxxxxxx
HOST=192.168.xxx.xxx
SSH_PRIVATE_KEY_PATH=~/.ssh/id_rsa
GITHUB_PASSWORDはgithubより以下の手順にします。
- githubへログイン
- プロフィール画像をクリックし、
Settings
をクリック - 左サイドバーで
Developer settings
をクリック - 左のサイドバーで
Personal access tokens
をクリック Generate new token
をクリック- トークンを使用目的に則して設定する, その後
Generate token
をクリック - トークンをGITHUB_PASSWORDにコピーする。
注意)トークンはページを離れると参照不可になる。
pm2用のデプロイファイルを作成
pm2 ecosystem
ecosystem.config.jsを編集
上で作成されたecosystem.config.jsをVSCodeで開き、以下のように編集します。
require('dotenv').config();
var user = encodeURIComponent(process.env.GITHUB_USER);
var password = encodeURIComponent(process.env.GITHUB_PASSWORD);
var keyPath = process.env.SSH_PRIVATE_KEY_PATH || "~/.ssh/id_rsa";
module.exports = {
/**
* Application configuration section
* http://pm2.keymetrics.io/docs/usage/application-declaration/
*/
apps : [
// First application
{
name : "hello-world",
script : "npm",
args : "start",
env: {
PORT: 3000
},
env_production : {
NODE_ENV: 'production',
}
}
],
/**
* Deployment section
* http://pm2.keymetrics.io/docs/usage/deployment/
*/
deploy : {
production : {
"key" : keyPath,
"user" : user,
"host" : [process.env.HOST],
"ref" : "origin/main",
"repo" : "https://"+user+":"+password+"@github.com/YujiTokuda/hello-world.git",
"ssh_options" : "StrictHostKeyChecking=no",
"path" : "/home/"+user+"/hello-world",
"post-setup" : "npm install",
"post-deploy" : "pm2 restart ecosystem.config.js --env production"
}
}
};
pm2ではデプロイ先を複数指定できます。
"host" : ["XXX.XXX.XXX.XXX", "YYY.YYY.YYY.YYY", "ZZZ.ZZZ.ZZZ.ZZZ"],
package.jsonを編集
スクリプトに下記コマンドを登録します。
{
:
"scripts": {
"start": "npm run build && node ./dist/index.js",
"dev:debug": "rm -rf dist && set DEBUG=* && tsc-watch --noClear --onSuccess \"node -r pino-debug ./dist/index.js\" | pino-pretty -t \"SYS:yyyy-mm-dd HH:MM:ss.l o\"",
"build": "tsc",
"lint": "eslint -c .eslintrc.js \"src/**/*.{js,ts,tsx}\" --quiet",
"lint:fix": "eslint -c .eslintrc.js \"src/**/*.{js,ts,tsx}\" --quiet --fix",
"deploy:setup": "pm2 deploy ecosystem.config.js production setup",
"deploy:update": "pm2 deploy ecosystem.config.js production update"
},
:
}
デプロイの実行
npm run deploy:setup
npm run deploy:update
ローカルマシンからデプロイ先(Linuxを想定)サーバにデプロイは完了です。
デプロイ先の動作確認
再度curlで動作確認。
curl -s -X GET http://192.168.xxx.xxx:3000/users | python -mjson.tool
[
{
"email": "user1@test.local",
"id": 1,
"name": "User1"
},
{
"email": "user2@test.local",
"id": 2,
"name": "User2"
},
{
"email": "user3@test.local",
"id": 3,
"name": "User3"
}
]
デプロイ先サーバにtelnetでログインし、以下のコマンドを実行します。
pm2 dashboard
最後に
デプロイ先サーバは以下を設定済みとして進めています。
1.SSHのログイン環境
2.node.js
3.PM2