Post

macOS Ops: launchd Jobs debuggen und Homebrew Services sauber betreiben

macOS Ops: launchd Jobs debuggen und Homebrew Services sauber betreiben

Wer macOS im professionellen Umfeld administriert, kommt an launchd und Homebrew nicht vorbei. Doch wie verhalten sich beide zusammen, wenn es um persistente Services geht? Dieser Beitrag bringt Licht ins Dunkel und zeigt praxistaugliche Konfigurationen.

Zwei Welten: LaunchAgents vs. LaunchDaemons

  • LaunchAgents: laufen im Kontext eines Users (GUI-Session), liegen in ~/Library/LaunchAgents
  • LaunchDaemons: systemweit, laufen als root, liegen in /Library/LaunchDaemons

Das ist nicht Kosmetik: Es entscheidet über Rechte, Environment und Zugriff auf Keychain/GUI.

Der Klassiker: PATH ist nicht dein PATH

launchd startet Jobs mit einem sehr kleinen Environment. Wenn euer Script brew, python, jq usw. braucht, gebt die Pfade explizit an oder setzt PATH.

Besser: ProgramArguments statt Program

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- file: com.example.cleanup.plist -->
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.example.cleanup</string>

    <key>ProgramArguments</key>
    <array>
      <string>/bin/bash</string>
      <string>/usr/local/scripts/cleanup.sh</string>
    </array>

    <key>StartInterval</key>
    <integer>3600</integer>

    <key>StandardOutPath</key>
    <string>/var/log/com.example.cleanup.out</string>
    <key>StandardErrorPath</key>
    <string>/var/log/com.example.cleanup.err</string>
  </dict>
</plist>

Damit seht ihr auch, ob das Script überhaupt startet.

launchd Debug-Workflow

1) Status prüfen

1
2
3
4
5
# Agent (User)
launchctl print gui/$(id -u)/com.example.cleanup

# Daemon (System)
sudo launchctl print system/com.example.cleanup

2) Job (neu) laden

1
2
3
4
5
# Agent
aunchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.example.cleanup.plist 2>/dev/null || true
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.cleanup.plist
launchctl enable gui/$(id -u)/com.example.cleanup
launchctl kickstart -k gui/$(id -u)/com.example.cleanup

Wenn bootstrap meckert: Plist prüfen (plutil -lint …) und Pfade.

3) Logs ansehen

Auf neueren macOS Versionen ist Unified Logging der Standard.

1
log show --style syslog --last 10m --predicate 'process == "launchd"'

Wenn ihr StandardOutPath nutzt, könnt ihr zusätzlich klassisch tailen.

Homebrew Services: Komfort ja, aber bewusst

brew services ist praktisch, weil es Plists generiert und managed. Aber: ihr solltet wissen, ob es als User-Agent oder als System-Daemon läuft.

1
2
brew services list
brew services info <formula>

Empfehlung: Services dokumentieren

Für produktionsnahe Macs (Build-Agents, Jump-Hosts, Lab-Rechner):

  • welche Services laufen?
  • warum?
  • unter welchem User?
  • wo landen Logs?

Takeaways

  • launchd hat ein minimales Environment: Pfade explizit setzen.
  • ProgramArguments ist robuster als Program.
  • Debugging beginnt mit launchctl print und endet mit brauchbaren Logs.
  • brew services ist bequem, aber ihr müsst User vs. System unterscheiden.
  • Dokumentiert laufende Services (Owner/Zweck/Logs), sonst wird’s Wildwuchs.
This post is licensed under CC BY 4.0 by the author.