Supervisor
是一个强大的 进程管理工具。
在非容器化管理的服务器上, Supervisor
是有非常广泛的使用场景的。
例如:
服务批量重启,多服务按顺序启动,服务oom后自动拉起,服务std日志收集等,甚至服务健康检查它都能做。
原 Supervisor (Python)
Contents
git: https://github.com/Supervisor/supervisor
doc: http://supervisord.org/
新轮子 Supervisor (Golang)
git: https://github.com/ochinchina/supervisord
对比
两个 Supervisor 对比
指标\语言 | Python | Golang |
---|---|---|
起源 | 2004 | 2017 |
当前版本 | 4.2.4 | 0.7.3 |
语言版本要求 | 2.7+ 或 3.4+ | 1.11+ |
*unix | 支持 | 支持 |
MacOS | 支持 | 支持 |
Widnows | 不支持 | 能跑 |
安装包大小 | Pyton环境(40MB) + 脚本(490KB) | 4.2MB |
Web GUI | 支持 | 支持 |
功能支持情况
共呢个\语言 | Python | Golang |
---|---|---|
分组 | 支持 | 支持 |
挂了自动拉起 | 支持 | 支持 |
定时重启 | 支持 | 支持 |
web端管理 | 支持 | 支持 |
监控文件自动重启 | 支持 | 支持 |
依赖顺序启动 | 支持 | 支持 |
… |
这里只是列举了常用的功能,基本都实现了的,依靠golang
的 按需runtime
+可执行代码
打包后,二进制部署相较 python
是更为方便和小巧的。
安装
gihub 上没有二进制包,需要clone代码,手动编译。
$ git clone https://github.com/ochinchina/supervisord
$ cd supervisord
$ go generate
# 以下代码会编译出 linux 平台二进制可执行文件
$ GOOS=linux go build -tags release -a -ldflags "-linkmode external -extldflags -static" -o supervisord
# mac 下
$ go build -tags release -o supervisord
试试
$ ./supervisord --help
Usage:
supervisord [OPTIONS] <command>
Application Options:
-c, --configuration= the configuration file
-d, --daemon run as daemon
--env-file= the environment file
Help Options:
-h, --help Show this help message
Available commands:
ctl Control a running daemon
init initialize a template
service install/uninstall/start/stop service
version show the version of supervisor
使用
- 先创建一个配置文件
$ vi supervisor.conf
[program:test]
command = watch -n 5 "echo Hello!"
- 启动
$ supervisord -c supervisor.conf
INFO[2022-10-15T17:31:24+08:00] load configuration from file file=./supervisor.conf
INFO[2022-10-15T17:31:24+08:00] create process:test
INFO[2022-10-15T17:31:24+08:00] stop listening
INFO[2022-10-15T17:31:24+08:00] try to start program program=test
DEBU[2022-10-15T17:31:24+08:00] wait program exit program=test
INFO[2022-10-15T17:31:25+08:00] success to start program program=test
## 此时该 supervisord 会前台运行,退出终端,或者 Ctrl+C 都会推出,会结束所有的程序。
^CINFO[2022-10-15T17:32:39+08:00] receive a signal to stop all process & exit signal=interrupt
INFO[2022-10-15T17:32:39+08:00] stop the program program=test
INFO[2022-10-15T17:32:39+08:00] force to kill the program program=test
INFO[2022-10-15T17:32:39+08:00] Send signal to program program=test signal=killed
INFO[2022-10-15T17:32:39+08:00] program stopped with status:signal: killed program=test
INFO[2022-10-15T17:32:39+08:00] program exited program=test
INFO[2022-10-15T17:32:39+08:00] Stopped by user, don't start it again program=test
- 启动并运行到后台
$ supervisord -c supervisor.conf -d
这样就启动了
http 管理
supervior
同样提供了 Web GUI
管理入口,我们来启用配置试试
[program:test]
command = watch -n 5 "echo Hello"
[inet_http_server]
port=127.0.0.1:9001
访问: http://127.0.0.1:9001 即
同样支持 http Auth
, 按照如下配置
[inet_http_server]
port=127.0.0.1:9001
username=test1
password=thepassword
注意: Shutdown 是停掉 supervisor 服务本身,包括 Web 入口,需要登陆到服务器,手动启动后,才能继续使用。要停掉所有自程序,选择全部然后点击
Stop Select
。
文件监控
当我们部署,或更新程序时,希望 supervisor
能自动关闭,并运行新的可执行文件,那么 文件监控
功能就派上用场了。
go-supervisor
支持多种文件监控模式:
- 执行的程序本身监控
- 某个文件夹内监控
- 文件监控
- 配置方式
[program:golang]
command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.toml
restart_when_binary_changed=true
这里的测试代码我放到文章最后了
INFO[2022-10-15T20:33:20+08:00] program is changed, restart it program=golang
INFO[2022-10-15T20:33:20+08:00] stop the program program=golang
INFO[2022-10-15T20:33:20+08:00] force to kill the program program=golang
INFO[2022-10-15T20:33:20+08:00] Send signal to program program=golang signal=killed
INFO[2022-10-15T20:33:20+08:00] program stopped with status:signal: killed program=golang
INFO[2022-10-15T20:33:20+08:00] program exited program=golang
INFO[2022-10-15T20:33:20+08:00] Stopped by user, don't start it again program=golang
INFO[2022-10-15T20:33:21+08:00] try to start program program=golang
DEBU[2022-10-15T20:33:21+08:00] wait program exit program=golang
INFO[2022-10-15T20:33:22+08:00] success to start program program=golang
监控到变化后,重启方式也有两种,一种是:直接kill。另一种是发送信号量给程序,让程序自行处理。
注意: 如果 supervisor 本身发了 kill 信号给程序,程序自己结束了,superviosr 默认也不会帮你在重启程序,它的设计逻辑时,我只负责发信号,其他程序自理。这里你可以手动新增一条配置:
[program:golang]
command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.toml
restart_when_binary_changed=true
autostart=true # 这行配置
如果管理了在线的大流量服务,推荐使用第二种,平滑重启,因为直接kill程序,会导致请求处理一半,或事务进行到一半中止,进而数据不一致。
好的,我们再次调整配置
[program:golang]
command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.toml
restart_when_binary_changed=true
restart_signal_when_binary_changed=9 # SIGKILL
来看下日志:
INFO[2022-10-15T20:37:58+08:00] program is changed, restart it program=golang
INFO[2022-10-15T20:37:58+08:00] Send signal to program program=golang signal=terminated
INFO[2022-10-15T20:37:58+08:00] program stopped with status:exit status 0 program=golang
INFO[2022-10-15T20:37:58+08:00] program exited program=golang
INFO[2022-10-15T20:37:58+08:00] Don't start the stopped program because its autorestart flag is false program=golang
注意这里的日志,说的是,supersivor 给程序发了 信号,但是程序退出了,由于,你启用自动重启配置,所有,没有启动该程序。
这里是信号发错了,调整一下:
[program:golang]
command = /Users/paulxu/golang/go-learn/main -conf ./Users/paulxu/golang/go-learn/config.toml
restart_when_binary_changed=true
restart_signal_when_binary_changed=SIGHUP # 1 这里填数字字符都行
这下重新启动supervisor
,看下效果。
程序运行日志:
2022-10-16 11:00:27.754 [INFO] main.go:13: start
2022-10-16 11:00:27.754 [INFO] main.go:21: waiting signal~
2022-10-16 11:00:28.755 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:29.757 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:30.761 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:31.765 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:32.768 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:33.771 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:34.774 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:35.779 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:36.783 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:37.659 [INFO] main.go:32: golang get signal hangup [sighup]
2022-10-16 11:00:37.788 [INFO] main.go:17: golang program is running~
2022-10-16 11:00:38.790 [INFO] main.go:17: golang program is running~
这样之后,我们就能实现部署新的程序后,自动平滑重启程序了。
注意:在
Web
端,手动stop/start
程序,不会发信号量到程序!
监控文件夹
刚刚展示目标程序变更,自动重启。那么配置文件更新了,自动重启如何配置呢?
注意:如果程序内自动监控了文件变化并更新配置(推荐这样做),则不需要 supervisor 来发信号给程序本身了。
这里新增了两行配置,1.配置监控存放配置文件的文件夹,2. 配置文件夹内文件变化时,发什么信号通知程序。
[program:golang]
command = /Users/paulxu/golang/go-learn/main -conf /Users/paulxu/golang/go-learn/config/config.toml
restart_when_binary_changed=true
restart_signal_when_binary_changed=SIGHUP
restart_directory_monitor=/Users/paulxu/golang/go-learn/config/
restart_signal_when_file_changed=SIGHUP
测试代码
package main
import (
"os"
"os/signal"
"syscall"
"time"
"github.com/gogf/gf/frame/g"
)
func main() {
g.Log().Line().Info("start!!")
go func() {
for {
time.Sleep(time.Second)
g.Log().Line().Info("golang program is running~")
}
}()
g.Log().Line().Info("waiting signal~")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
select {
case s := <-c:
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
g.Log().Line().Infof("golang get signal %+v", s)
return
case syscall.SIGHUP:
g.Log().Line().Infof("golang get signal %+v [sighup]", s)
default:
g.Log().Line().Infof("golang get other signal %+v", s)
return
}
}
}
}
最后
好的,今天给大家介绍了一款 supervior
的golang
轮子,以及基本使用方法。可以看到一些常用的基础和golang
碰撞后,擦出了不一样的火花。由于 Go
语言的编译工具链会全静态链接构建二进制文件,All in One
的设计理念,对运维部署时非常友好的。期待更多这样的轮子。
虽然,在当前容器化时代,它的使用场景被进一步挤压,但是在小型站点,实体机上使用还是很方便的。
关注我,了解更多golang知识~