这些被systemd拉起的服务程序以守护进程(daemon process)的形式运行,那什么又是守护进程呢?《UNIX环境高级编程3rd(Advanced Programming in the UNIX Environment)》[4]一书中是这样定义的:
1 2 3
Daemons are processes that live for a long time. They are often started when the system is bootstrapped and terminate only when the system is shut down. Because they don’t have a controlling terminal, we say that they run in the background. UNIX systems have numerous daemons that perform day-to-day activities.
COMMANDS: install install service uninstall uninstall service start start service stop stop service run run service
OPTIONS: -config string config file of the service (default "/etc/myapp/config.ini") -user string user account to run the service -workingdir string working directory of the service`
fmt.Println(s) }
func init() { installCommand.StringVar(&user, "user", "", "user account to run the service") installCommand.StringVar(&workingdir, "workingdir", "", "working directory of the service") installCommand.StringVar(&config, "config", "/etc/myapp/config.ini", "config file of the service") runCommand.StringVar(&config, "config", defaultConfig, "config file of the service") flag.Usage = usage }
func main() { var err error n := len(os.Args) if n <= 1 { fmt.Printf("invalid args\n") flag.Usage() return }
subCmd := os.Args[1] // the second arg
// get Config c, err := getServiceConfig(subCmd) if err != nil { fmt.Printf("get service config error: %s\n", err) return } ... ... }
func getServiceConfig(subCmd string) (*service.Config, error) { c := service.Config{ Name: "myApp", DisplayName: "Go Daemon Service Demo", Description: "This is a Go daemon service demo", Executable: "/usr/local/bin/myapp", Dependencies: []string{"After=network.target syslog.target"}, WorkingDirectory: "", Option: service.KeyValue{ "Restart": "always", // Restart=always }, }
switch subCmd { case "install": installCommand.Parse(os.Args[2:]) if user == "" { fmt.Printf("error: user should be provided when install service\n") return nil, errors.New("invalid user") } if workingdir == "" { fmt.Printf("error: workingdir should be provided when install service\n") return nil, errors.New("invalid workingdir") } c.UserName = user c.WorkingDirectory = workingdir
这里要注意的是service.Config中的Option和Arguments,前者用于在systemd service unit配置文件中放置任意的键值对(比如这里的Restart=always),而Arguments则会被组成为ExecStart键的值,该值会在start service时传入使用。
$sudo make install cp ./myapp /usr/local/bin $sudo make install-cfg mkdir -p /etc/myapp cp ./config.ini /etc/myapp
接下来,我们就来将myapp安装为systemd的服务:
1 2 3 4 5 6 7
$sudo ./myapp install -user tonybai -workingdir /home/tonybai install operation ok
$sudo systemctl status myApp ● myApp.service - This is a Go daemon service demo Loaded: loaded (/etc/systemd/system/myApp.service; enabled; vendor preset: enabled) Active: inactive (dead)
$sudo systemctl status myApp ● myApp.service - This is a Go daemon service demo Loaded: loaded (/etc/systemd/system/myApp.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-09-09 23:30:01 CST; 5s ago Main PID: 623859 (myapp) Tasks: 6 (limit: 12651) Memory: 1.3M CGroup: /system.slice/myApp.service └─623859 /usr/local/bin/myapp run -config /etc/myapp/config.ini
Sep 09 23:30:01 tonybai systemd[1]: Started This is a Go daemon service demo. Sep 09 23:30:01 tonybai myapp[623859]: listen on :65432
我们看到myApp服务成功启动,并在65432这个端口上监听!
我们利用curl向这个端口发送一个请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$curl localhost:65432 Welcome
$sudo systemctl status myApp ● myApp.service - This is a Go daemon service demo Loaded: loaded (/etc/systemd/system/myApp.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-09-09 23:30:01 CST; 1min 27s ago Main PID: 623859 (myapp) Tasks: 6 (limit: 12651) Memory: 1.4M CGroup: /system.slice/myApp.service └─623859 /usr/local/bin/myapp run -config /etc/myapp/config.ini
Sep 09 23:30:01 tonybai systemd[1]: Started This is a Go daemon service demo. Sep 09 23:30:01 tonybai myapp[623859]: listen on :65432 Sep 09 23:31:24 tonybai myapp[623859]: [:65432]: receive a request from: 127.0.0.1:10348
我们看到myApp服务运行正常并返回预期应答结果。
现在我们利用stop subcommand停掉该服务:
1 2 3 4 5 6 7 8 9 10 11 12 13
$sudo systemctl status myApp ● myApp.service - This is a Go daemon service demo Loaded: loaded (/etc/systemd/system/myApp.service; enabled; vendor preset: enabled) Active: inactive (dead) since Fri 2022-09-09 23:33:03 CST; 3s ago Process: 623859 ExecStart=/usr/local/bin/myapp run -config /etc/myapp/config.ini (code=killed, signal=TERM) Main PID: 623859 (code=killed, signal=TERM)
Sep 09 23:30:01 tonybai systemd[1]: Started This is a Go daemon service demo. Sep 09 23:30:01 tonybai myapp[623859]: listen on :65432 Sep 09 23:31:24 tonybai myapp[623859]: [:65432]: receive a request from: 127.0.0.1:10348 Sep 09 23:33:03 tonybai systemd[1]: Stopping This is a Go daemon service demo... Sep 09 23:33:03 tonybai systemd[1]: myApp.service: Succeeded. Sep 09 23:33:03 tonybai systemd[1]: Stopped This is a Go daemon service demo.
$sudo systemctl status myApp ● myApp.service - This is a Go daemon service demo Loaded: loaded (/etc/systemd/system/myApp.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-09-09 23:34:38 CST; 3s ago Main PID: 624046 (myapp) Tasks: 6 (limit: 12651) Memory: 1.4M CGroup: /system.slice/myApp.service └─624046 /usr/local/bin/myapp run -config /etc/myapp/config.ini
Sep 09 23:34:38 tonybai systemd[1]: Started This is a Go daemon service demo. Sep 09 23:34:38 tonybai myapp[624046]: listen on :65431