Node 應用的 Systemd 啟動

阮一峰發表於2016-03-12

前面的文章介紹了 Systemd 的操作命令基本用法,今天給出一個例項,如何使用 Systemd 啟動一個 Node 應用。

本文是獨立的,不需要前面的教程作為預備知識。

一、克隆程式碼

首先,下載示例庫


$ git clone https://github.com/ruanyf/node-systemd-demo.git
$ cd node-systemd-demo

示例指令碼server.js非常簡單,就是一個 HTTP 伺服器。


var http = require('http');

var hostname = '0.0.0.0';
var port = 5000;

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World');
}).listen(port, hostname, function () {
  console.log('Server running at http://%s:%s/', hostname, port);
});

二、修改配置檔案

Systemd 啟動上面這個指令碼,需要一個配置檔案node-server.service。這個檔案的檔名可以隨便取,但是字尾名必須是.service


[Unit]
Description=node simple server

[Service]
ExecStart=[/path/to/node/executable] [path/to/node-systemd-demo]/server.js
Restart=always
User=[yourUserName]
Group=[yourUserGroup]
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=[/path/to/node-systemd-demo]

[Install]
WantedBy=multi-user.target

上面指令碼里面,有五個地方出現了四個佔位符。

  • [/path/to/node/executable]:node可執行檔案的絕對路徑
  • [path/to/node-systemd-demo]:示例庫的絕對路徑
  • [yourUserName]:你的使用者名稱
  • [yourUserGroup]:你的組名

你需要將上面這四個佔位符,改成自己電腦的設定。下面是一個已經改好的例子。


[Unit]
Description=node simple server

[Service]
ExecStart=/usr/bin/node /tmp/node-systemd-demo/server.js
Restart=always
User=nobody
Group=nobody
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/tmp/node-systemd-demo

[Install]
WantedBy=multi-user.target

如果你不知道這幾個佔位符的值,下面的命令可以幫你找出來。


# node executable path
$ which node

# your user name
$ id -un

# your group name
$ id -gn

三、配置檔案的解釋

簡單解釋一下,上面的配置檔案的幾個引數。

Unit區塊的Description欄位,是服務的簡單描述。

Service區塊的欄位含義如下。

  • ExecStart:啟動命令
  • Restart:如何重啟。always表示如果程式退出,總是重啟
  • Environment:環境變數
  • WorkingDirectory:工作目錄

Install區塊的WantedBy欄位指定,設為開機啟動時,該服務所在的 Target 是multi-user.target

四、啟動服務

現在將配置檔案拷貝到 Systemd 之中。


$ sudo cp node-server.service /etc/systemd/system

接著,就啟動服務。


# 過載配置檔案
$ sudo systemctl daemon-reload

# 啟動服務
$ sudo systemctl start node-server

訪問 http://0.0.0.0:5000,應該看到網頁顯示"Hello World"。

五、檢視狀態

如果啟動失敗,或者想檢視日誌,就要執行下面的命令。


# 檢視狀態
$ sudo systemctl status node-server

# 檢視日誌
$ sudo journalctl -u node-server

# 實時輸出最新日誌
$ sudo journalctl --follow -u node-server

六、重啟服務和停止服務


# 重啟服務
$ sudo systemctl restart node-server

# 停止服務
$ sudo systemctl stop node-server

如果想設為開機啟動,就要執行systemctl enable


$ sudo systemctl enable node-server

七、Socket 啟用

一般情況下,學到這裡,應該就夠用了。如果你還想體驗一下 Systemd 的強大功能,請接著往下讀。

我們知道,HTTP伺服器啟動在那裡,終究是耗費資源的。那麼能不能做到,只有有人訪問時,才啟動服務,否則就關閉?

這在 Systemd 裡面叫做"Socket 啟用"。開發者可以指定 Socket 監聽的埠,系統根據有沒有收到請求,自動啟動或關閉服務。不難想到,只要前面加一層負載均衡器,這就等同於實現了一個簡單的雲服務,即根據訪問量,系統自動擴容或收縮。

