好 pm2, 不用嗎?
前言
pm2 是什麼?
- pm2 是一個 node 的程序管理器
pm2 解決什麼問題?
- pm2 可以讓 node 服務 crash 掉之後,自動幫我們重啟
- pm2 可以在 server 重啟之後,自動幫我們重啟
- pm2 可利用 CPU 多核,開啟多程序,已達到類似負載平衡的效果
- Graceful reload 可達成類似 rolling upgrade 的效果,0 downtime 升級
- 多程序多服務,可提升處理 request 的速度
- 可設定 cron 排程自動重啟時間
- pm2 提供多項資訊,包含已重啟次數、 CPU 用量、 memory 用量, process id, 等等…
- pm2 可以在指定的條件下,自動幫我們重啟,條件可以是’up time’, ‘已使用多少 memory’, 等等…,
- pm2 可以幫我們整理 log, 讓 log 以我們想要的週期分割檔案,並保存我們想要的數量,若有超過,自動刪除。
- pm2 提供簡單的部署方式,可一次性部署到多台 server
- pm2 可與 CD / CD 工具做結合, CI / CD 部署也沒有問題
好 pm2, 不用嗎?
本篇將提到:
- 安裝 pm2
- 使用
CLI
啟動 pm2 - 使用 pm2 設定檔
ecosystem
啟動 pm2 - 使用 pm2 設定檔
ecosystem
部署 node 專案 - 使用 pm2 搭配
GitLab CI / CD Runner
部署 node 專案
安裝
- 全域安裝
pm2 with CLI
可以使用 pm2 CLI
來啟動 node 專案, 範例如下:
以上範例中設定代表的意思,參考如下:
開始可以附加的參數
--name
指定 app 一個名字--watch
檔案有變更時,會自動重新啟動--max-memory-restart
Memory 使用超過這個門檻時,會自動重啟--log
指定 log 的位址, 若要指定新位址,需將原本的 process 刪掉,再重新啟動指定--output
指定 output log 位址--error
指定 error log 位址--log-date-format
指定 log 的格式--merge-logs
同一個 app 跑多程序時,不要依據程序 id 去分割 log, 全部合在一起--arg1
--arg2
--arg3
指派額外的參數--restart-delay
自動重啟時,要 delay 多久--time
給 log 加上前綴--no-autorestart
不要自動重啟--cron
指定 cron 規律,強制重啟--no-daemon
無 daemon 模式, listen log 模式
叢集模式
- pm2 自動偵測該機器的 CPU 數量,啟動最大能負荷的 process, 適用上面的選項,
-i
後面接希望啟動 instance 的數量, 0 或 max 默認自動偵測 CPU 啟動最大值
管理程序
- 直接 kill 掉 process, 再重新開始程序
- 如果是在 cluster mode,
reload
會依序升級重啟每一個程序,達到 zero downtime 升級
- 停止服務
- 停止並刪除服務
- 除了 app_name 之外,你也可以指定
all
: 啟動所有程序id
: 該程序 id
顯示管理程序狀態
Logs
- 輸出 log
- 顯示指定行數 log (指定倒數 200 行)
- 指定輸出程序 log
- 指定輸出格式
- 清空 log
- 取消 log 可以利用指定 log 路徑為
/dev/null
來取消 log 輸出, log 參數用法請參考 ecosystem 範例
循環 log
如果你看過 log 檔案超肥,幾年的 log 都寫在同一個檔案; 如果你打開 log 資料夾,發現裡面躺著幾百個 log 檔案; 如果你看過千奇百怪的 log 檔名; 如果你 du -h
發現 log 資料夾大的嚇死人 如果你有以上的經驗,那恭喜你,你有救了
安裝
config 檔位置
/home/user/.pm2/module_conf.json
參數
- max_size (預設 10M): 當 log 檔案達到多大時, logrotate module 會將它分割成另外一個檔案。 logrotate module 有可能在檢查檔案時,檔案已經超過指定的大小了,所以超過一些些是可能的。 單位可以自行指定, 10G, 10M, 10K
- retain (預設 30 個 log 檔案): 預設最多保存的 log 數量,如果設定為 7 的話,將會保存目前的 log, 以及最多 7 個 log 檔案
- compress (預設 false): 壓縮所有循環 log 檔案
- dateFormat (時間格式,預設 YYYY-MM-DD_HH-mm-ss) : 檔案命名的時間格式
- rotateModule (預設 true) : 跟其他 apps 一樣,循環 pm2’s module
- workerInterval (預設 30 秒) : 多久 logrotate 會檢查一次 log 檔案大小
- rotateInterval (預設每天午夜循環, 範例 0 0 * * * ): 除了設定檔案大小以外,我們也可以設定以時間為單位去循環,格式上採用
node-schedule
- TZ (預設為系統時間): 檔案命名的時間會根據你所設定的時區而改變
圖示
terminal 監控面板
pm2 ecosystem
CLI 工具固然不錯,但只要是人難免手滑打錯或漏打參數。 pm2 ecosystem 解決了這個問題,只要好好的打上一次,以後除非設定有變更,否則啟動服務只需要短短幾個指令,而且 ecosystem 檔案還可以納入 git 控管,跟著專案跑
- 產生範例 ecosystem file
CLI
跟前面介紹過的管理程序一樣,差別只是將 app.js 換成 ecosystem.js 多個管理程序 CLI, 這邊就只列出 start, 其餘同上
從 ecosystem 中只啟動特定 app
下面的 appName 為我們寫在 ecosystem.config.js 檔案中的 appName
帶入參數
拿下面的範例來說,如果我輸入 pm2 start ecosystem --only app1 --env production
, 那麼 pm2 就會使用 NODE_ENV=production
這個環境變數
參數範例
下面的參數有點多,我們肯定不會一次使用到這麼多的參數,所以可以視專案需求留下我們需要的參數即可
pm2 部署
pm2 的部署功能,可以讓我們從本機直接部署到多台 server 上, 也可以結合 CI / CD 工具,在提交 commit 後自動部署
部署前的必要條件
- 首先要先確定,local 到 remote 端的 ssh key 有準備好了嗎?
local 到 remote server 的 ssh 連線是必要的哦
! 簡單來說,你需要在 local 放一把 private key, 然後在你的 remote server 放一把 public key, 這樣才能暢通無阻哦! 這部分再麻煩 Google 一下哦! - 再來,因為 pm2 會 ssh 到 remote server 上,然後在 remote server 上從我們的專案處 GitHub 或 GitLab 將專案 clone 下來,所以務必確保
remote server 是可以從 GitHub 或 GitLab clone 我們的專案
, 所以你要在 remote server 上放一把 clone 用的 private key, 然後將 public key 放在 GitLab 或 GitHub 上,這部分也是麻煩 Google 一下哦 - 由於首次 ssh 連線時會跳詢問是否將 public key 加入到 known host,這個 prompt 會讓 pm2 deploy 卡住,所以務必先將 remote server 設定好哦! 可以先連線一次,也可以修改 ssh config, 取消這個 hostKey 的 確認功能。
- 接下來,要將 ecosystem 設定檔寫好,這部分請參考上方的 deploy 範例
- 最後,請確認 remote server 的 ssh 通道 (預設 port 22) 不是關閉的哦!
初始化遠端資料夾
在部署之前, 先在 remote server 上初始化專案的資料夾, 可以帶入不同的參數讓 pm2 根據設定檔做相對應得部署
部署
- 部署 在初始化遠端資料夾之後,我們就可以使用 pm2 的部署功能了
- deploy 可使用的參數如下,也可使用
pm2 deploy help
查看
部署相關指令
強制重啟
pm2 的部署,會要求 local 端先將變更推上 Git repository, 然後 pm2 會在 remote server 執行 git pull, 所以當 local 的變更尚未推上 Git 時,部署會失敗。 這時候如果我們硬要部署,我們可以使用
CI / CD 部署
- 利用 GitLab 的 CI / CD Runner 配合 pm2 來跑自動部署, 以下為 gitlab.yml 檔案範例
- 設定好之後,只要 git push 到 master branch, 就會觸發 GitLab CI / CD Runner 自動完成 CI / CD
開機自動啟動
- 產生開機 script
- 取消開機自動重啟
- 儲存下次重啟時,預設啟動的 process
- 如果有更新 node 的版本,記得更新 script
有變更時重啟
監看該資料夾下的所有檔案,以及子資料夾,並且忽略 node_module
這個資料夾
更新 PM2
常用指令
自動補齊
- 支援 pm2 指令可以打
tab
自動補齊
疑難雜症
遇到錯誤 Error: ENOENT: no such file or directory, uv_cwd
意思是說, pm2
的工作目錄資料夾不存在,所謂的工作目錄資料夾就是我們第一次啟動 pm2
的位置。很可能是我們啟動之後,就不小心把它刪了,如果要尋找工作目錄資料夾在哪,可以使用下面的 command
- 找到
pm2
的 process id
- 然後查詢該 process 執行時所在的目錄(將上面得到的 process id 替換下面的
PM2_Process_ID
- 公布結果
結果應該會如下, 最後的 deleted
表示該目錄已經被刪除了
現在知道原因了,那解決的方法呢? 我們要先把目前的 process 砍掉,然後到一個安全一點的地方在開啟一次,以免下次又被誤刪了!
- 殺掉 pm2 process id
kill -9 processID
- 到一個安全不會再被意外砍掉的目錄再次啟動
pm2
參考資料
Write Medium in Markdown? Try Markdium!