Yifei Kong

May 24, 2018

使用 supervisord 部署服务

在某一刻你会意识到你需要写一个长期运行的服务。如果有错误,这些脚本不应该停止运行,而且当系统重启的时候应该自动把这些脚本拉起来。

为了实现这一点,我们需要一些东西来监控脚本。这些工具在脚本挂掉的时候重启他们,并且在系统启动的时候拉起他们。

脚本

这样的工具应该是怎样的呢?我们安装的大多数东西都带了某种进程监控的机制。比如说Upstart和Systemd。这些工具被许多系统用力啊监控重要的进程。当我们安装php5-fpm,Apache 和nginx的时候,他们通常已经和系统集成好了,以便于他们不会默默挂掉。

然而,我们有时候需要一些简单点儿的解决方案。比如说我经常写一些 nodejs 的脚本来监控github上的某个动态并作相应的动作。node可以处理 http请求并且同时处理他们,也就是很适合作为一个一次性运行的服务。

这些小的脚本可能不值得使用 Upstart 或者 Systemd 这种重量级的东西。

下面是我们用来举例的脚本 我们把它放在 /srv/http.js 中

var http = require('http');

function serve(ip, port) {
        http.createServer(function (req, res) {
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.write("\nSome Secrets:");
            res.write("\n"+process.env.SECRET_PASSPHRASE);
            res.write("\n"+process.env.SECRET_TWO);
            res.end("\nThere's no place like "+ip+":"+port+"\n");
        }).listen(port, ip);
        console.log('Server running at http://'+ip+':'+port+'/');
}

// Create a server listening on all networks
serve('0.0.0.0', 9000);

All this service does is take a web request and print out a message. It's not useful in reality, but good for our purposes. We just want a service to run and monitor.

Note that the service prints out two environmental variables: "SECRET_PASSPHRASE" and "SECRET_TWO". We'll see how we can pass these into a watched process.

这个服务仅仅是接受一个 http 请求并打印一条消息。在现实中并没有什么卵用,但是用来演示很好。我们只是需要一个服务来运行和监控。

注意到这个服务打印两个变量 "SECRET_PASSPHRASE" 和 "SECRET_TWO"。我们将会演示如何把这个传递个被监控的进程。

Supervisord

Supervisord is a simple and popular choice for process monitoring.

Supervisord 是一个使用很广也很简单的进程监控工具。

安装

建议使用系统的包管理器安装,虽然可能版本稍微老一点,但是。不过 supervisor 还不支持 python 3,所以必须使用 python 2 版本。

brew install supervisor

在 linux 上可以通过apt-get来安装 supervisor,同样的命令。

apt-get install supervisor
service supervisor start

配置

下面我们来配置一个 supervisor 服务。

打开 /etc/supervisor/supervisord.conf,我们可以看到最后一行:

[include]
files = /etc/supervisor/conf.d/*.conf

所以我们只需要把我们的配置文件放在 /etc/supervisor/conf.d 文件夹下就好了。

[program:nodehook]
command=/usr/bin/node /srv/http.js
directory=/srv
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/webhook/nodehook.err.log
stdout_logfile=/var/log/webhook/nodehook.out.log
user=www-data
environment=SECRET_PASSPHRASE='this is secret',SECRET_TWO='another secret'

每个选项如下:

  • [program:nodehook] 定义运行的服务的名字。
  • command 启动被监控的服务的命令,如果你需要传递命令行参数的话,也放在这里
  • directory 设定进程的运行目录
  • autostart 是否需要在 supervisord 启动的时候自动拉起
  • autorestart 是否在程序挂掉的时候自动重新拉起
  • startretries 如果启动失败,重试多少次
  • stderr_logfile 标准错误输出写入到哪个文件
  • stdout_logfile 标准输出写入到哪个文件
  • user 运行进程的用户
  • environment 传递给进程的环境变量

需要注意的是,supervisor 不会自动创建日志文件夹,所以需要我们首先创建好。

sudo mkdir /var/log/webhook

supervisor 配置文件的搜索路径包括:

/usr/local/etc/supervisord.conf
/usr/local/supervisord.conf
supervisord.conf  # 当前目录
etc/supervisord.conf
/etc/supervisord.conf
/etc/supervisor/supervisord.conf

控制进程

可以使用 supervisorctl 来控制对应的服务了。不过需要首先启动 supervisord 的daemon 才行。

supervisorctl reread
supervisorctl update

这样就可以启动刚刚定义的服务。supervisorctl 的其他功能可以查看帮助

Web 界面

We can configure a web interface which comes with Supervisord. This lets us see a list of all processes being monitored, as well as take action on them (restarting, stopping, clearing logs and checking output).

supervisor 自带了一个 web 界面。这样我们就可以通过浏览器来管理进程了。

Inside of /etc/supervisord.conf, add this:

在 /etc/supervisord.conf 中添加:

[inet_http_server]
port = 9001
username = user # Basic auth username
password = pass # Basic auth password

If we access our server in a web browser at port 9001, we'll see the web interface:

ref: https://serversforhackers.com/c/monitoring-processes-with-supervisord