Engineering-Notiz

Build- und Signaturfehler auf einem Cloud-Mac mit Unified Log untersuchen

DevOps & CI/CD ·ca. 5 Min. Lesezeit

Build- und Signaturfehler auf einem Cloud-Mac mit Unified Log untersuchen

Ein nächtlicher automatisierter Build schlägt plötzlich fehl, im Terminal bleibt lediglich Command PhaseScriptExecution failed zurück – beim nächsten Versuch läuft alles wieder problemlos. In diesem Fall hilft es nicht, nur die letzte Ausgabezeile zu betrachten. Buildwerkzeuge, Signaturdienste, Netzwerkprozesse und Systemberechtigungen schreiben auf einem Cloud-Mac jeweils eigene Ereignisse in das Unified Log von macOS. Werden diese Ereignisse auf einer gemeinsamen Zeitachse zusammengeführt, lässt sich meist erkennen, ob die Ursache im Projektskript, bei einem Systemdienst oder in einer unterbrochenen Remoteverbindung liegt.

Fehlerzeitpunkt und Reproduktionsrahmen festhalten

Notieren Sie zuerst die Uhrzeit des Knotens, den Startzeitpunkt des Befehls, den Fehlerzeitpunkt und den Exit-Code. Die im Remoteclient angezeigte lokale Zeit kann von der Zeitzone des Knotens abweichen. Verwenden Sie deshalb für die gesamte Untersuchung die Zeit des Knotens.

date -u '+%Y-%m-%dT%H:%M:%SZ'
set -o pipefail
xcodebuild \
  -workspace Demo.xcworkspace \
  -scheme Demo \
  -configuration Release \
  build 2>&1 | tee "$HOME/build-output.log"
printf 'exit=%s
' "${PIPESTATUS[0]}"

Löschen Sie nicht sofort DerivedData, starten Sie keine Prozesse neu und überschreiben Sie keine vorhandenen Protokolle. Sichern Sie zunächst die Buildausgabe und prüfen Sie anschließend, ob sich der Fehler zuverlässig reproduzieren lässt. Bei sporadischen Problemen sollten mindestens zwei Läufe protokolliert werden. Halten Sie außerdem fest, ob Commit, Xcode-Pfad, Shell-Umgebung und Arbeitsverzeichnis in beiden Läufen identisch waren.

Das Unified Log ersetzt nicht die Terminalausgabe. Ersteres zeigt, was im System und in seinen Diensten passiert ist; Letztere zeigt, bis zu welchem Schritt der Buildbefehl ausgeführt wurde. Beide Aufzeichnungen müssen denselben Zeitraum abdecken.

Unified Log mit Prädikaten eingrenzen

Mit log show lassen sich bereits aufgetretene Ereignisse nachträglich untersuchen. Exportieren Sie nicht vorschnell sämtliche Protokolle mehrerer Stunden. Das erzeugt unnötiges Rauschen und erhöht den Aufwand für die Anonymisierung. Begrenzen Sie den Zeitraum zunächst auf zehn Minuten vor und nach dem Fehler und filtern Sie nach Prozessnamen:

log show \
  --last 20m \
  --style compact \
  --info \
  --debug \
  --predicate 'process == "xcodebuild" OR process == "codesign"'

Zeigt das Terminal lediglich einen Signaturfehler, suchen Sie anschließend nach Ablehnungen durch Sicherheitsdienste. Wurde der Build von der Remotesitzung beeinflusst, prüfen Sie sshd sowie den Prozess, der das Skript tatsächlich ausführt. Verwenden Sie in Prädikaten nach Möglichkeit die Felder process, subsystem, category und eventMessage, statt den gesamten Text unspezifisch zu durchsuchen.

log show --last 15m --style compact \
  --predicate '(process == "sshd") OR (eventMessage CONTAINS[c] "denied")'

Häufige Signale lassen sich anhand der folgenden Tabelle einordnen. Die endgültige Bewertung muss jedoch immer den Exit-Code und die Reproduktionsschritte einbeziehen.

Protokollsignal Zuerst prüfen Nicht vorschnell folgern
permission denied Dateiberechtigungen, Schlüsselbundzugriff, ausführendes Benutzerkonto Hardwarefehler des Knotens
Prozess wurde beendet Speicherdruck, übergeordneter Prozess, Zeitlimits des Skripts Xcode selbst ist beschädigt
SSH-Sitzung wurde getrennt Clientnetzwerk, Keepalive-Einstellungen, Ausführungsart des Jobs Der Build ist zwangsläufig fehlgeschlagen
Signaturdienst findet keinen passenden Eintrag Schlüsselbund, Zertifikatsname, Zuordnung der Profile Die gesamte Toolchain muss neu installiert werden

Relevante Ereignisse während der Reproduktion live beobachten

Lässt sich der Fehler zuverlässig reproduzieren, öffnen Sie eine zweite SSH-Sitzung und führen dort log stream aus. Der Live-Stream dient ausschließlich der Beobachtung. Fassen Sie die Filterbedingungen nicht zu weit, da wichtige Ereignisse sonst in der kontinuierlichen Ausgabe untergehen.

log stream \
  --style compact \
  --level info \
  --predicate 'process == "xcodebuild" OR process == "codesign" OR process == "securityd"'

