在 MacOS 中用 launchd 管理进程

在 MacOS 中用 launchd 管理进程

2020-02-09
技术
MacOS, launchd

在 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/LaunchDaemonsroot 或者通过 UserName 配置指定的用户
System Agents/System/Library/LaunchAgents当前登录用户
System Daemons/System/Library/LaunchDaemonsroot 或者通过 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