下面就是"Socket 啟用"的Demo。

八、安裝依賴

首先,請確認前面啟動的 Node 服務已經被關閉了,5000 埠已經釋放出來了。

然後,開啟啟動指令碼socket-server.js,你會發現多出了兩個模組:systemdautoquit


require('systemd');
require('autoquit');

var http = require('http');

var server = http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World');
});

server.autoQuit({ timeOut: 60 });
server.listen('systemd');

console.log('Server running at http://0.0.0.0:5000/');

上面程式碼中,systemd模組用於新增"Socket 啟用",autoquit模組用於指定多少時間無人訪問後,關閉 Node 服務,上面指令碼是60秒。另外,還有一個journald模組,用於向 Systemd 日誌新增內容,這個例子中沒有使用。

現在,安裝依賴。


$ npm install

九、改寫配置檔案

Socket 啟用需要兩個配置檔案。

一個是node-socket-server.socket


[Socket]
ListenStream=5000

[Install]
WantedBy=sockets.target

另一個是node-socket-server.service


[Unit]
Description=node simple server (socket activation)

[Service]
ExecStart=[/path/to/node/executable] [path/to/node-systemd-demo]/socket-server.js
User=[yourUserName]
Group=[yourGroupName]
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=[/path/to/node-systemd-demo]

上面這個檔案需要改寫佔位符。可以看到,由於不是開機啟動,配置檔案裡面沒有Install區塊;由於不需要重啟,也沒有Restart欄位。

改寫後,將它們拷貝到 Systemd。


$ sudo cp node-socket-server.socket /etc/systemd/system
$ sudo cp node-socket-server.service /etc/systemd/system

十、啟動 Socket 啟用

然後,執行下面兩個命令,啟動 Socket 啟用。


$ sudo systemctl daemon-reload
$ sudo systemctl start node-socket-server.socket

這個時候,檢查一下狀態。


$ sudo systemctl status node-socket-server.socket
● node-socket-server.socket
   Loaded: loaded (/etc/systemd/system/node-socket-server.socket; disabled)
   Active: active (listening) since 2016-03-10 20:36:41 CST; 7s ago
   Listen: [::]:5000 (Stream)

$ sudo systemctl status node-socket-server.service
● node-socket-server.service - node simple server (socket activation)
      Loaded: loaded (/etc/systemd/system/node-socket-server.service; disabled)
      Active: inactive (dead)

可以看到,node-socket-server.socket是啟用的(active),而node-socket-server.service沒有(inactive)。

這時訪問 http://0.0.0.0:5000 ,會發現網頁可以正常訪問。

然後,再檢查一下狀態。


$ sudo systemctl status node-socket-server.socket
● node-socket-server.socket
   Loaded: loaded (/etc/systemd/system/node-socket-server.socket; disabled)
   Active: active (running) since 2016-03-10 20:36:41 CST; 1min 20s ago
   Listen: [::]:5000 (Stream)

$ sudo systemctl status node-socket-server.service
● node-socket-server.service - node simple server (socket activation)
   Loaded: loaded (/etc/systemd/system/node-socket-server.service; disabled)
   Active: active (running) since 2016-03-10 20:37:55 CST; 3min 11s ago
 Main PID: 1084 (node)
   CGroup: /system.slice/node-socket-server.service
           └─1084 node /home/ruanyf/project/node-systemd-demo/socket-server.js

這時,socketservice都啟用了。

十一、停止服務

此時,如果手動停止 HTTP 伺服器,Systemd 會發出一個警告。


$ sudo systemctl stop node-socket-server.service
Warning: Stopping node-socket-server.service, but it can still be activated by:
  node-socket-server.socket

上面的警告表示,Socket 依然是啟用的,因此服務隨時可能被重啟,所以還需要關閉 Socket 啟用。


$ sudo systemctl stop node-socket-server.socket

十二、參考連結

(完)

相關文章