Starten Sie danach den Build in der ursprünglichen Sitzung und messen Sie den zeitlichen Abstand zwischen dem ersten auffälligen Protokolleintrag und dem Buildfehler. Tritt zuerst ein Signaturfehler auf, den das Buildwerkzeug anschließend nur als allgemeinen Fehler zusammenfasst, sollte die Signaturkette vorrangig untersucht werden. Wird dagegen zuerst die SSH-Verbindung getrennt, während der Buildprozess weiterläuft, ist zu prüfen, ob der Job an ein interaktives Terminal gebunden ist. Dies darf nicht vorschnell als Kompilierungsfehler bewertet werden.

Korrelationsmarken in Skripte einfügen

Eigene Skripte können zu Beginn und am Ende einen Eintrag in das Unified Log schreiben. Verwenden Sie dafür ein festes Subsystem und eine pro Ausführung eindeutige Job-ID. So ist keine unscharfe Suche nach Dateinamen erforderlich.

job_id="$(date -u '+%Y%m%dT%H%M%SZ')"
logger -p user.notice -t minid-build "job=$job_id phase=start"
./scripts/build.sh
status=$?
logger -p user.notice -t minid-build "job=$job_id phase=end status=$status"
exit "$status"

Das von logger gesetzte Tag kann über process oder den Nachrichteninhalt gesucht werden. Die Job-ID dient ausschließlich dazu, Ereignisse eines einzelnen Laufs miteinander zu verknüpfen. Sie darf keine Tokens, Repository-Zugangsdaten oder Kundendaten enthalten.

Nachprüfbare und sicher übertragbare Belege exportieren

Textausgaben auf der Kommandozeile eignen sich für eine schnelle Analyse. Bei komplexeren Problemen sollte zusätzlich ein .logarchive aufbewahrt werden. Prüfen Sie vor dem Archivieren erneut den Zeitraum, damit keine historischen Daten erfasst werden, die mit dem Fehler nichts zu tun haben.

mkdir -p "$HOME/diagnostics"
sudo log collect \
  --last 15m \
  --output "$HOME/diagnostics/build-incident.logarchive"

cp "$HOME/build-output.log" "$HOME/diagnostics/"

Versenden Sie nicht ungeprüft das gesamte Verzeichnis. Kontrollieren Sie die Buildprotokolle zunächst auf expandierte Umgebungsvariablen, absolute Projektpfade, Knotenadressen, Repository-Adressen, Zertifikatsnamen und Skriptparameter. Ersetzen Sie vertrauliche Werte anhand einer konsistenten Zuordnung. Derselbe Benutzername sollte beispielsweise immer durch <USER> ersetzt werden, da sich sonst später nicht mehr feststellen lässt, ob mehrere Ereignisse demselben Konto zuzuordnen sind.

Erstellen Sie zusätzlich eine reine Textdatei mit UTC-Zeit, ausgeführtem Befehl, Exit-Code, erwartetem und tatsächlichem Ergebnis, Reproduzierbarkeit sowie dem Commit des letzten erfolgreichen Laufs vor dem Fehler. Die Protokolle belegen, was geschehen ist; die Begleitdatei definiert den Untersuchungsrahmen.

Nächste Schritte anhand der Belege festlegen

Ordnen Sie das Problem nach Abschluss der Datenerfassung zunächst einer von vier Kategorien zu: Projekt, Umgebung, Verbindung oder Ressourcen. Projektbezogene Fehler lassen sich prüfen, indem derselbe Commit in einem sauberen Arbeitsverzeichnis ausgeführt wird. Bei Umgebungsproblemen sind die Xcode-Auswahl, die Shell-Initialisierung und die Sichtbarkeit des Schlüsselbunds zu kontrollieren. Bei Verbindungsproblemen muss zwischen einer getrennten Sitzung und einem tatsächlich beendeten Job unterschieden werden. Bei Ressourcenproblemen sollten freier Speicherplatz, Speicherdruck und parallel laufende Prozesse untersucht werden.

Führen Sie vor Abschluss der Untersuchung eine minimale Abnahme durch: Bauen Sie denselben Commit zweimal hintereinander und stellen Sie sicher, dass beide Läufe den Exit-Code null liefern. Signierte Artefakte müssen sich mit codesign --verify --deep --strict validieren lassen. Hintergrundjobs müssen nach dem Trennen der SSH-Verbindung wie vorgesehen abgeschlossen werden, und das Diagnoseverzeichnis darf keine Tokens im Klartext enthalten. Erst wenn alle diese Bedingungen erfüllt sind, gilt der Vorfall als vollständig behoben.

Häufig gestellte Fragen

Warum reicht die Ausgabe von xcodebuild nicht immer aus?

Sie zeigt vor allem Buildschritte. Zugriffsverweigerungen, Signaturdienste, Netzwerkabbrüche und Fehler von Systemprozessen können ausschließlich im Unified Log erscheinen.

Welche Angaben müssen vor dem Teilen entfernt werden?

Benutzernamen, absolute Projektpfade, Knotenadressen, Repository-Adressen, Token, Zertifikatsnamen und erkennbare Projektdaten müssen maskiert werden.

MiniD Cloud Mac

Dedizierten physischen Mac mini tage-, wochen- oder monatsweise mieten

Jeder Plan läuft auf einem dedizierten physischen Mac mini mit Remote-Desktop- und SSH-Zugang; aktuelle Modelle, Regionen und Laufzeiten stehen auf der Bestellseite.

Bestelloptionen ansehen