zd This demo shows you how working with Systemd. We will run a Node app as a daemon.
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);
});
First step, clone the code.
$ git clone https://github.com/ruanyf/node-systemd-demo.git
$ cd node-systemd-demo
Second step, modify the node-server.service
.
Replace the following placeholders with the real values.
[/path/to/node/executable]
[path/to/node-systemd-demo]
[yourUserName]
[yourUserGroup]
For example, if your node executable is /usr/bin/node
, and path to node-systemd-demo
is /tmp/node-systemd-demo
, and both of your user name and your group name is nobody
, the modified node-server.service
should look like the following.
[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
If you don't know these values, run the following commands.
# node executable path
$ which node
# your user name
$ id -un
# your group name
$ id -gn
Third step, copy the node-server.service
into Systemd.
$ sudo cp node-server.service /etc/systemd/system
Fourth step, launch the service.
# reload configure file
$ sudo systemctl daemon-reload
# start the service
$ sudo systemctl start node-server
Now visit http://0.0.0.0:5000, you should see a webpage of "Hello World".
Fifth step, check the status.
If you want to see the log, the following commands are helpful.
# check the service status
$ sudo systemctl status node-server
# view the log
$ sudo journalctl -u node-server
# view the growing log with appended output
$ sudo journalctl --follow -u node-server
Sixth step, restart / stop the service.
# restart the service
$ sudo systemctl restart node-server
# stop the servie
$ sudo systemctl stop node-server
If you want to launch the app in booting, use systemctl enable
.
$ sudo systemctl enable node-server
Now, you have done the above steps, Node listens on the TCP port 5000 and serves requests, and Systemd monitors Node and restarts it when needed. It is the time we try something new.
Systemd has a great feature called "socket activation".
[Socket Activation]
"You configure systemd to monitor the TCP port 5000, but don't launch Node. When a request comes in, Systemd will spawn Node and hand over the socket. All of this happens transparently to the client: it doesn’t know it is happening. From then on, Node handles all requests. Systemd goes back to the role of monitoring Node. When Node is done, Systemd will shut Node down automatically, and pick up the monitoring of the TCP port. The cycle can start again."
Before doing the following steps, you should ensure the Node service in the previous part has been stopped.
First step, install the dependencies.
Our socket-server.js
needs two new modules: systemd
and autoquit
.
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/');
Node module systemd
adds support for running node.js as a socket-activated service, and autoquit
detects when a server has been inactive for a period of time and shuts it down. As you see, in the above script, the timeout
option is set 60 seconds of inactivity before triggering the service shutdown method. Moreover, you could use the journald
module to add your own message into the Systemd log.
Now install the dependencies.
$ npm install
Second step, modify the node-socket-server.service
Look up the first part.
Third step, copy the configure files into Systemd.
Socket activation has two configure files.
$ sudo cp node-socket-server.socket /etc/systemd/system
$ sudo cp node-socket-server.service /etc/systemd/system
Fourth step, launch the socket activation.
$ sudo systemctl daemon-reload
$ sudo systemctl start node-socket-server.socket
Now you check the status.
$ 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)
You could see the socket is active
and the service is inactive
.
You make a visit of http://0.0.0.0:5000. Then check the stutus again.
$ 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
You could see the output is different. Both of the socket and the service is active
now.
Fifth step, stop the service and socket activation.
You turn off the service. Systemd will give you a warning.
$ sudo systemctl stop node-socket-server.service
Warning: Stopping node-socket-server.service, but it can still be activated by:
node-socket-server.socket
You should stop the socket activation as well.
$ sudo systemctl stop node-socket-server.socket
- Ruben Vermeersch, Deploying Node.js with systemd
- Mike MacCana, How to deploy your node app on Linux, 2016 edition
MIT