systemd

systemd是一套软件,是Linux系统下面的第一个进程,用来初始化系统的各种任务,提供计划任务、电源管理、挂载磁盘、DNS解析、系统日志、网络配置等等,甚至使用systemd-boot替代Grub,大概感觉就是systemd能接管的,最后都会用systemd

systemctl是用来管理任务的,最直接的操作包括:启动、停止、重启、查看状态。

# 启动 caddy 服务
systemctl start caddy

这个命令是给维护人员在命令行上面使用的,虽然偶尔会偷懒,使用ifconfig命令获取IP地址之类的不是很骚的操作,但是调用二进制执行某些任务,最多只能知道成功了没有,这期间不包括某个命令找不到,缺乏执行权限,版本差异导致获取不到预期输出等等问题,最合适的做法是使用软件提供的开放接口执行命令。

调用 systemd 接口

Linux系统下面通讯基本靠着d-bus,在简单一点就是信号。要在软件里面实现,我需要找到一个d-bus库,以及systemd的API文档,好在这些都不是很难。直接贴代码:

package main

import (
	"fmt"
	"github.com/godbus/dbus"
	"github.com/urfave/cli"
	"log"
	"os"
)

var conn *dbus.Conn
var busObject dbus.BusObject

func main() {
	c, err := dbus.SystemBus()
	if err != nil {
		log.Fatal(err)
	}
	conn = c
	busObject = c.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
	app := &cli.App{
		Commands: cli.Commands{
			{
				Name:   "start",
				Action: start,
			},
			{
				Name:   "stop",
				Action: stop,
			},
			{
				Name:   "restart",
				Action: restart,
			},
		},
	}
	fmt.Println(app.Run(os.Args))
}

func start(c *cli.Context) error {
	call := busObject.Call("org.freedesktop.systemd1.Manager.StartUnit", 0, c.Args().First(), "replace")
	ret := ""
	err := call.Store(&ret)
	return err
}
func stop(c *cli.Context) error {
	call := busObject.Call("org.freedesktop.systemd1.Manager.StopUnit", 0, c.Args().First(), "replace")
	ret := ""
	err := call.Store(&ret)
	return err
}
func restart(c *cli.Context) error {
	call := busObject.Call("org.freedesktop.systemd1.Manager.RestartUnit", 0, c.Args().First(), "replace")
	ret := ""
	err := call.Store(&ret)
	return err
}

代码不多,关于D-bus的例子大多数是C语言的,如果是最简单的调用一个API,就需要四个参数:目的地、路径、方法、参数,比如重启一个服务:

参数说明
org.freedesktop.systemd1目的地
/org/freedesktop/systemd1路径
org.freedesktop.systemd1.Manager.RestartUnit调用的接口,这里重启一个服务
xxx.service接口的参数

现成封装好的库也是有的,CoreOS项目里面有一个bus库,封装好了systemd的各种接口,调用起来非常的方便,如果开发系统管理之类的工具,调用这个库比起自己编写的功能补全臭虫一堆的代码会节省很多时间,Golang真棒。

也不是所有人都喜欢systemd这个玩意,比如最近就有Debian 就支持非 systemd 初始化系统进行投票,在Debian从14年开始使用systemd到现在19年,已经五年了,稳定并且普及开来,如果有更好的方案私底下是会使用的,相反的的在生产环境里面在未来可以预见的一段时间内,Linux的第一个进程都会是systemd