在 Linux 上有一个大家用惯的 systemd,在 MacOS 上有一个与之相对应的工具,launchd。

Linux 下,systemd 的 pid 是 1,系统启动后,它是第一个被拉起来的,其它进程都是它的子进程。所以在 Linux 下,用 systemd 来做 supervisor 是最稳妥的办法。因为如果 systemd 挂掉了,整个系统都 crash 了。

MacOS 下面也有一个这样的超级进程,所有的其它进程都是它产生的,挂为它的子进程、孙子进程…… 它就是 launchd。launchd 对应的管理工具就是 launchctl。

1. 原理

通过后缀名为 .plist 的配置文件追加 launchd 的管理项。添加和删除,都是用 .plist 文件来完成的。

.plist 文件存在于下面的文件夹中,分别是。

类型 路径 说明
User Agents ~/Library/LaunchAgents 为当前登录用户启动
Global Agents /Library/LaunchAgents 为当前登录用户启动
Global Daemons /Library/LaunchDaemons root 或者通过 UserName 配置指定的用户
System Agents /System/Library/LaunchAgents 当前登录用户
System Daemons /System/Library/LaunchDaemons root 或者通过 UserName 配置指定的用户

按照需要将你要监控的程序放到不同等级的目录中。

2. 配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.simonkuang.macos.coredns</string>
    <key>Disabled</key>
    <false/>
    <key>KeepAlive</key>
    <true/>
    <key>ProcessType</key>
    <string>Background</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/coredns</string>
      <string>-conf</string>
      <string>/usr/local/etc/Corefile</string>
    </array>
    <key>UserName</key>
    <string>root</string>
    <key>GroupName</key>
    <string>wheel</string>
  </dict>
</plist>

上面的例子是启动一个 coredns 进程。启动的命令如下。

/usr/local/bin/coredns -conf /usr/local/etc/Corefile

配置中的项目包括。

  • Label: 应该是唯一的 package name。
  • Disabled: 是否不生效(launchd 忽略,不执行)
  • KeepAlive: 意外挂掉的话,是否由 launchd 重新拉起。
  • ProcessType: 进程类型。
  • ProgramArguments: 程序参数。
  • UserName: 启动进程的用户。
  • GroupName: 启动进程的用户组。

因为 coredns 会启动 53/udp 端口的监听,53 < 1024,因此我们需要给它 root 用户的权限。因为 dns 是基础网络服务,因此以系统进程的方式启动。所以该配置文件按下面的路径保存。

/Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

请注意,文件名和 Label 保持一致。

3. 操作

# 加载配置
launchctl load -w /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

# 卸载配置
launchctl unload /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

# 修改配置后重载配置
launchctl unload /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist && \
launchctl load -w /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

-w 参数的意思是,无论配置中 Disabled 项是 true 还是 false,都启动进程。这个参数对调试配置和进程特别有效。

加载成功的服务,系统重启后会按照配置运行,达到 supervisor 的目的。

4. 更多

# 查看所有的 plist 服务
launchctl list

# 禁用服务
launchctl disable /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

# 启用服务
launchctl disable /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

# 杀死进程(不优雅地杀,直接杀进程)并重启服务。对一些停止响应的服务有效。
launchctl kickstart -k /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

# 在不修改 Disabled 配置的前提下启动服务
launchctl start /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist

# 在不修改 Disabled 配置的前提下停止服务
launchctl stop /Library/LaunchDaemons/com.simonkuang.macos.coredns.plist