Härten Sie Ihre Bereitstellung
Ein selbstgehosteter Runner führt beliebigen, modellgesteuerten Code auf Ihrer Infrastruktur im Namen aller aus, die eine Sitzung in seiner Umgebung starten können. Das ist jedes Mitglied Ihrer Anthropic-Organisation und jeder, der eine Claude Tag-Kanalsitzung in einem Bereich starten kann, den ein Owner zur Umgebung weitergeleitet hat. Arbeiten Sie jedes Element durch, bevor Sie eine Umgebung mit Produktionssystemen verbinden:-
Ephemere, sitzungsspezifische Container: Führen Sie jeden Runner-Prozess in einem frischen Container oder einer VM aus, die zerstört wird, wenn der Prozess beendet wird, mit
--capacity 1und dem Standard--drain-grace-sec 0, sodass jeder Container genau eine Sitzung bedient. Bei einer höheren Kapazität oder mit einer positiven Drain-Grace bedient ein Container mehrere Sitzungen vom selben gesperrten Owner; siehe Runner-Lebenszyklus. Verwenden Sie kein Dateisystem zwischen Runner-Neustarts wieder, außer in der absichtlichen vorgewärmten Checkout-Einrichtung, und niemals über Owners hinweg.- Wenn der Runner eine Sitzung beendet, sendet er kein Signal an einen Prozess, der nach dem Beenden seines Shell-Befehls noch läuft, etwa einen Dienst, der sich als Daemon abgelöst hat. Das Zerstören des Containers oder der VM beendet diesen Prozess.
-
Keine breiten Anmeldedaten im Image: Fügen Sie keine langlebigen SSH-Schlüssel, Cloud-Provider-Anmeldedaten oder persönliche Zugriffstokens ein, die mehr gewähren als eine Sitzung benötigt. Erstellen Sie Anmeldedaten, die während einer Sitzung verwendet werden, wie Push- oder API-Tokens, pro Sitzung aus Ihrem Wrapper-Skript. Der anfängliche Clone findet statt, bevor der Wrapper ausgeführt wird. Verwenden Sie dafür daher einen
checkout-Lebenszyklus-Hook oder--use-anthropic-git-proxy, wenn alle Repositorys einer Sitzung auf github.com liegen. Zu beiden siehe Git konfigurieren. -
Halten Sie die GitHub-Anmeldedaten des Hosts von Sitzungen fern: Claude kann alle GitHub-Anmeldedaten verwenden, die eine Sitzung lesen kann, mit dem Zugriff, den diese Anmeldedaten gewähren. Halten Sie die eigenen, weit gefassten GitHub-Anmeldedaten des Runner-Hosts aus allem heraus, was eine Sitzung lesen kann. Solche Anmeldedaten können ein persönliches Zugriffstoken sein, das Token, das
gh auth loginfür Ihr Konto speichert, oder einGH_TOKENin der Umgebung des Runners.- Mit Anthropic-verwaltetem Git: Mit solchen Anmeldedaten erreicht Claude GitHub direkt statt über Anthropic-verwaltetes Git.
- Ohne Anthropic-verwaltetes Git: Clone-Anmeldedaten können im Image bleiben, wenn Sie sie so eng beschränken, wie in Git-Konfiguration in Ihrem Image ausliefern beschrieben.
- Halten Sie das Umgebungsgeheimnis von sitzungsausführenden Hosts fern: Das Umgebungsgeheimnis kann Runner registrieren und jede Sitzung abholen, die in der Umgebung in die Warteschlange eingereiht ist. In einer festen Flotte lebt es auf jedem Runner-Host, wo jeder Sitzungscode das Geheimnisdatei lesen kann. Bevorzugen Sie On-Demand-Runner, bei denen das Geheimnis auf dem Orchestrator-Host bleibt, der niemals Benutzercode ausführt, und jeder Runner einen einmaligen Arbeitsauftrag erhält, der genau einen Runner registriert. Behandeln Sie in einer festen Flotte die Umgebungsgeheimnisdatei als von jeder Sitzung lesbar und rotieren Sie das Geheimnis nach jedem vermuteten Sitzungskompromiss.
- Standard-Deny-Netzwerk-Egress: Beschränken Sie den ausgehenden Datenverkehr von Runner- und Sitzungs-Containern an Ihrer eigenen Netzwerkgrenze in jeder Umgebung; Standard-Deny-Egress behandelt, was erlaubt ist und warum.
- Least-Privilege-Host-IAM: Die Compute-Identität, die an den Runner-Host angehängt ist, wie ein Instance-Profil oder ein Node-Service-Konto, sollte nur das gewähren, was der Runner selbst benötigt. Sitzungen sollten ihre eigenen Anmeldedaten über Ihr Wrapper-Skript erhalten, anstatt die des Hosts zu erben.
-
Blockieren Sie den Cloud-Metadaten-Endpunkt von Sitzungen: Um Sitzungen von der Host-Identität fernzuhalten, müssen Sie ihren Zugriff auf den Cloud-Metadaten-Endpunkt blockieren, und Subnetz-Level-Egress-Richtlinien unterbrechen keinen Link-Local-Metadaten-Datenverkehr, daher blockieren Sie ihn im Container selbst:
- IMDSv2 mit einem Hop-Limit von eins
- GKE Workload Identity mit Metadaten-Verbergung
- Ein explizites Deny für
169.254.169.254im Netzwerk-Namespace des Sitzungs-Containers
-
Pro-Runner-Dateisystem-Isolation: Jeder Runner-Prozess erhält sein eigenes Arbeitsverzeichnis, das kein anderer Prozess auf dem Host lesen oder schreiben kann. Machen Sie
--hooks-dir, das Wrapper-Skript und das~/.claude/-Verzeichnis des Hosts für die Sitzung schreibgeschützt, entweder in das Image eingebaut oder schreibgeschützt eingebunden. -
Dispatch hat keine Pro-Umgebungs-Zugriffskontrolle: Jedes Mitglied Ihrer Anthropic-Organisation kann eine Sitzung in jede ihrer Umgebungen starten. Wenn ein Owner Claude Tag-Kanäle zur Umgebung leitet, kann jeder, den die Claude Tag-Zugriffssetting zulässt, Kanalsitzungen starten, die dort ausgeführt werden. Standardmäßig ist das jeder im verbundenen Slack-Workspace, mit oder ohne Claude-Konto. Behandeln Sie jeden Runner-Host als erreichbar für die Codeausführung durch jeden, der ihn starten kann, und platzieren Sie auf einem Runner-Host nur Daten und Anmeldedaten, die alle diese Personen lesen dürfen.
--lock-to-accountbegrenzt, welche Konten-Sitzungen ein bestimmter Host ausführt, aber es verengt nicht, wer in die Umgebung starten kann. Um selbstgehostete Umgebungen zur einzigen Picker-Option zu machen, kann ein Owner Anthropic-gehostete Umgebungen für die ganze Organisation auf der Cloud-Umgebungen-Seite ausblenden. -
Erzwingen Sie die Repo-Settings-Guard: Wählen Sie den Guard-Modus mit
--confine-repo-settings. Der Standardwarnprotokolliert eine Verletzung und startet die Sitzung trotzdem,enforcelehnt die Sitzung ab, undoffdeaktiviert den Scan. Der Runner scannt die festgeschriebenen Einstellungen jedes Repositorys auf:- Eine Berechtigung, die außerhalb des eigenen Workspace dieser Sitzung aufgelöst wird: ein
additionalDirectories-Eintrag, eineEdit-,Write- oderNotebookEdit-Regel inpermissions.allow, oder einsandbox.filesystem.allowWrite- oderallowRead-Eintrag - Ein nicht leerer
env-Block - Eine Operator-Haltungs-Überschreibung wie
sandbox.enabled: false
--trust-workspaceund deckt keine Repository-Hooks,.mcp.jsonoder Bash-Regeln ab; siehe Berechtigungen und Tool-Genehmigung für den Ort dieser Berechtigungen. - Eine Berechtigung, die außerhalb des eigenen Workspace dieser Sitzung aufgelöst wird: ein
Netzwerkanforderungen
Der Runner und die Sitzungs-Kinder, die er spawnt, stellen ausgehende Verbindungen zu den folgenden Hosts her. Beschränken Sie den Sitzungs-Container-Egress auf diese Hosts und die spezifischen internen Services, die Sitzungen erreichen müssen; Standard-Deny-Egress behandelt wie und warum. Diese Hosts sind immer erforderlich:--use-anthropic-git-proxy verwendet, leitet seinen Git-Datenverkehr für github.com über api.anthropic.com und benötigt daher den Git-Host-Pfad für github.com nicht. Er benötigt diesen Pfad weiterhin, wenn Sie --push-outcome-on-release setzen oder aus einem post-session-Hook pushen.
Ob diese Hosts erforderlich sind, hängt von Ihrer Konfiguration ab:
statsig.anthropic.com,*.sentry.io,claude.aiundplatform.claude.com: Diese Hosts erscheinen in einigen älteren Enterprise-Netzwerk-Checklisten, aber der Runner erreicht sie nicht. Feature-Flag-Abrufe gehen zuapi.anthropic.com, und der Runner authentifiziert sich mit dem Umgebungsgeheimnis anstelle von interaktivem OAuth.mcp-proxy.anthropic.com: Selbstgehostete Sitzungen verwenden es nicht. Wenn die Bereitstellung von Konnektoren für Ihre Organisation aktiviert ist, erreichen die claude.ai-Konnektoren Ihrer Organisation die Sitzungen überapi.anthropic.com. Siehe MCP-Server.
claude.ai, führen Sie sie daher von einem Host aus, dessen Egress dies erlaubt, anstatt den Sitzungs-Container-Egress zu erweitern:
- Der Einzeilen-Installer: Ruft
install.shzur Installationszeit vonclaude.aiab. - Interaktives
claude auth login: Meldet sich überclaude.ai,claude.comundplatform.claude.coman. Das geführte Setup, der angemeldete Modus vondoctorund CI-Dispatch verwenden es. Der Browser, mit dem Sie sich anmelden, lädt außerdem die Browser-Prüfungen der claude.ai-Anmeldeseite vonhcaptcha.com,*.hcaptcha.comundchallenges.cloudflare.com. Wenn Ihre Organisation Single Sign-On verwendet, kann dieser Browser außerdem übersso.claude.comumgeleitet werden.
Standard-Deny-Egress
Stellen Sie Runner- und Sitzungs-Container in einem Netzwerk-Segment oder Namespace bereit, dessen ausgehender Datenverkehr auf die Hosts in der Netzwerkanforderungs-Tabelle, Ihren Git-Host und die spezifischen internen Services begrenzt ist, die Sitzungen erreichen müssen. Das Produkt kann dies nicht überprüfen oder erzwingen, daher wenden Sie es an Ihrer eigenen Netzwerkgrenze in jeder Umgebung an. Sitzungscode ist modellgesteuert und kann Verbindungen zu beliebigen Hosts versuchen; Standard-Deny-Egress auf der Netzwerkebene begrenzt, wo diese Versuche landen können. Dies gilt unabhängig vom Berechtigungsmodus: Der Standard-Vorab-Genehmigungstool-Satz enthält bereitsBash, daher läuft Shell-Egress ohne Eingabeaufforderung auch ohne Auto-Modus.
Für Details darüber, welche Telemetrie jede Sitzung aussendet und wie man sie ausschaltet, siehe Telemetrie.
Authentifizieren Sie sich bei einem Egress-Proxy
Einige Corporate-Egress-Proxys erfordern einenProxy-Authorization-Header bei jeder Verbindung. Das Token in diesem Header rotiert oft zu schnell, um es in die Proxy-URL zu schreiben, die Sie in HTTPS_PROXY setzen. Setzen Sie HTTPS_PROXY oder HTTP_PROXY wie gewohnt auf die URL Ihres Proxys, dann setzen Sie --proxy-authorization-command oder --proxy-authorization-file, um dem Runner zu sagen, wo er den Header-Wert lesen soll. Beide Flags erfordern Claude Code v2.1.238 oder später.
Wählen Sie, woher der Proxy-Authorization-Wert kommt
Wählen Sie das Flag, das der Art entspricht, wie Sie das Proxy-Authorization-Token erzeugen:
--proxy-authorization-command <command>: Wählen Sie dies für ein Token, das Sie bei Bedarf generieren. Der Runner führt das Shell-Kommando aus und verwendet seine getrimmte Standardausgabe als Header-Wert, zum BeispielBearer <token>.--proxy-authorization-file <path>: Wählen Sie dies für ein Token, das ein anderer Prozess an Ort und Stelle rotiert. Der Runner liest die Datei und verwendet ihren getrimmten Inhalt als Header-Wert.
Konfigurationen, die der Runner ablehnt zu starten
Jedes Flag hat auch eine Umgebungsvariablen-Form, die neben ihm in der Runner-CLI-Flags-Referenz aufgelistet ist. Bevor der Runner Ihren Proxy oder die Kontrollebene kontaktiert, überprüft er die Flags und ihre Variablen und lehnt in drei Fällen ab zu starten:- Beide Flags gesetzt: Ein Flag plus die Umgebungsvariable des anderen Flags zählt als Setzen beider.
- Keine Proxy-URL: Weder
HTTPS_PROXYnochHTTP_PROXYenthält einehttp://- oderhttps://-URL. Der Runner liest beide Variablen in Groß- oder Kleinbuchstaben und konsultiert nichtALL_PROXY. - Eines der Flags an den Orchestrator-Subcommand übergeben:
self-hosted-runner orchestratorakzeptiert die Flags oder ihre Umgebungsvariablen nicht. Übergeben Sie das Flag stattdessen an jeden Runner, den der Orchestrator startet.
Was der Runner ändert, während ein Proxy-Autorisierungs-Flag gesetzt ist
Mit einem der Flags gesetzt, startet der Runner seinen eigenen Listener und sendet Proxy-Datenverkehr von sich selbst, seinen Lebenszyklus-Hooks und seinen Sitzungen durch diesen Listener. Der Listener fügt denProxy-Authorization-Header auf dem Weg zu Ihrem Proxy hinzu.
- Listener: Der Listener ist ein Forward-Proxy auf
127.0.0.1. Der Runner startet den Listener vor der Registrierung bei der Kontrollebene und beendet sich beim Start, wenn der Listener nicht starten kann. - Proxy-Variablen: Der Runner schreibt whichever von
HTTPS_PROXYundHTTP_PROXYum, die Sie setzen, damit es auf den Listener zeigt. Dieser umgeschriebene Wert erreicht den Runner selbst, seine Lebenszyklus-Hooks und jede Sitzung, die er ausführt. - Token-Rotation: Ein rotiertes Token wird ohne Neustart wirksam. Für jede Verbindung, die der Listener zu Ihrem Proxy öffnet, führt der Runner Ihren Befehl aus oder liest Ihre Datei erneut und fügt das Ergebnis als Header hinzu.
- Sitzungs-Umgebung: Eine Sitzung erreicht Ihren Proxy nur durch den Listener. In der Umgebung jeder Sitzung entfernt der Runner
ALL_PROXY, entfernt jede Schreibweise vonHTTPS_PROXYoderHTTP_PROXY, die Sie nicht gesetzt haben, und pinntNO_PROXYauf den Wert des Runners. - Logs: Der Runner protokolliert niemals den Header-Wert.
Git konfigurieren
Der Runner verwaltet Repository-Checkouts, konfiguriert aber standardmäßig nicht die Git-Identität oder Anmeldedaten. Sie kontrollieren das Runner-Image und die Prozessumgebung, daher kontrollieren Sie die Git-Konfiguration. Wählen Sie einen von zwei Ansätzen:- Lassen Sie den Runner Git konfigurieren: Starten Sie den Runner mit
--configure-git, um die gleiche Identität und Commit-Signierungskonfiguration zu schreiben, die Anthropic-gehostete Sitzungen verwenden - Versenden Sie Git-Konfiguration in Ihrem Image: Setzen Sie Identität und Push-Anmeldedaten selbst, zum Beispiel um unter Ihrer eigenen Bot-Identität zu committen
--use-anthropic-git-proxy starten oder CLAUDE_RUNNER_USE_GIT_PROXY=1 setzen, um Anthropic zu bitten, Git für die Sitzungen des Runners bereitzustellen.
Git-Versionsuntergrenzen auf dem Runner-Host: --configure-git SSH-Commit-Signierung erfordert Git 2.34 oder neuer, --use-anthropic-git-proxy erfordert 2.32 oder neuer, und das Fortsetzen von Sitzungen von Branches, die von --push-outcome-on-release gepusht werden, erfordert 2.29 oder neuer. Git 2.24 ist ausreichend, wenn Sie alle drei weglassen und die Git-Identität selbst verwalten.
Lassen Sie den Runner Git konfigurieren
Starten Sie den Runner mit--configure-git, oder setzen Sie SELF_HOSTED_RUNNER_CONFIGURE_GIT=1, um die globale Git-Konfiguration beim Start zu schreiben:
user.name = Claudeunduser.email = noreply@anthropic.com, passend zu Anthropic-gehosteten Sitzungen- SSH-Format-Commit- und Tag-Signierung, geleitet durch einen Runner-verwalteten Shim, der jeden Commit über Anthropic’s Signierungsservice mit den Anmeldedaten der Sitzung signiert. Signaturen sind auf GitHub gegen Anthropic’s veröffentlichten SSH-Signierungsschlüssel überprüfbar.
push.negotiate = true, damit Git Ihren Git-Host fragt, welche Commits er bereits hat, bevor er einen Push packt. Erfordert Claude Code v2.1.257 oder später.core.hooksPath, das auf ein Runner-verwaltetes Hooks-Verzeichnis zeigt. Seinecommit-msg- undprepare-commit-msg-Hooks fügen jedem Commit einenCo-authored-by:-Trailer für den Ersteller der Sitzung hinzu. Der Trailer wird aus der E-Mail inCCR_SESSION_ACCOUNT_EMAILerstellt und weggelassen, wenn diese Variable nicht gesetzt ist. Wenn Ihr Image bereitscore.hooksPathsetzt und der Runner kein Anthropic-verwaltetes Git verwendet, behält der Runner Ihre Einstellung bei, überspringt die Installation dieser Hooks und gibt eine[runner:git]-Warnung aus.
checkout- oder post-session-Lebenszyklus-Hook erstellen, ebenfalls als die Sitzung signiert, ohne den Co-authored-by:-Trailer. Git-Konfiguration innerhalb von Lebenszyklus-Hooks beschreibt die Git-Einstellungen, die der Runner innerhalb dieser Hooks festlegt.
Mit oder ohne --configure-git weist Claude Code Claude an, seine Commit-Nachrichten mit einem Claude-Session: <url>-Trailer und seine Pull-Request-Beschreibungen mit der URL der Sitzung abzuschließen. Um beides wegzulassen, setzen Sie attribution.sessionUrl in der ~/.claude/settings.json des Runner-Hosts auf false und starten Sie den Runner anschließend neu.
Versenden Sie Git-Konfiguration in Ihrem Image
Git-Identität ist für jeden Commit erforderlich. Setzen Sie sie systemweit in Ihrem Dockerfile, damit die Konfiguration unabhängig davon gilt, welcher Benutzer den Runner-Prozess ausführt:git commit mit Please tell me who you are fehl und Sitzungen können nicht voranschreiten. Sie können stattdessen Ihre eigene Bot-Identität verwenden; der Runner überschreibt diese Werte nicht.
Backen Sie keine langlebigen oder breit gefassten Push-Anmeldedaten in ein gemeinsames Runner-Image: Anmeldedaten im Image sind für jede Sitzung verfügbar, die das Image ausführt, wer auch immer sie gestartet hat. Erstellen Sie stattdessen ein kurzlebiges, minimal gefasstes Token pro Sitzung aus Ihrem Wrapper-Skript, unter Verwendung der Identität des Sitzungs-Erstellers, die aus dem Sitzungs-JWT dekodiert ist. Paaren Sie es mit einem ephemeren Pro-Sitzungs-Container, der --capacity 1 erfordert, damit keine Anmeldedaten die Sitzung überleben, die sie erstellt hat; siehe den Härtungsabschnitt.
Wenn Sie Push-Anmeldedaten auf Image-Ebene konfigurieren müssen, zum Beispiel für einen schreibgeschützten Deploy-Schlüssel, begrenzen Sie sie so eng wie Ihr Git-Host erlaubt:
- Ein SSH-Deploy-Schlüssel, der auf ein Repository mit einer
url.<base>.insteadOf-Umschreibung begrenzt ist - Ein
credential.helper, der ein minimal gefasstes Token zurückgibt GIT_SSH_COMMAND, das auf einen eng gefassten Schlüssel zeigt
- Der Runner setzt
GIT_TERMINAL_PROMPT=0, daher fragt Git nicht nach Benutzername oder Passwort. - Der Runner führt SSH mit
BatchMode=yesaus, angehängt an IhrenGIT_SSH_COMMAND, wenn Sie einen setzen, daher fragt SSH nicht nach einer Passphrase oder Host-Bestätigung. - Der Runner setzt
GCM_INTERACTIVE=never, daher öffnet Git Credential Manager keinen Anmeldedialog. - Der Runner löscht
core.askPass, daher setzen Sie es, wenn Sie einen Askpass-Helper verwenden, stattdessen durch dieGIT_ASKPASS-Umgebungsvariable.
GIT_SSH_COMMAND oder GIT_ASKPASS benennen, dort, wo Sitzungen nicht darauf schreiben können, wie die Härtungs-Checkliste für das Hooks-Verzeichnis und das Wrapper-Skript verlangt. Das Gleiche gilt für jeden Schlüssel oder jede Datei in der Befehlszeile dieses Programms. Der Runner’s eigenes Git führt dieses Programm aus, wenn es klont oder abruft.
Wenn Checkout-Verzeichnisse einem anderen uid als dem Runner-Prozess gehören, weigert sich Git, auf ihnen zu arbeiten; fügen Sie safe.directory hinzu:
Verwenden Sie den Anthropic-Git-Proxy
Mit dem Anthropic-Git-Proxy, auch Anthropic-verwaltetes Git genannt, benötigt das Runner-Image für die Sitzung selbst keine SSH-Schlüssel, keinen Credential-Helper, keine.netrc und keine anderen Git-Anmeldedaten. Stattdessen bittet der Runner Anthropic, Git für seine Sitzungen bereitzustellen. Bei einer Benutzersitzung, für die Anthropic Git bereitstellt, laufen der Clone des Runners sowie die eigenen Fetches und Pushes der Sitzung über Anthropic, das das für den Ersteller der Sitzung gespeicherte GitHub-OAuth-Token verwendet. Wie Anthropic Git für eine Sitzung bereitstellt behandelt Bot- und Agentensitzungen.
Der Git-Proxy ist ausgeschaltet, sofern Sie ihn nicht einschalten. Ein Runner, der Ihren Git-Host mit eigenen Anmeldedaten erreicht, benötigt ihn nicht, und sein Git funktioniert mit jedem Git-Host.
Im Gegenzug schränkt der Git-Proxy ein, was der Runner unterstützt, und ändert, was er benötigt:
- Nur github.com: Anthropic stellt Git für eine Sitzung nur bereit, wenn sich alle ihre Repositorys auf github.com befinden, und der Git-Proxy unterstützt GitHub Enterprise Server noch nicht. Auf einem Runner mit dem Git-Proxy startet eine Sitzung nicht, wenn sie ein Repository auf einem anderen Git-Host hat.
- Anmeldedaten nur für die Repositorys der Sitzung: Anthropic stellt Git-Anmeldedaten für die Repositorys bereit, die Teil der Sitzung sind, nicht für andere Repositorys auf demselben Git-Host. Ein privates Submodul, eine Abhängigkeit, die Ihr Paketmanager mit Git abruft, oder ein Plugin-Marketplace in einem anderen Repository erhält keine Anmeldedaten von Anthropic. Bitten Sie die Personen, die Sitzungen erstellen, beim Erstellen jedes Repository hinzuzufügen, das eine Sitzung benötigt. Jeder Lauf einer geplanten Cloud-Aufgabe ist eine Sitzung mit den Repositorys der Aufgabe. Bitten Sie daher den Eigentümer jeder Aufgabe, jedes Repository hinzuzufügen, das ihre Läufe benötigen.
- Nur Branch-Pushes: Ein Push, der einen Branch löscht, schlägt fehl, ebenso ein Push auf jede andere Art von Ref, etwa ein Tag. Welche Branches ein Push aktualisieren kann, erfahren Sie unter GitHub-Proxy.
- Verbundene GitHub-Konten: Bitten Sie jede Person, die Benutzersitzungen mit einem Repository erstellt, GitHub zu verbinden. Ohne ihre eigene Verbindung starten diese Sitzungen nicht.
-
--capacity 1: Der Git-Proxy erfordert eine Sitzung pro Runner-Prozess, führen Sie daher mehr Replicas für Parallelität aus. Den Anthropic-Git-Proxy einschalten listet die Anforderungen auf. - Ersetzte globale Git-Konfiguration: Der Runner löscht und ersetzt die globale Git-Konfiguration des Benutzers, unter dem er läuft. Führen Sie ihn als dedizierten Benutzer oder in einem Container aus.
-
Host-Anmeldedaten für Host-Pushes: Der Push des Runners über
--push-outcome-on-releaseund jeder Push, den Ihrpost-session-Hook ausführt, verwenden weiterhin die eigenen Git-Anmeldedaten des Runner-Hosts und dessen Netzwerkpfad zugithub.com. Halten Sie diese Anmeldedaten aus der globalen Git-Konfiguration heraus; Möglichkeiten, sie bereitzustellen, finden Sie unter Versenden Sie Git-Konfiguration in Ihrem Image. - Entscheidung pro Sitzung: Anthropic entscheidet für jede Sitzung auf dem Runner, ob es deren Git bereitstellt, und eine Sitzung, für die es das nicht tut, startet nicht. Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten behandelt die Ursachen.
safe.directory, in der System-Git-Konfiguration auf.
Den Anthropic-Git-Proxy einschalten
Bevor Sie den Runner mit--use-anthropic-git-proxy starten, vergewissern Sie sich, dass der Runner-Host jede dieser Anforderungen erfüllt. Der Runner verweigert den Start, wenn die Kapazitäts- oder Git-Anforderung nicht erfüllt ist:
- Claude Code v2.1.267 oder später: Frühere Versionen akzeptieren das Flag, melden Anthropic aber nicht die Anfrage, Git bereitzustellen, und geben die Zeile
Registering as opted innicht aus, daher stellt Anthropic für ihre Sitzungen kein Git bereit. --capacity 1, der Standardwert: Jeder Runner-Prozess verarbeitet jeweils eine Sitzung, daher führen Sie mehr Replicas für Parallelität aus.- Git 2.32 oder neuer: Älteres Git ignoriert die Git-Konfiguration pro Sitzung, die der Runner für den Git-Proxy einrichtet.
--use-anthropic-git-proxy hinzu oder setzen Sie CLAUDE_RUNNER_USE_GIT_PROXY=1 in der Umgebung des Runners. Dieser Befehl, in einer Shell auf dem Runner-Host ausgeführt, startet den Runner aus dem Schnellstart mit eingeschaltetem Git-Proxy:
Registering as opted in to Anthropic-managed git (--use-anthropic-git-proxy) aus. Anthropic entscheidet dann für jede Sitzung auf diesem Runner, ob es deren Git bereitstellt. Für jede Sitzung, für die es Git bereitstellt, protokolliert der Runner eine [runner:session]-Zeile, die governed git ACTIVE enthält. Wenn eine Sitzung stattdessen nicht startet, siehe Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten.
Wie Anthropic Git für eine Sitzung bereitstellt
Bei einer Sitzung, für die Anthropic Git bereitstellt, laufen der Clone des Runners sowie die eigenen Fetches und Pushes der Sitzung über Anthropic, authentifiziert mit dem eigenen kurzlebigen Token der Sitzung:- Benutzersitzungen: Anthropic verwendet das für den Ersteller der Sitzung gespeicherte GitHub-OAuth-Token.
- Bot- und Agentensitzungen: Anthropic verwendet das GitHub-App-Installations-Token Ihrer Organisation.
- URL-Umschreibungen:
--git-host-rewriteund--git-ssh-rewritehaben keine Auswirkung auf ein Repository, das der Git-Proxy bereitstellt.
Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten
Auf einem Runner, der mit--use-anthropic-git-proxy gestartet wurde, startet eine Sitzung nicht, wenn Anthropic kein Git für sie bereitstellt. Suchen Sie im Log des Runners nach einem Git-Fehler, der eine api.anthropic.com-Adresse mit /git_proxy/ nennt.
Für jede Sitzung protokolliert ein Runner mit Claude Code v2.1.267 oder später außerdem entweder eine [runner:session]-Zeile mit governed git ACTIVE, wenn Anthropic Git für die Sitzung bereitstellt, oder eine [runner:warn]-Zeile mit the server withheld Anthropic-managed git for this session, wenn nicht. Suchen Sie die Zeile, die Sie sehen, unter diesen Fällen:
- Weder
governed git ACTIVEnoch diewithheld-Zeile: Ein Runner, der älter als Claude Code v2.1.267 ist, protokolliert keine der beiden Zeilen, und Anthropic stellt für seine Sitzungen kein Git bereit. Aktualisieren Sie den Runner auf v2.1.267 oder später, indem Sie Die Version festlegen folgen. - Die
withheld-Zeile: Anthropic hat kein Git für die Sitzung bereitgestellt. Ein Runner, der zuvor mit dem Git-Proxy funktioniert hat, kann auf diese Weise fehlschlagen, ohne dass Sie etwas geändert haben.- Ein Repository liegt nicht auf github.com: Für eine Sitzung mit auch nur einem Repository auf einem anderen Git-Host, etwa GitHub Enterprise Server, wird kein Git bereitgestellt, auch nicht für ihre github.com-Repositorys. Schalten Sie den Anthropic-Git-Proxy aus für die Runner dieser Umgebung.
- Jedes Repository liegt auf github.com: Melden Sie den Fehler Ihrem Anthropic-Account-Team mit der Sitzungs-ID aus der
withheld-Zeile. Anthropic erfasst den Grund auf seiner Seite.
- Eine Zeile mit
remote: access denied by the git proxy: Auch eine Sitzung, für die Anthropic Git bereitstellt, kann abgewiesen werden, zum Beispiel wenn eine Organisationsrichtlinie den Git-Zugriff für die Sitzung verweigert oder die Sitzung nicht für das Repository autorisiert ist. Das Log des Runners zeigt dann eine Zeile mitremote: access denied by the git proxy, und der Rest dieser Zeile nennt den Grund. GitHub authentication required: Dies erscheint, wenn der Ersteller der Sitzung keine funktionierende GitHub-Verbindung auf claude.ai hat. Der Clone der Sitzung schlägt fehl, und der Git-Fehler lautetGitHub authentication required. Please reconnect your GitHub account.Bitten Sie diese Person, GitHub in ihren claude.ai-Einstellungen zu verbinden oder erneut zu verbinden.
Den Anthropic-Git-Proxy ausschalten
Wenn Sitzungen in einer Umgebung ein Repository auf einem anderen Git-Host als github.com verwenden, etwa GitHub Enterprise Server, schalten Sie--use-anthropic-git-proxy für die Runner dieser Umgebung aus.
Flag entfernen
--use-anthropic-git-proxy aus dem Befehl des Runners. Wenn Sie CLAUDE_RUNNER_USE_GIT_PROXY in der Umgebung des Runners gesetzt haben, etwa in einer Pod-Spezifikation oder einer Compose-Datei, entfernen Sie es dort. Heben Sie es in einer Shell auf:Dem Runner Git-Anmeldedaten geben
--use-anthropic-git-proxy gesetzt war. Liefern Sie Anmeldedaten in Ihrem Image mit oder verwenden Sie einen checkout-Lebenszyklus-Hook.Netzwerkpfad öffnen
Runner neu starten
GitHub-API-Zugriff ohne die GitHub CLI
Wenn Ihr Runner-Image die GitHub CLI nicht enthält, kann Claude Code ein integriertesgh bereitstellen, sodass Claude weiterhin Pull Requests öffnen, kommentieren und CI-Ergebnisse lesen kann. Das integrierte gh ist für Runner gedacht, die Anthropic-verwaltetes Git verwenden. Es unterstützt einen einzigen Befehl, gh api, der die REST-API von GitHub aufruft. Erfordert Claude Code v2.1.287 oder später im Runner-Image.
Dieser Befehl öffnet einen Pull Request anstelle von gh pr create. Das integrierte gh füllt {owner} und {repo} für das aktuelle Repository aus:
- Anmeldedaten: Das integrierte
ghsendet seine REST-Anfragen über Anthropic-verwaltetes Git, das die GitHub-Anmeldedaten auf Anthropic’s Seite bereitstellt, daher benötigt das Image dafür kein GitHub-Token - Welche Sitzungen es erhalten: Anthropic entscheidet pro Sitzung, ob Anthropic-verwaltetes Git das
ghder Sitzung bedient. Wenn ja, zeigt die Zeile[runner:session] governed git ACTIVE, die der Runner für die Sitzung protokolliert,gh_path_shim=true. Wenn nicht, hat die Sitzung keingh jq: Installieren Siejqim Image, wenn--jqfunktionieren sollCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: Wenn die Sitzungsumgebung diese Variable setzt, stellt Claude Code das integrierteghnicht bereit, und die Sitzung hat keingh
Vertrauen Sie einer privaten Zertifizierungsstelle mit Anthropic-verwaltetem Git
Dieser Abschnitt gilt, wenn SieGIT_SSL_CAINFO oder GIT_SSL_NO_VERIFY in der Umgebung eines Runners setzen, dessen Sitzungen Anthropic-verwaltetes Git verwenden. Die hier beschriebene Behandlung erfordert, dass der Runner Claude Code v2.1.283 oder später ausführt.
Wenn Git auf dem Runner einer privaten Zertifizierungsstelle (CA) vertrauen muss, wie beispielsweise der, die ein TLS-inspizierender Proxy signiert, funktionieren die üblichen Ansätze wie folgt:
- System-Zertifikatspeicher: Installieren Sie Ihre CA im System-Zertifikatspeicher des Runner-Hosts, und Git vertraut ihr ohne eine der beiden Variablen.
GIT_SSL_CAINFO: Setzen Sie sie auf eine PEM-Datei Ihrer CAs, zum BeispielGIT_SSL_CAINFO=/etc/ssl/corp-ca.pem.GIT_SSL_NO_VERIFY: hilft nicht hinter einem Neu-Signierungs-Proxy. Der Runner’s eigener Clone durch Anthropic-verwaltetes Git überprüft Zertifikate auch wenn die Variable gesetzt ist, daher schlägt dieser Clone fehl, bis Git Ihrer CA durch einen der anderen beiden Ansätze vertraut.
command-Hook beginnt mit der Umgebung der Sitzung, daher erhält er, was Git innerhalb der Sitzung erhält:
GIT_SSL_CAINFO: Was Git gegen Anthropic-verwaltetes Git überprüft, hängt davon ab, wo Git ausgeführt wird:- Runner’s eigener Clone und Abrufe: Laufen ohne die Variable und überprüfen Anthropic-verwaltetes Git gegen eine Pro-Sitzungs-Zertifikatsdatei, die der Runner schreibt. Der Runner erstellt diese Datei aus dem System-CA-Bundle des Runner-Hosts und den Zertifikaten in Ihrer Datei.
- Git innerhalb der Sitzung: Erhält
http.sslCAInfo-Konfiguration, die Ihre Datei anstelle der Variable benennt, plushttp.<url>.sslCAInfo-Einträge, die Anthropic-verwaltetes Git gegen die Pro-Sitzungs-Datei überprüfen. checkout- undpost-session-Hooks: Erben die Variable unverändert.
GIT_SSL_NO_VERIFY: Welche Zertifikatsüberprüfungen ausgeschaltet bleiben, hängt davon ab, wo Git ausgeführt wird:- Runner’s eigener Clone und Abrufe: Laufen ohne die Variable und überprüfen das Zertifikat, das ihnen präsentiert wird.
- Git innerhalb der Sitzung: Erhält
http.sslVerify=false-Konfiguration anstelle der Variable, daher bleiben Überprüfungen für andere Hosts ausgeschaltet. Es erhält auchhttp.<url>.sslVerify=true-Einträge, die Überprüfungen für Anthropic-verwaltetes Git eingeschaltet halten. checkout- undpost-session-Hooks: Wenn die Sitzung ein Repository auf Anthropic-verwaltetem Git hat, erhaltenhttp.sslVerify=false-Konfiguration anstelle der Variable. Sie erhalten auchhttp.<url>.sslVerify=true-Einträge, die Überprüfungen für Anthropic-verwaltetes Git eingeschaltet halten.
/etc/ssl/certs/ca-certificates.crt oder /etc/pki/tls/certs/ca-bundle.crt auf dem Runner-Host. Sie benötigt auch eine GIT_SSL_CAINFO-Datei, die der Runner’s Benutzer lesen kann, die PEM-CERTIFICATE-Blöcke enthält, und die höchstens 1 MiB groß ist. Wenn der Runner die Pro-Sitzungs-Datei nicht erstellen kann, protokolliert er eine [runner:warn]-Zeile, die did not build the certificate file und den Grund enthält. Git verwendet dann Ihre Datei wie sie ist für Anthropic-verwaltetes Git. Beheben Sie, was die Zeile benennt.
Für jede Sitzung, die Anthropic-verwaltetes Git verwendet, protokolliert der Runner auch eine [runner:warn]-Zeile, die mit governed git: GIT_SSL_CAINFO is set oder governed git: GIT_SSL_NO_VERIFY is set beginnt. Die Zeile sagt, was der Runner mit dieser Variable für sein eigenes Git, für Git innerhalb der Sitzung und für Ihre Lebenszyklus-Hooks getan hat. Sie endet damit, ob Sie etwas ändern müssen.
github.com-Repositorys zu Claude Tag-Channel-Sitzungen hinzufügen
Wenn Claude ein github.com-Repository nicht zu einer Claude Tag-Channel-Sitzung hinzufügen kann, stellen Sie sicher, dass der Channel Zugriff darauf hat, auch wenn Ihr Runner es klonen kann. Dieser Zugriff ergibt sich aus Einstellungen auf GitHub und in Ihrer Claude-Organisation, nicht aus den Git-Anmeldedaten Ihres Runners.Die Claude GitHub App installieren
Die GitHub-Organisation oder das GitHub-Konto verknüpfen
Das Repository freigeben
Schreiben Sie Git-URLs für private Netzwerke um
Repository-URLs kommen von der Kontrollebene als HTTPS mit dem Hostnamen Ihres Git-Hosts; für GitHub Enterprise ist das der Hostname, den Sie für die GitHub Enterprise-Integration auf claude.ai konfiguriert haben. Zwei wiederholbare Flags schreiben diese URLs vor dem Clone um:--git-host-rewrite <from>=<to>: für Split-Horizon-DNS, wo Anthropic Ihren Git-Host über einen externen Hostnamen erreicht, aber Runner einen internen verwenden müssen--git-ssh-rewrite <host>: für Git-Hosts, die nur SSH akzeptieren, oder einen Runner-Host, der nur einen SSH-Schlüssel hat. Um beispielsweise github.com-Repositorys über SSH zu klonen, fügen Sie dem Runner-Befehl--git-ssh-rewrite github.comhinzu. Der Runner schreibt dannhttps://github.com/owner/repoingit@github.com:owner/repoum. SSH muss ohne Eingabeaufforderung eine Verbindung herstellen.
--git-ssh-rewrite auf, wenn Sie beide benötigen. Für vollständige Kontrolle über Checkout verwenden Sie einen checkout-Lebenszyklus-Hook.
Erstellen Sie das Runner-Image
Anthropic veröffentlicht kein vorgefertigtes Runner-Image. Erstellen Sie Ihr eigenes um dieclaude-Binärdatei, schichten Sie ein, was auch immer Ihre Repositorys benötigen: Sprach-Laufzeiten, Compiler, Paket-Manager und MCP-Sidecars.
Die Rezepte unten verwenden --capacity 4, daher bedient ein Container bis zu vier gleichzeitige Sitzungen vom selben gesperrten Owner. Das bietet nicht die Pro-Sitzungs-Container-Isolation im Härtungsabschnitt: Bevor Sie eine Umgebung mit Produktionssystemen verbinden, führen Sie entweder die Rezepte bei --capacity 1 mit einem Container pro Sitzung aus, oder verwenden Sie On-Demand-Runner, die auch das Umgebungsgeheimnis von sitzungsausführenden Hosts fernhalten. Wenn Sie den Anthropic-Git-Proxy zu einem dieser Rezepte hinzufügen, ändern Sie auch --capacity auf 1.
Dieses Dockerfile ist ein minimaler Ausgangspunkt. Es installiert python3, weil die Hooks, die die Control Plane von Anthropic bereitstellt, in Claude-Tag-Sitzungen python3 ausführen, einschließlich des Hooks, mit dem Claude seine Antwort in Slack postet. Behalten Sie python3 im PATH jedes Images, das Claude-Tag-Sitzungen bedient:
linux-x64 gegen linux-arm64 aus, wenn Ihre Knoten ARM sind, oder gegen linux-x64-musl oder linux-arm64-musl auf einem musl-basierten Image wie Alpine; siehe Alpine Linux-Setup für die zusätzlichen Pakete, die musl-Images benötigen. Die URL ist der Standard-Claude-Code-Release-Ort, daher können Sie die heruntergeladene Binärdatei gegen das signierte Manifest des Release überprüfen, wie in Binäre Integrität und Code-Signierung beschrieben. Der Runner erfordert Claude Code Version 2.1.224 oder später bzw. 2.1.229 oder später, um Claude-Tag-Sitzungen zu bedienen. Erstellen Sie das Image, pushen Sie es dann in Ihre Registry und referenzieren Sie es in den Rezepten unten:
stable-Release-Nummer nach und übergibt sie als Build-Argument, daher wird das Image nach einer neuen stabilen Release durch Ausführung desselben Befehls mit der neueren Binärdatei neu erstellt. Um eine bestimmte Release für reproduzierbare Builds zu fixieren, übergeben Sie die Versionsnummer direkt als CLAUDE_CODE_VERSION. Ersetzen Sie stable durch latest in der Nachschlag-URL, wenn Sie eine Release benötigen, die neuer als der stabile Kanal ist, z. B. eine, die ein neu gestartetes Modell erfordert.
Dimensionieren Sie CPU und Speicher für Sitzungen
Dimensionieren Sie einen Runner-Container oder Host für die Sitzungen, die er ausführt, anstatt für den Runner-Prozess. Der Runner selbst fragt nach Arbeit ab, bereitet den Checkout jeder Sitzung vor, führt Ihre Lebenszyklus-Hooks aus und startet und überwacht die Sitzungs-Prozesse. Die Last kommt von den Sitzungen: Jede ist ein Claude Code-Prozess plus alles, was sie startet, wie Builds, Test-Suites, Paket-Installationen und MCP-Server. Für eine Sitzung beginnen Sie mit den folgenden Werten, angegeben als Kubernetes-Anfragen und Limits oder das Äquivalent Ihrer Plattform, und behandeln Sie sie als Ausgangspunkt anstatt als Anforderung:- Speicher: eine Anfrage und ein Limit von jeweils 4 GiB, was das 4-GB-Minimum in Claude Code’s Systemanforderungen erfüllt. Halten Sie die beiden gleich, damit der Scheduler die volle Speicherkapazität des Containers berücksichtigt. Wenn der Container sein Speicherlimit erreicht, tötet der Kernel Prozesse darin, was eine Sitzung mitten in einer Aufgabe beenden kann.
- CPU: eine Anfrage von 2 CPUs und ein Limit von 4 CPUs, daher kann eine Sitzung während Builds über die Anfrage hinaus platzen. Der Kernel drosselt einen Container bei seinem CPU-Limit, anstatt Prozesse darin zu töten, daher laufen Sitzungen am Limit langsamer, aber laufen weiter.
resources-Block:
--capacity, um zu begrenzen, wie viele Sitzungen er gleichzeitig ausführt. Er teilt CPU oder Speicher nicht zwischen ihnen, daher teilen sich die Sitzungen auf einem Runner die CPU und den Speicher des Containers. Damit die Speichernutzung einer Sitzung die anderen nicht beendet, führen Sie eine Sitzung pro Runner mit einem eigenen Speicherlimit aus.
-
Eine Sitzung pro Runner: Geben Sie jedem Container die Werte einer Sitzung. Verwenden Sie diese Dimensionierung bei
--capacity 1, das der Härtungsabschnitt empfiehlt, und für On-Demand-Runner, wo Sie die Werte auf der Workload setzen, die Ihrspawn-runner-Hook einreicht, wie ein Kubernetes Job’s Pod-Template. -
Mehrere Sitzungen pro Runner: Bei einem
--capacityüber eins multiplizieren Sie die Werte einer Sitzung mit der Kapazität, weil bis zu so viele Sitzungen gleichzeitig im Container laufen können. Die Kubernetes- und Docker Compose-Rezepte führen--capacity 4ohne CPU- oder Speicherlimits aus, daher fügen Sie Limits hinzu, die für die Kapazität dimensioniert sind, die Sie ausführen. -
Mehrere Runner-Container auf einem Host: Dimensionieren Sie den Host für die Summe der Kapazitäten der Runner, weil jeder Runner nur seine eigenen Sitzungen auf
--capacityanrechnet:- Speicher: Multiplizieren Sie den Speicher einer Sitzung mit der Summe und addieren Sie dann, was die eigenen Prozesse des Hosts verwenden
- CPU: Multiplizieren Sie die CPU-Anfrage einer Sitzung mit der Summe. Damit jede Sitzung gleichzeitig über ihre Anfrage hinausgehen kann, multiplizieren Sie stattdessen ihr CPU-Limit.
--base-dir-Pfad, auf einem Datenspeicher, den kein Container eines anderen Runners einbindet, damit jeder Runner ein eigenes Arbeitsverzeichnis hat.
Geben Sie jeder Sitzung ein eigenes Speicherlimit
Um zu verhindern, dass eine Sitzung die anderen beendet, wenn der Speicher ausgeht, führen Sie jeden Runner bei--capacity 1 unter einem eigenen Speicherlimit aus, das auf den Speicher einer Sitzung gesetzt ist:
- In einem Container: Führen Sie einen Runner pro Container aus und setzen Sie das Speicherlimit des Containers, etwa
limits.memoryunter Kubernetes,--memoryunter Docker odermem_limitin einer Compose-Datei. Halten Sie die Summe der Limits der Container unter dem Speicher des Hosts, denn wenn dem Host selbst der Speicher ausgeht, kann der Kernel Prozesse an beliebiger Stelle auf dem Host beenden. - Unter systemd ohne Container: Setzen Sie
MemoryMaxfür die Unit des Runners und führen Sie einen Runner pro Host aus, denn Runner, die dasselbe--base-dirauf einem Dateisystem verwenden, teilen sich die dort geklonten Repositorys. Beispielsweise können ihre Sitzungen bei--capacity 1ohnecheckout-Hook gleichzeitig im selben Checkout eines Repositorys arbeiten. Um mehrere Runner auf einem Host auszuführen, geben Sie jedem einen Container.
--capacity über eins setzen, teilen sich die Sitzungen ein Limit. Wenn sie es erreichen, wählt der Kernel die zu beendenden Prozesse nicht nach Sitzung aus, sodass die Speichernutzung einer Sitzung die anderen beenden kann.
Unter Kubernetes können Sie die Sitzungen mit keinem der beiden Werte der kubelet-Einstellung singleProcessOOMKill voneinander trennen. Ebenso wenig können Sie den Gesamtspeicher einer Sitzung mit einem Speicher-ulimit in Ihrem Wrapper-Skript begrenzen. Der Kernel wendet einen Wert wie ulimit -v auf jeden Prozess einzeln an.
Lassen Sie Spielraum unter Prozess- und Thread-Limits
Um ein Prozess- und Thread-Limit zu dimensionieren, messen Sie, was eine Sitzung benötigt, und multiplizieren Sie dies mit der Anzahl der Sitzungen, die sich das Limit teilen. Wenn diese Sitzungen das Limit erreichen, verweigert der Kernel neue Prozesse und Threads, sodass Befehle, Builds und Tests in jeder von ihnen fehlschlagen können. Der verweigerte Aufruf gibtEAGAIN zurück, dessen Standardmeldung Resource temporarily unavailable lautet.
Angenommen, eine Sitzung erreicht in der Spitze 300 Prozesse und Threads, und vier Sitzungen teilen sich das Limit. Zusammen benötigen sie 1.200, und mit einem Limit von 2.400 lassen Sie Spielraum für Builds, die doppelt so viel benötigen.
Wo Sie jedes Limit setzen
Jedes Limit in dieser Tabelle zählt sowohl Threads als auch Prozesse, undpids.max ist die Datei, die das Limit einer cgroup enthält:
TasksMax nicht setzen, wendet systemd DefaultTasksMax an, das standardmäßig 15 % des niedrigsten Werts von kernel.pid_max, kernel.threads-max und pids.max der Root-cgroup beträgt.
Messen Sie den Spitzenwert einer Sitzung
Um die Werte für Ihre eigenen Runner zu ermitteln, messen Sie eine Sitzung auf ihrem Host, unter Kubernetes also auf dem Node:Starten Sie einen einzelnen Runner
--capacity 1 ohne weitere Inhalte in seinem Container oder seiner systemd-Unit, allein auf seinem Host und in seiner Umgebung:- Sein Host: Verwenden Sie einen, auf dem kein anderer Runner läuft. So können Sie seinen Prozess im nächsten Schritt identifizieren.
- Seine Umgebung: Machen Sie ihn zum einzigen Runner dort, zum Beispiel in einer Umgebung, die Sie für den Test erstellen. Sitzungen werden an eine Umgebung geleitet und nicht an einen Runner.
Ermitteln Sie das cgroup-Verzeichnis des Runners
ps. Lesen Sie /proc/<pid>/cgroup für diese ID:- Eine Zeile enthält
:pids:: Der Host verwendet cgroup v1, und das Verzeichnis ist/sys/fs/cgroup/pids, gefolgt vom Text nach:pids: - Die einzige Zeile beginnt mit
0::: Der Host verwendet cgroup v2, und das Verzeichnis ist/sys/fs/cgroup, gefolgt vom Text nach0::
Führen Sie einen repräsentativen Build aus und erfassen Sie den Spitzenwert
- Das Verzeichnis enthält
pids.peak: Lesen Sie die Datei, nachdem der Build abgeschlossen ist - Das Verzeichnis enthält kein
pids.peak: Lesen Siepids.currenteinmal pro Sekunde, während der Build läuft, und behalten Sie den höchsten Wert. Ein Spitzenwert zwischen zwei Lesevorgängen bleibt unbemerkt, behandeln Sie diesen Wert daher als niedrige Schätzung.
Multiplizieren Sie mit den Sitzungen, die sich das Limit teilen
- Pod, Container oder Unit eines Runners: Multiplizieren Sie den Spitzenwert mit der
--capacitydes Runners - Ein Limit, das sich mehrere Runner teilen: Multiplizieren Sie den Spitzenwert mit der Summe ihrer Kapazitäten
Setzen Sie das Limit über dem Ergebnis
Prüfen Sie ein pids.max-Limit
- Prüfen, ob
pids.maxerreicht wurde: Durchsuchen Sie das Kernel-Log des Hosts, zum Beispiel mitdmesg, nach einer Zeile, diecgroup: fork rejected by pids controller inund den Pfad einer cgroup enthält. Der Kernel protokolliert sie nur beim ersten Mal, wenn er in dieser cgroup einen Prozess oder Thread verweigert, durchsuchen Sie daher das gesamte Log. - Das geltende Limit anzeigen: Lesen Sie
pids.maxim cgroup-Verzeichnis des Runners und in jedem darüberliegenden Verzeichnis. Der niedrigste Wert ist das geltende Limit, undmaxbedeutet, dass auf dieser Ebene kein Limit besteht.
Kubernetes
Der Runner bedientGET /healthz auf Port 8080 standardmäßig, konfigurierbar mit --health-port, daher funktionieren Kubernetes-Probes ohne zusätzliches Setup. Der Endpunkt gibt 200 zurück, wann immer der Prozess lebt, daher erkennen die Probes unten einen toten Prozess, nicht einen steckengebliebenen; um einen Runner zu fangen, der aufgehört hat zu pollen, warnen Sie die last_poll_age_seconds-Serie von /metrics. Die Deployment unten bindet das Umgebungsgeheimnis von einem Kubernetes Secret, zeigt die Liveness- und Readiness-Probes auf /healthz und setzt eine 90-Sekunden-Terminierungs-Grace-Periode. Siehe Shutdown-Timing für warum die Grace-Periode wichtig ist.
Das Manifest setzt keine CPU- oder Speicher-resources auf dem Runner-Container. Fügen Sie einen Block hinzu, der für die Kapazität dimensioniert ist, die Sie ausführen, wie Dimensionieren Sie CPU und Speicher für Sitzungen beschreibt.
claude-runners-Namespace. Erstellen Sie den Namespace zuerst:
(umask 077 && cat > ./environment-secret) aus, fügen Sie das Geheimnis ein, drücken Sie Enter und dann Ctrl-D. Erstellen Sie anschließend das Secret und löschen Sie die Datei:
Docker Compose
Der Compose-Service unten startet den Runner neu, wann immer er beendet wird, was sowohl Crashes als auch den normalen Exit nach dem Draining abdeckt. Eine Docker-Restart-Richtlinie startet den gleichen Container mit seiner beschreibbaren Schicht intakt neu, daher kommt der Runner auf einem wiederverwendeten Dateisystem anstatt dem frischen, das die Härtungs-Haltung empfiehlt; verwenden Sie dieses Rezept zur Evaluierung, und für die Produktion entweder den Container pro Lauf neu erstellen oder einen Orchestrator verwenden, der das tut. Docker wartet länger, bevor jeder Neustart eines Containers erfolgt, der weiterhin beendet wird, bis zu einer Obergrenze, daher startet ein Runner, der nicht gestartet werden kann, nicht in einer engen Schleife unter diesem Rezept neu. Wenn der Runner beendet wird beschreibt, was zu überprüfen ist, wenn das passiert.Zeitverhalten beim Herunterfahren
NachSIGTERM benötigt ein Runner Zeit, um seine Sitzungen sauber herunterzufahren, bevor Ihr Orchestrator ihn beendet. Wie lange, protokolliert er beim Start in einer Zeile, die bei Standardeinstellungen This runner needs up to 80s enthält. Setzen Sie das Stopp-Timeout Ihres Orchestrators auf mindestens so viele Sekunden: terminationGracePeriodSeconds unter Kubernetes, stop_grace_period unter Docker Compose oder das Äquivalent Ihrer Plattform. Kubernetes verwendet standardmäßig 30 Sekunden, sodass es ohne diese Einstellung den Pod stoppen kann, bevor der Runner fertig ist.
Bei SIGTERM nimmt der Runner keine neuen Sitzungen mehr an. Anschließend beginnt er ein geordnetes Herunterfahren, den sogenannten Drain, sofern Sie nicht --defer-shutdown-max-min setzen, um ihn aufzuschieben. Der Drain besteht aus drei Schritten:
- Der Runner wartet bis zu
--drain-wait-secSekunden, standardmäßig0, darauf, dass noch laufende Turns abgeschlossen werden. - Er beendet den Prozessbaum jeder Sitzung, einschließlich aller Befehle, die Claude noch ausgeführt hat, jedoch nicht einen Prozess, der nach dem Ende seines Shell-Befehls noch läuft.
- Er führt den
post-session-Lifecycle-Hook aus.
post-session-Hook noch nicht committete Arbeit sichert.
Die protokollierte Dauer ist die Summe dieser Werte:
--drain-wait-secfür Schritt 1, standardmäßig 0 Sekunden--session-stop-grace-secfür Schritt 2, standardmäßig 5 Sekunden--post-session-hook-timeout-secfür Schritt 3, standardmäßig 60 Sekunden- Ein fester Puffer von 15 Sekunden
- Weitere 30 Sekunden, wenn
--push-outcome-on-releasegesetzt ist
--capacity erhöht diesen Wert nicht, da der Runner alle seine Sitzungen gleichzeitig leert.
Planen Sie mehr Zeit ein, wenn Sie eines dieser Flags setzen:
- Mit
--retire-at: Bemessen Sie den Abstand zwischen dem Retire-Zeitpunkt und dem Stopp-Zeitpunkt des Hosts so, dass er typische Turns abdeckt, zuzüglich der Wartezeit für Hintergrundaufgaben, die unter Runner-Lebenszyklus beschrieben ist, zuzüglich der protokollierten Dauer. Berechnen Sie den Retire-Zeitpunkt bei jedem Start, beispielsweisedate +%splus die vorgesehene Lebensdauer des Runners. - Mit
--defer-shutdown-max-min: Das Stopp-Timeout muss zusätzlich die von Ihnen konfigurierten Minuten abdecken sowie eine weitere Wartezeit vor Beginn des Drains, mit Standardeinstellungen 75 Sekunden. Das Leeren über das erste Signal hinaus aufschieben erläutert beides. Der Runner protokolliert diese längere Dauer ebenfalls beim Start.
Laufende Turns vor einem Neustart abschließen lassen
Damit laufende Turns vor einem Rolling Restart abgeschlossen werden können, setzen Sie--drain-wait-sec und erhöhen Sie Ihr Stopp-Timeout auf mindestens diese Wartezeit plus 80 Sekunden. Mit der Standard-Wartezeit von 0 unterbricht ein Neustart jeden noch laufenden Turn, und die Sitzung wird auf einem anderen Runner ohne ihre nicht gepushte Arbeit fortgesetzt.
--drain-wait-sec: etwa so lange wie die Turns und Hintergrundaufgaben, die Sie abschließen lassen möchten. Es handelt sich um einen Höchstwert: Die Wartezeit endet früher, wenn sie zuerst abgeschlossen sind.- Ihr Stopp-Timeout:
terminationGracePeriodSecondsin Kubernetes,stop_grace_periodin Docker Compose. Ersetzen Sie beispielsweise bei--drain-wait-sec 120die90im Rezept für Kubernetes oder Docker Compose durch200. - Wenn Sie andere Einstellungen für das Herunterfahren geändert haben: Die 80 Sekunden gelten für Standardeinstellungen. Starten Sie einen Runner mit Ihren Flags und verwenden Sie mindestens die Zahl in seiner Startzeile
This runner needs up to, die die Wartezeit einschließt. Wenn--defer-shutdown-max-mingesetzt ist, verwenden Sie die größere Zahl in der nächsten Startzeile, nachSize the stop timeout to at least. Zeitverhalten beim Herunterfahren listet auf, was zu diesen Zahlen beiträgt.
Vor einem Neustart eine Statusmeldung veröffentlichen
Lassen Sie vor einem Neustart, der Sitzungen unterbrechen wird, einen Owner über die Admin-Seite Cloud environments eine Statusmeldung für die Umgebung veröffentlichen. Unter claude.ai/code sehen Mitglieder die Meldung in ihren Sitzungen in dieser Umgebung. Lassen Sie den Owner beim Veröffentlichen ein Ablaufdatum festlegen oder die Meldung entfernen, sobald die Runner wieder verfügbar sind.Das Leeren über das erste Signal hinaus aufschieben
Setzen Sie--defer-shutdown-max-min <n>, wenn ein Runner, den Sie neu starten, die von ihm gehaltenen Sitzungen noch bis zu n Minuten weiter bedienen soll, statt sie beim ersten Signal zu leeren. Beim ersten SIGTERM oder SIGINT nimmt der Runner keine neue Arbeit mehr an und bedient die von ihm gehaltenen Sitzungen weiter. Er fragt weiterhin ab, damit die Control Plane diese Sitzungen nicht neu einreiht. Erfordert Claude Code v2.1.238 oder höher.
Was nach dem ersten Signal mit den vom Runner gehaltenen Sitzungen geschieht
In den ersten beiden Phasen nach dem Signal gibt der Runner Sitzungen frei, und eine freigegebene Sitzung wird auf einem neuen Runner fortgesetzt, wenn ihr Benutzer die nächste Nachricht sendet. Ab dem ersten Signal gerechnet durchläuft der Runner drei Phasen:- Während der ersten
nMinuten: Der Runner bedient seine Sitzungen normal und setzt--startup-timeout-minund--kill-session-after-minweiterhin durch. Wenn Sie zusätzlich--release-idle-session-minsetzen, gibt der Runner jede Sitzung frei, deren Benutzer so lange inaktiv war; ohne dieses Flag bleiben inaktive Sitzungen auf dem Runner. - Wenn die
nMinuten abgelaufen sind: Der Runner gibt jede Sitzung frei, die er noch hält, ob inaktiv oder nicht. Bei einer Sitzung mitten in einem Turn wartet der Runner, bis der Turn endet, und bis zu 60 weitere Sekunden auf die Hintergrundaufgaben des Turns, bevor er diese Sitzung freigibt. - Wenn die Grace nach der Freigabe abgelaufen ist: Der Runner leert alle Sitzungen, die er noch hält, und die Control Plane reiht jede geleerte Sitzung sofort bei einem anderen Runner neu ein. Die Grace nach der Freigabe beginnt, wenn die
nMinuten abgelaufen sind, und beträgt mit Standardwerten 75 Sekunden. Wenn Sie--drain-wait-secauf mehr als 60 Sekunden setzen, beträgt die Grace nach der Freigabe stattdessen--drain-wait-secplus 15 Sekunden.
--defer-shutdown-max-min tut. Sobald ein Leeren im Gange ist, erzwingt das nächste Signal das Beenden des Runners. Das gilt unabhängig davon, ob ein zweites Signal oder der Ablauf der Grace nach der Freigabe das Leeren ausgelöst hat.
Das Stopp-Timeout bemessen
Geben Sie dem Stopp-Timeout Ihres Hosts mindestens die Summe aus drei Anteilen: die von Ihnen konfiguriertenn Minuten, die Grace nach der Freigabe und den Drain, der unter Zeitverhalten beim Herunterfahren beschrieben ist. Mit Standardeinstellungen beträgt die Grace nach der Freigabe 75 Sekunden und der Drain dauert bis zu 80 Sekunden, planen Sie also n Minuten plus 155 Sekunden ein. Der Runner gibt diese Summe beim Start aus, wann immer --defer-shutdown-max-min gesetzt ist.
Wenn das Stopp-Timeout abläuft, bevor der Runner fertig ist, erhalten die Sitzungen, die er noch hält, keinen post-session-Hook. Der Runner meldet sich nicht ab, sodass die Control Plane einige Minuten und manchmal länger benötigen kann, um diese Sitzungen neu einzureihen. Wenn Sie dem Stopp-Timeout diese Summe nicht geben können, lassen Sie --defer-shutdown-max-min ungesetzt, damit der Runner stattdessen beim ersten Signal leert.
Was einen laufenden post-session-Hook erreicht
Derpost-session-Hook und der Claude-Sitzungs-Kindprozess laufen jeweils in einer eigenen POSIX-Prozessgruppe, getrennt von der des Runners, sodass Stopp-Mechanismen sie unterschiedlich erreichen:
- Ein
SIGTERM, während der Runner bereits leert: erzwingt das sofortige Beenden des Runners und überspringt den verbleibenden Rest des Drains. Ohne--defer-shutdown-max-minist das das zweiteSIGTERM, das der Runner empfängt. Nichts sendet einem laufendenpost-session-Hook ein Signal, sodass er auf einem Bare-Host, auf dem ein Init-Prozess verwaiste Prozesse übernimmt, eigenständig zu Ende läuft, jedoch unbeaufsichtigt: Sein Timeout-Budget gilt nicht mehr, und ein Schreibvorgang in die geschlossene Log-Pipe kann ihn mitSIGPIPEbeenden. Ein Hook, der dort ein erzwungenes Beenden überstehen muss, sollte seine eigene Ausgabe daher in eine Datei umleiten. In den Container-Rezepten auf dieser Seite ist der Runner PID 1 des Containers und sein Beenden beendet den Container, und unter dem systemd-StandardKillMode=control-grouperreicht das cgroup-weite Beenden auch den Hook, wie der Eintrag Cgroup-weite Kills beschreibt; behandeln Sie in beiden Fällen ein erzwungenes Beenden als fatal für den Hook und verlassen Sie sich stattdessen auf die Grace Period. - Prozessgruppenweite Signale, etwa
kill -- -<pid>in einem Wrapper-Skript, Shell-Jobsteuerung oder ein gruppenweiter Watchdog: erreichen den Runner und einen Unterprozess eines laufendencheckout-Hooks, der absichtlich an die Gruppe gebunden bleibt, aber keinen laufendenpost-session-Hook und nicht den Sitzungs-Kindprozess. - Cgroup-weite Kills, etwa der systemd-Standard
KillMode=control-groupoder dasSIGKILL, das Kubernetes an den gesamten Container sendet, wennterminationGracePeriodSecondsabläuft: erreichen alles, einschließlich des Hooks. Die Isolation der Prozessgruppe schützt davor nicht, weshalb die Grace Period den gesamten Drain abdecken muss. - Das eigene Timeout des Hooks: Wenn ein Hook
--post-session-hook-timeout-secüberschreitet, sendet der RunnerSIGTERMan die gesamte Prozessgruppe des Hooks und zwei Sekunden späterSIGKILL, sodass ein vom Hook abgespaltener Worker, etwa tar, rsync oder git, zusammen mit der Wrapper-Shell beendet wird, statt als verwaister Prozess weiterzuleben. Die Überwachung durch den Runner endet, sobald die stdio des Hooks geschlossen wird: Ein Worker, der seine eigene Ausgabe in eine Datei umgeleitet hat und dieSIGTERM-Phase überlebt, liegt außerhalb der Reichweite des Runners.
post-session-Hooks noch laufen, sodass Sie ein ruhiges Leeren von einem unterscheiden können, das sich mitten in einem Snapshot befindet.
Halten Sie das Basis-Verzeichnis und die Kapazität über Runner identisch
Wenn ein Runner Mid-Sitzung stirbt, requeued der Server die Sitzung und ein anderer Runner in der Umgebung hebt sie auf. Dieser Runner leitet den Checkout-Pfad von seinem eigenen--base-dir und --capacity ab: --capacity 1 checkt direkt unter --base-dir aus, und ein --capacity über 1 verwendet stattdessen Pro-Sitzungs-Worktrees. Wenn Runner in der gleichen Umgebung unterschiedliche Werte für eines der Flags verwenden, ändert sich das Arbeitsverzeichnis der fortgesetzten Sitzung, und absolute Pfade, die der Agent früher aufgezeichnet hat, in Edits, Tool-Aufrufen oder seinen eigenen Notizen, zeigen auf einen Ort, der nicht mehr existiert.
Verwenden Sie den gleichen --base-dir und --capacity auf jedem Runner in einer Umgebung, und verwenden Sie keinen Pro-Host-Wert wie eine Instance-ID oder einen Hostnamen. Übergeben Sie beide Flags explizit, wie es die Rezepte für Kubernetes und Docker Compose tun, sodass keiner der beiden Werte von einem Standardwert abhängt.
Das Basis-Verzeichnis standardmäßig auf /workspace, mit der Ausnahme, die die --base-dir-Referenz-Zeile aufzeichnet. Der Runner benötigt Schreibzugriff darauf. Beim Start, vor der Registrierung, erstellt der Runner das Verzeichnis und bestätigt, dass er darin schreiben kann, und beendet sich mit cannot create or write to base directory, wenn er nicht kann. Ein Runner, der als Root gestartet wird, erstellt das Standard /workspace selbst. Für einen Non-Root-Runner erstellen Sie das Verzeichnis und geben Sie dem Runner’s Benutzer Eigentum, bevor Sie den Runner starten, oder zeigen Sie --base-dir auf ein Verzeichnis, das dieser Benutzer bereits besitzt.
Wiederverwendung eines vorgewärmten Checkouts
Bei großen Repositories kann das Klonen den Sitzungsstart dominieren. Um das kalte Klonen zu überspringen, stellen Sie selbst einen Klon unter dem Pfad bereit, an dem der Runner seinen eigenen Klon ablegt. Ohnecheckout Hook behält der Runner einen kanonischen Klon pro Repository unter <base-dir>/<repo-owner>/<repo> und verwendet ihn über Sitzungen hinweg erneut:
- Bei
--capacity 1: Der Runner ruft die angeforderte Referenz ab, trenntHEADab und setzt hart darauf zurück, was nahezu augenblicklich ist, wenn sich wenig geändert hat. - Bei einer
--capacitygrößer als eins: Der Runner ruft in diesen Klon ab und checkt dann für jede Sitzung einen separaten Worktree daraus aus. Ein vorgewärmter Klon spart den Download, aber nicht den Checkout.
- Klon im Image: Erstellen Sie den Klon in Ihrem Runner-Image unter diesem Pfad. Jeder neue Container startet dann mit dem warmen Klon, ohne eine Festplatte wiederzuverwenden.
- Klon auf einem persistenten Volume: Bei Runnern, die Sie mit
--lock-to-accountauf das Konto eines Benutzers sperren, verweisen Sie--base-dirauf ein persistentes Volume, sodass die Festplatte nur diesem Konto dient. Ein gesperrter Runner akzeptiert niemals Claude Tag Channel-Sitzungen, daher gilt diese Option nicht für Runner, die diese bedienen.
-
Klontiefe: Erstellen Sie den Klon ohne
--depth, mit oder ohne--single-branch. Der Runner übergibt niemals--depth, wenn er in einen Klon mit einemorigin-Remote abruft, selbst wenn SieCLAUDE_RUNNER_FETCH_DEPTHfestlegen. Bei einem vollständigen Klon lädt jede Sitzung nur die Commits herunter, die dem Klon fehlen. Bei einem flachen Klon lädt eine Sitzung auf einem Branch, der vor dem ältesten Commit des Klons abgezweigt wurde, die gesamte Historie dieses Branches herunter. -
Nachverfolgte Änderungen werden zurückgesetzt, nicht nachverfolgte Dateien bleiben erhalten: Bei
--capacity 1beginnt jede Sitzung mit einem harten Zurücksetzen, das die nachverfolgten Änderungen der vorherigen Sitzung löscht, aber der Runner führt niemalsgit cleanaus, daher bleiben nicht nachverfolgte Dateien aus früheren Sitzungen des gesperrten Besitzers im Baum. -
Per-Session-Verzeichnisse bleiben ebenfalls erhalten: Neben dem Checkout erstellt der Runner für jede Sitzung, die er ausführt, Einträge pro Sitzung unter
<base-dir>/_sessions/. Das Claude-Konfigurationsverzeichnis der Sitzung enthält eine lokale Kopie des Gesprächstranskripts. Daneben befinden sich die hochgeladenen Dateien der Sitzung, falls die Sitzung welche hat. Das Sitzungsverzeichnis befindet sich auch dort: Es enthält alle Pro-Session-Worktrees undcheckoutHook-Checkouts während der Sitzung ausgeführt wird, und es behält alles andere, was Claude darin geschrieben hat. Standardmäßig lässt der Runner diese an Ort und Stelle, wenn die Sitzung endet, daher sammeln sie sich auf einer Festplatte an, die den Runner-Prozess überlebt. Jede Sitzung wird als eigener Benutzer des Runners ausgeführt, daher kann jede spätere Sitzung, die diese Festplatte bedient, sie lesen. Wenn Sie ein persistentes--base-dirbeibehalten, dimensionieren Sie das Volume für dieses Wachstum. Das Gleiche gilt für jedes Setup, das den Runner auf demselben Dateisystem neu startet, einschließlich des Docker Compose-Rezepts. -
Mit
--remove-session-statebleiben Per-Session-Verzeichnisse nicht erhalten: Starten Sie den Runner mit--remove-session-state, um ihn dazu zu bringen, die Per-Session-Verzeichnisse jeder Sitzung zu löschen, wenn die Sitzung endet. Das Löschen ist bestmöglich: Die Verzeichnisse bleiben erhalten, wenn der Runner beendet wird, bevor seine Bereinigung ausgeführt wird. Der kanonische Klon und Dateien, die eine Sitzung an anderer Stelle auf dem Host geschrieben hat, wie das temporäre Verzeichnis, bleiben unabhängig davon erhalten. -
Mit dem Git-Proxy wird das Zurücksetzen zu einem Checkout: Mit
--use-anthropic-git-proxybereinigt der Runner das.git/-Verzeichnis des Klons vor jeder Sitzung. Er behält den Objektspeicher und den flachen Zustand und löscht den Index. Ohne den Index beginnt jede Sitzung mit einem vollständigen Working-Tree-Checkout anstelle eines nahezu augenblicklichen Zurücksetzens. Der Runner ruft weiterhin in den vorhandenen Klon ab, anstatt das Repository erneut zu klonen. Submodul-Vorwärme wird unter dem Proxy nicht unterstützt. -
Mit dem Git-Proxy verliert ein
reftable-Vorwärm seine Referenzen: Wenn der Runner.git/vor jeder Sitzung bereinigt, behält er.git/refs/und entfernt das Verzeichnis.git/reftable/. Ein imreftable-Referenzformat von Git vorgewärmter Klon verliert auf diese Weise seine Referenzen. Wärmen Sie den Klon daher stattdessen imfiles-Referenzformat von Git vor. - Lange Klone benötigen keine Umgehung: Der Runner begrenzt jede Git-Operation mit einem 120-Sekunden-Watchdog ohne Fortschritt und einer 30-Minuten-Obergrenze, nicht mit einem flachen Timeout, daher wird ein langsamer kalter Klon, der weiterhin Fortschritt meldet, abgeschlossen.
Bestätigen, dass der Runner Ihren Klon verwendet
Um zu bestätigen, dass der Runner Ihren Klon verwendet, starten Sie ihn mit--log-level debug und starten Sie eine Sitzung für das Repository. Der Runner protokolliert Prefetched repo found at und den Pfad des Klons. Wenn er stattdessen No prefetched repo, fresh init at protokolliert, hat er unter dem Pfad in dieser Zeile keinen verwendbaren Klon gefunden. Prüfen Sie, ob sich Ihr Klon unter diesem Pfad befindet, dem Benutzer des Runners gehört und ein Remote namens origin hat.
Wenn der Runner Ihren Klon findet und Sitzungen dennoch langsam starten, prüfen Sie, ob der Klon flach ist.
Pinnen Sie die Version
Der Kindprozess jeder Sitzung führt standardmäßig die eigene Binärdatei des Runners aus, und der Runner schaltet Auto-Update in den Sitzungen, die er startet, aus. Mit dieser Standardeinstellung führt jede Sitzung die Version aus, die Sie auf dem Host installiert oder in das Image eingebaut haben. Ein Host-Level-Update wird wirksam, das nächste Mal, wenn der Runner startet. Legen Sie fest, welche Version Ihre Sitzungen ausführen und wann sie sich ändert:- Bevor Sie eine Version pinnen: Überprüfen Sie die Claude-Code-Versionen, die Modelle erfordern für jedes Modell, das Ihre Sitzungen verwenden. Wenn ein Modell eine neuere Version erfordert als die, die Ihre Sitzungen ausführen, lehnt der Server Anfragen für dieses Modell mit Claude Code unterstützt dieses Modell nicht ab.
- Um eine Flotte auf einer Version zu halten: Erstellen Sie das Image mit einer gepinnten Version, oder installieren Sie auf einem bloßen Host eine spezifische Version und deaktivieren Sie Auto-Updates
- Um eine feste Flotte zu aktualisieren: Lesen Sie die Changelog-Einträge zwischen Ihrer Version und der Version, die Sie installieren, und installieren Sie dann die neuere Version oder bauen Sie das Image neu und starten Sie die Runner neu
- Um bedarfsgesteuerte Runner zu aktualisieren: Lesen Sie die Changelog-Einträge zwischen Ihrer Version und der Version, die Sie installieren, und ändern Sie dann das Image, das Ihr
spawn-runner-Hook startet. Jeder neue Runner erhält die neue Version. Ein bereits laufender Runner, einschließlich eines Standby-Runners, den--min-idlegestartet hat, behält seine Version, bis er beendet wird. Starten Sie ihn nicht neu, da sein Arbeitsauftrag nur einmal verwendet werden kann. - Wenn Sitzungen eine andere Binärdatei starten: Wenn Sie
--exec-pathoder einencommand-Hook verwenden, um eine andere Claude-Code-Binärdatei als die des Runners zu starten, führen Sitzungen die Version dieser Binärdatei aus. Aktualisieren Sie diese Binärdatei, wenn Sie den Runner aktualisieren. - Plugins: Plugin-Marktplätze auto-updaten auch nicht; setzen Sie
FORCE_AUTOUPDATE_PLUGINS=1in der Runner’s Umgebung, um Plugins auto-updaten zu lassen, während die Binärdatei gepinnt bleibt
Skalieren Sie die Flotte
Ihr Orchestrator entscheidet, wann Runner hinzugefügt oder entfernt werden. Wegen der One-Owner-Per-Runner-Lock ist die minimale Replica-Anzahl die Anzahl der Benutzer und Claude Tag-Agenten, die Sie gleichzeitig aktiv erwarten;--capacity kontrolliert Parallelismus innerhalb einer Owner’s Sitzungen, nicht über Owners.
Zwei Skalierungs-Ansätze sind verfügbar:
- Feste Flotte: Führen Sie einen statischen Satz von Runner-Replicas aus und skalieren Sie auf den Prometheus-Metriken, die jeder Runner bedient
- On-Demand-Runner: Führen Sie den
claude self-hosted-runner orchestrator-Subcommand aus, der Anthropic auf Sitzungen abfragt, die mit keinem verfügbaren Runner in die Warteschlange eingereiht sind und Ihrenspawn-runner-Hook aufruft, um einen pro Sitzung zu starten. Siehe On-Demand-Runner.
Inaktive Sitzungen in einer festen Flotte freigeben
Wenn Sitzungen in einer festen Flotte in der Warteschlange bleiben, obwohl alle Runner online sind, können inaktive Sitzungen die Ursache sein. Standardmäßig behält eine Sitzung ihren Slot, nachdem ihr Turn abgeschlossen ist, und ihr Runner bleibt an den Owner dieser Sitzung gebunden. Wenn die geplante Cloud-Aufgabe Ihres Teams bei jeder Ausführung eine neue Sitzung startet, können deren inaktive Sitzungen alle Slots belegen. Lesen Sie zur Überprüfungclaude_code_self_hosted_runner_session_idle_seconds in den Prometheus-Metriken jedes Runners aus. Jede Sitzung, die ein Runner hält, hat ihre eigene Zeitreihe: 0, solange die Sitzung beschäftigt ist, andernfalls die Sekunden seit Beginn der Inaktivität. Wählen Sie die Inaktivitätsdauer, die Sie zulassen möchten: länger als die Pausen, die Personen mitten in einer Aufgabe einlegen, und kurz genug, dass jede Ausführung freigegeben wird, bevor die nächste Ausführung der geplanten Aufgabe beginnt. Vergleichen Sie die Zeitreihen mit diesem Wert.
- Zeitreihen über diesem Wert, etwa
1800für 30 Minuten: Inaktive Sitzungen belegen diese Slots, setzen Sie daher--release-idle-session-min - Alle Zeitreihen darunter: Keine Sitzung war so lange inaktiv. Fügen Sie Runner hinzu oder setzen Sie
--kill-session-after-minfür Sitzungen, die nie inaktiv werden. - Ein Runner ohne Zeitreihe: Keine Sitzung belegt ihn. Siehe Sitzungen bleiben in der Warteschlange unter Fehlerbehebung.
- Ein Runner, dessen Metriken nicht antworten: Sein Prozess wurde möglicherweise beendet. Siehe Eine Umgebung, die fehlerfrei aussieht unter Wenn der Runner beendet wird.
--release-idle-session-min und dieser Dauer in Minuten, etwa --release-idle-session-min 30. Der Runner gibt dann jede Sitzung frei, die so lange inaktiv bleibt, unabhängig davon, ob eine geplante Aufgabe oder eine Person sie gestartet hat.
- Nicht gepushte Arbeit: Eine freigegebene Sitzung wird bei ihrer nächsten Nachricht fortgesetzt, jedoch ohne die Arbeit, die sie nicht gepusht hatte. Wie Sie ihre Commits behalten, erfahren Sie unter Fortgesetzte Sitzungen verlieren nicht gepushte Arbeit.
- Runner wird beendet: Ein Runner, der seine letzte Sitzung freigibt, leitet ein normales Beenden ein. Lassen Sie ihn von Ihrem Supervisor auf einem frischen Dateisystem neu starten, wie unter Härten Sie Ihr Deployment beschrieben.
- Sitzungen, die nie inaktiv werden: Setzen Sie zusätzlich
--kill-session-after-min, da manche Sitzungen nicht als inaktiv gelten
Bekannte Probleme und Einschränkungen
Die folgenden sind die Einschränkungen in dieser Version, mit Umgehungen, wo eine existiert.Connector-Datenverkehr verlässt Ihr Netzwerk
Anthropic ruft Connector-Tools von seiner eigenen Infrastruktur anstatt von Ihrem Runner auf. Connector-Tools sind die claude.ai-Connectoren, wie GitHub, Slack und Linear. Wenn Claude einen Connector in einer selbstgehosteten Sitzung verwendet, geht dieser Datenverkehr durchapi.anthropic.com anstatt von innerhalb Ihrer Netzwerkgrenze zu stammen.
Um einen Connector aus selbstgehosteten Sitzungen zu halten, filtern Sie ihn mit den allowedMcpServers- und deniedMcpServers-Richtlinien-Einstellungen. Claude Code wendet diese Einstellungen auf die Connectoren an, die Anthropic liefert, sowie auf die Server, die Sie vom Runner-Host seeden, und die Server, die Benutzer hinzufügen. Wenn Sie also eine Zulassungsliste für andere Server bereitstellen, blockiert Claude Code auch gelieferte Connectoren. Um Connectoren neben einer URL-basierten Zulassungsliste verfügbar zu halten, fügen Sie Einträge hinzu, die den Anthropic-Proxy-Pfaden für gelieferte Connectoren entsprechen:
https://api.anthropic.com/v2/ccr-sessions/*https://api.anthropic.com/v1/code/sessions/*https://api.anthropic.com/v1/code/mcp/*
Einige Sitzungen zählen nicht als untätig
Eine Sitzung, die einen Hintergrund-Task hält, der niemals fertig wird, zählt nicht als untätig, daher wird--release-idle-session-min diese Sitzung nicht freigeben. Eine Sitzung, die auf eine Genehmigung wartet, die von innerhalb eines laufenden Tool-Aufrufs angefordert wird, zählt auch nicht als untätig. Setzen Sie immer --kill-session-after-min daneben als harten Backstop, damit keine Sitzung einen Slot unbegrenzt halten kann.
--kill-session-after-min ist ein Backstop für Runaway-Sitzungen. Auf einem Runner mit v2.1.260 oder später wird eine Sitzung, die das Limit erreicht, nicht sofort beendet. Der Runner gibt ihr ein Kulanzfenster, standardmäßig 15 Minuten, das Sie mit SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS ändern können:
- Wenn die Sitzung auf ihren Benutzer wartet, gibt der Runner sie frei. Wenn ihr Zug beendet ist und sie hält nur Hintergrund-Tasks, wartet der Runner bis zu 60 Sekunden, damit diese Tasks fertig werden, und gibt sie dann frei. Die Sitzung wird fortgesetzt, wenn ihr Benutzer ihre nächste Nachricht sendet.
- Wenn ein Zug noch läuft, wartet der Runner darauf, dass der Zug fertig wird, oder dass die Sitzung das nächste Mal auf ihren Benutzer wartet, und gibt sie dann frei.
- Wenn die Sitzung noch auf dem Runner ist, wenn das Kulanzfenster endet, beendet der Runner sie, und jede laufende Zug-Arbeit geht verloren. Ein Zug, der auf eine Genehmigung wartet, die von innerhalb eines laufenden Tool-Aufrufs angefordert wird, ist eine Möglichkeit, wie eine Sitzung das Fenster überlebt.
--kill-session-after-min 480 für 8 Stunden. Um Slots aus Gesprächen freizugeben, die untätig werden, verwenden Sie stattdessen --release-idle-session-min.
Zusätzliche Einschränkungen
- Fortgesetzte Sitzungen verlieren nicht gepushte Arbeit: Ein frischer Runner klont das Repository erneut von seinem Start-Branch, daher ist Arbeit, die die Sitzung nicht gepusht hat, verloren.
- Um committete Arbeit zu behalten: Setzen Sie
--push-outcome-on-releaseauf jedem Runner in der Umgebung, da ein Runner ohne das Flag die Sitzung von ihrem Start-Branch aus fortsetzt. Ein Runner mit dem Flag führt vor der Freigabe einen Best-Effort-Push der Ergebnis-Branches der Sitzung durch, und die fortgesetzte Sitzung startet von diesen Commits. Der Push verwendet die eigenen Git-Anmeldedaten des Runner-Hosts, auch auf einem Runner, der von Anthropic verwaltetes Git verwendet. - Mit einem
checkout-Hook: Repositorys, die über einencheckout-Lifecycle-Hook ausgecheckt werden, werden nicht gepusht. Sichern Sie diese stattdessen über denpost-session-Hook. - Bevor Sie das Flag aktivieren: Beschränken Sie, wer zu
claude/*-Refs auf dem Quell-Remote pushen kann. Beim Fortsetzen ruft der Runner den zuvor gepushten Branch ab, ohne zu überprüfen, wer ihn gepusht hat. - Nicht committete Änderungen gehen weiterhin verloren: Wie Sie Claude per Prompt anweisen, nach Abschluss seiner Antwort zu committen und zu pushen, erfahren Sie unter Sitzungen zum Pushen ihrer Arbeit auffordern
- Um committete Arbeit zu behalten: Setzen Sie
- Ein durch einen verlorenen Runner abgebrochener Befehl kann erneut ausgeführt werden: Wenn die Sitzung auf einem anderen Runner fortgesetzt wird, sieht Claude den unterbrochenen Tool-Aufruf mit einem Ergebnis, das besagt, dass sein Ausgang unbekannt ist.
- Ein während der Sitzung hinzugefügtes Repository kann beim Klonen fehlschlagen: Claude klont es mit
git cloneüber HTTPS. Auf einem Runner ohne--use-anthropic-git-proxyschlägt das Klonen mit einem Git-Authentifizierungsfehler fehl, wenn nichts auf dem Host das Repository lesen kann. Wählen Sie nach Möglichkeit jedes Repository, das die Sitzung benötigt, bereits beim Erstellen aus. - Einige Connectoren erscheinen nicht in selbstgehosteten Sitzungen: Ein Connector, den Sie noch nicht in claude.ai Settings verbunden haben, wird nicht in einer selbstgehosteten Sitzung aufgelistet, und die Sitzung wird Sie nicht auffordern, ihn zu verbinden. Verbinden Sie ihn zuerst in Settings, dann starten Sie eine frische Sitzung. Das Hinzufügen eines Connectors zu einer bereits laufenden Sitzung macht seine Tools auch nicht für Claude verfügbar; starten Sie eine frische Sitzung, um einen neu hinzugefügten Connector aufzugreifen.
- Wenn jemand eine Sitzung archiviert oder löscht oder ihren Runner über das Menü der Sitzung freigibt: Verlassen Sie sich nicht auf den Push durch
--push-outcome-on-release. Um Commits in diesen Fällen zu sichern, pushen SieHEADaus einempost-session-Hook in einen Rettungs-Branch. Wenn Sie vom dortigen Beispiel ausgehen, sorgen Sie dafür, dass es auch dann pusht, wenn nichts uncommittet ist, da es nur nach einem Snapshot-Commit pusht.
Melden Sie ein Problem
Für Probleme mit selbstgehosteten Umgebungen kontaktieren Sie Ihr Anthropic-Account-Team.Fehlerbehebung
Für geführte Diagnose führen Sie den Doctor-Subcommand auf dem Runner-Host aus. Der Doctor-Subcommand startet eine interaktive Claude Code-Sitzung mit den Logs und dem Zustand des Runners angehängt. Melden Sie sich zuerst mitclaude auth login auf diesem Host an, daher kann die Sitzung Ihre Umgebung, ihre Runner und ihre in die Warteschlange eingereihten Sitzungen abfragen. Ohne diese Anmeldung, zum Beispiel wenn der Host mit einem API-Schlüssel authentifiziert, ist es auf den lokalen Health-Endpunkt, Metriken und das Runner-Log begrenzt, und es liest das Log nur, wenn Sie den Runner mit --log-file gestartet haben.
-
Runner erscheint nicht in der Umgebung: Bestätigen Sie, dass der Host
api.anthropic.comüber HTTPS erreichen kann, das Umgebungsgeheimnis aktuell ist und die Host-Uhr innerhalb von fünf Minuten der echten Zeit liegt; größere Abweichung verursacht, dass die Authentifizierung fehlschlägt. Der Runner protokolliert[runner:fatal]mit dem Ablehnungsgrund bei Auth-Fehler. -
Runner beendet sich beim Start mit
cannot create or write to base directory: Der Runner kann--base-dirnicht erstellen oder schreiben, das standardmäßig auf/workspaceist. Beheben Sie das Verzeichnis’s Eigentum oder zeigen Sie--base-dirauf einen beschreibbaren Pfad, wie in Halten Sie das Basis-Verzeichnis und die Kapazität über Runner identisch beschrieben. Wenn der Runner stattdessen[runner:fatal]protokolliert, dass die Basis-Verzeichnis-Überprüfung abgelaufen ist, ist das Verzeichnis auf einem hängenden NFS- oder CSI-Mount. Überprüfen Sie die Mount-Gesundheit anstatt der Berechtigungen. Der Runner druckt beide dieser Startup-Fehler zu stderr, bevor er--log-fileöffnet, daher suchen Sie nach ihnen im Terminal oder Ihren Plattform-Container-Logs anstatt der Log-Datei. Vor v2.1.225 überprüfte der Runner das Basis-Verzeichnis nicht beim Start, und diese Fehlkonfiguration schlug Sitzungen nach der Aufnahme fehl. -
Runner beendet sich beim Start mit
RegisterRunner failed:und einem TLS-Zertifikatsfehler: Der Fehler kann zum Beispielself signed certificate in certificate chainlauten. Der Runner vertraut der Zertifizierungsstelle (CA) hinter dem empfangenen Zertifikat nicht, wie es hinter einem TLS-inspizierenden Proxy vorkommt. Setzen SieNODE_EXTRA_CA_CERTSin der Umgebung des Runners auf eine PEM-Datei mit der Root-CA des Proxys. Für Sitzungen müssen Sie die Variable nicht erneut setzen, da diese sie erben. Git liest sie nicht: Für Clones über diesen Proxy setzen Sie zusätzlichGIT_SSL_CAINFO. -
Ihr Startskript gibt einen Schreibfehler mit
Resource temporarily unavailableaus und beendet sich: Ihr Skript teilt seine stdout oder stderr mit dem Prozessclaude self-hosted-runneroder Orchestrator, den es startet, und dieser Prozess hat die gemeinsame Pipe bzw. den gemeinsamen Socket in den nicht blockierenden Modus umgeschaltet. Wenn die Pipe voll ist, schlägt ein Schreibvorgang Ihres Skripts mit diesem Betriebssystemfehler fehl, anstatt zu warten, und unterset -ebeendet sich das Skript. Um den Fehler zu vermeiden, leiten Sie die Ausgabe des Runners oder Orchestrators in eine Datei um, die der Benutzer Ihres Skripts erstellen kann. Hängen Sie>> "$HOME/claude-runner.log" 2>&1an den Befehl an, der ihn startet, und zwar vor einem eventuellen&, das ihn in den Hintergrund schickt:Die eigene Ausgabe Ihres Skripts geht weiterhin dorthin, wohin sie vorher ging, während das, was der Runner nach stdout und stderr schreibt, einschließlich seiner Startfehler, in diese Datei geht. Verwenden Sie diese Shell-Umleitung statt--log-fileallein, das das Log in eine Datei spiegelt, während der Runner weiterhin nach stdout und stderr schreibt. Wenn Sie bereits--log-fileübergeben, behalten Sie es ebenfalls bei, denn die Umleitung ändert nicht, was diese Datei empfängt. -
Orchestrator protokolliert
poll failed:mit einem TLS-Zertifikatsfehler und versucht es fortlaufend erneut: Der Orchestrator vertraut der CA hinter dem empfangenen Zertifikat nicht, wie es hinter einem TLS-inspizierenden Proxy vorkommt. Setzen SieNODE_EXTRA_CA_CERTSin der Umgebung des Orchestrators auf eine PEM-Datei mit der Root-CA des Proxys. Setzen Sie die Variable auch für die Runner, die Ihrspawn-runner-Hook startet. Zum Beispiel kann eine Zeile mitpoll failed: self signed certificate in certificate chain — retrying in 1senden, wobei zwischen dem Doppelpunkt und dem Gedankenstrich die Worte der TLS-Bibliothek stehen. Um die Behebung zu bestätigen, prüfen Sie, dassconnectedim Body von/healthzdes Orchestratorstrueist. -
Sitzungen bleiben in der Warteschlange: Jeder Online-Runner kann auf einen anderen Owner gesperrt sein. Überprüfen Sie die
claude_code_self_hosted_runner_locked_account-Metrik jedes Runners oder daslocked_account-Feld seiner[runner:health]-Log-Zeile, um zu sehen, wer sie hält. Beide zeigen die Email des Owners nur, nachdem der Runner ein Sitzungs-Token mit einemact.email-Claim ausgestellt bekommen hat, das die Sitzungen eines Claude Tag-Agenten niemals tun. Ohne den Claim sendet der Runner keinelocked_account-Serie aus und protokolliertlocked_account=yes, was Ihnen sagt, dass der Runner gesperrt ist, aber nicht auf welchen Owner. Fügen Sie Replicas hinzu, oder warten Sie, bis ein bestehender Runner drainiert und neu startet. Wenn die Umgebung On-Demand-Runner verwendet, überprüfen Sie stattdessen den Orchestrator; siehe On-Demand-Runner. -
Sitzungen schlagen sofort nach der Aufnahme fehl: Öffnen Sie die Sitzung in claude.ai/code, um den Fehler zu sehen. Wenn der Fehler zeigt, dass Git sich nicht authentifizieren konnte, überprüfen Sie die Git-Anmeldedaten des Runners. Bei einem Runner, der mit
--use-anthropic-git-proxygestartet wurde, siehe Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten. Ein nicht beschreibbares Basis-Verzeichnis stoppt den Runner beim Start, anstatt Sitzungen fehlschlagen zu lassen. Siehe den Runner beendet sich beim Start mitcannot create or write to base directory-Eintrag in dieser Liste. -
Eine Sitzung wird aufgenommen, aber Claude beantwortet ihre erste Nachricht nie: Wenn Ihre Runner
api.anthropic.comüber einen Proxy erreichen, konfigurieren Sie ihn so, dass er die/worker/events/stream-Antwort der Sitzung so durchreicht, wie sie eintrifft. Das Erhöhen der Timeouts des Runners hilft nicht. Um die Ursache im Log des Runners zu bestätigen, siehe Eine Sitzung wird aufgenommen, aber Claude beantwortet ihre erste Nachricht nie. -
Sitzungen starten nicht auf einem Runner, der
--use-anthropic-git-proxygesetzt hat: Suchen Sie im Log des Runners nachaccess denied by the git proxyoder nach einem Git-Fehler, der eineapi.anthropic.com-Adresse mit/git_proxy/nennt. Um festzustellen, ob Anthropic die Sitzung bedient hat, und die Ursache zu beheben, siehe Wenn Sitzungen auf einem Runner mit dem Git-Proxy nicht starten. -
Sitzungen können das Netzwerk nicht durch einen authentifizierenden Egress-Proxy erreichen: Wenn die Quelle, die Sie mit
--proxy-authorization-commandoder--proxy-authorization-filesetzen, fehlschlägt, nach 30 Sekunden abläuft oder einen leeren Wert ergibt, antwortet der Runner dieser Verbindung502 Bad Gatewayund protokolliert warum. Der Runner redigiert das Kommando’s stderr in diesem Log und protokolliert niemals den Header-Wert. Mit--proxy-authorization-commandführen Sie das Kommando selbst auf dem Host aus, um zu bestätigen, dass es den ganzen Header-Wert auf stdout druckt. Wenn der Runner stattdessen beim Start mitcould not start the proxy-authorization listenerbeendet wird, konnte er seinen Loopback-Listener nicht öffnen. -
Runner protokolliert
Poll failed-Zeilen, dierejecting the malformed poll responseenthalten: Der Runner erhielt eine Work-Poll-Antwort, deren Body nicht das erwartete JSON der Warteschlange ist. Eine mögliche Ursache ist ein abfangender Proxy oder ein Captive Portal, der mit seiner eigenen Seite antwortet. Wenn sich der Runner über einen Proxy verbindet, konfigurieren Sie den Proxy so, dass er Antworten vonapi.anthropic.comunverändert durchlässt. Der Runner lehnt die fehlerhafte Antwort ab, zählt sie unter dertransport-Art derclaude_code_self_hosted_runner_poll_errors_total-Metrik und versucht es gemäß dem Zeitplan für fehlgeschlagene Polls, der in Sitzungs-Lebenszyklus beschrieben ist, erneut. Der Runner bedient weiterhin seine Live-Sitzungen. Vor v2.1.246 las der Runner eine solche Antwort als eine leere Warteschlange, die seine Live-Sitzungen beenden oder ihn zum Exit bringen könnte. -
Eine Sitzung schlägt mit
no longer exists on the remoteodercouldn't find remote reffehl: Der Runner wertet dascouldn't find remote refvon Git als gelöschten Branch. Der Branch kann trotzdem noch existieren. Suchen Sie ihn auf Ihrem Git-Host unter genau dem Namen aus der Meldung, und prüfen Sie dann jede zutreffende Ursache:- Der Branch ist weg: Stellen Sie ihn wieder her, wie die Meldung es verlangt.
- Der Branch existiert und Sie administrieren den Runner nicht: Senden Sie dem Administrator des Runners die vollständige Meldung und teilen Sie ihm mit, dass der Branch existiert.
- Der Branch existiert und der Runner hat einen
checkout-Hook: Ein Git-Befehl in Ihrem Hook kanncouldn't find remote refnach stderr ausgeben, bevor der Hook mit einem Exit-Code ungleich null endet. Finden Sie diesen Befehl, und korrigieren Sie die Ref, die er anfordert, oder das Remote, von dem er abruft. Der Runner übergibt Ihrem Hook die von der Sitzung angeforderte Revision alsCLAUDE_RUNNER_REPO_REF. - Der Branch existiert und der Runner hat keinen
checkout-Hook: Der Runner ruft den Branch selbst ab. Wenn ein--git-host-rewritefür das Repository gilt, prüfen Sie, ob der Host, auf den umgeschrieben wird, den Branch unter demselben Namen hat, und pushen Sie den Branch dorthin, falls nicht. - Der Branch existiert und der Runner ist älter als v2.1.301: Aktualisieren Sie den Runner wie in Version festlegen beschrieben, damit ein anderer Fehler seine eigene Fehlermeldung anzeigt. Vor v2.1.301 wurden auch andere Fehler mit
couldn't find remote refin ihrer Fehlerausgabe als gelöschter Branch gemeldet.
-
Claude Tag postet seine Antwort in Slack manchmal nicht: Die Antwort-Erinnerung ist ein Hook, den die Control Plane bereitstellt. Prüfen Sie mit
claude --version, ob der Runner Claude Code v2.1.229 oder neuer ist, da ältere Runner bereitgestellte Hooks ignorieren; prüfen Sie, obpython3 --versionim Runner-Image erfolgreich ausgeführt wird, da die Hookspython3ausführen; und prüfen Sie, dass keine Einstellungsdatei Hooks ausschaltet, sei esdisableAllHooksinmanaged-settings.json, in der~/.claude/settings.jsondes Runner-Benutzers oder in der.claude/settings.jsonoder.claude/settings.local.jsondes Repositorys, oderallowManagedHooksOnlyoder einestrictPluginOnlyCustomizationin den verwalteten Einstellungen, die Hooks abdeckt. -
Eine Sitzung startet ohne eines ihrer Repositories: Auf einem Runner ohne
checkoutHook kann der Git-Host den Zugriffsprüfung des Runners für ein Repository, das die Sitzung nur liest, ablehnen. Der Runner überspringt dann dieses Repository, protokolliert eine[runner:warn] could not access context source-Zeile, die die Ablehnung benennt, und startet die Sitzung auf den verbleibenden. Der Runner überspringt nur eine klare Ablehnung: Der Host antwortet, dass das Repository nicht gefunden wurde, Git findet keine Anmeldedaten für den Host, oder die Authentifizierung schlägt fehl. Ein Netzwerkfehler, ein Timeout oder ein HTTP403schlägt immer noch den Sitzungsstart fehl, ebenso wie eine Ablehnung für ein Repository, zu dem die Sitzung Ergebnisse pusht. Der Runner schlägt immer noch eine Sitzung fehl, die das Überspringen ohne Repository überhaupt verlassen würde. Mit--use-anthropic-git-proxyüberspringt der Runner nur ein Repository, das der Git-Proxy selbst ablehnt. Die Zugriffsprüfung läuft jedes Mal erneut, wenn die Sitzung auf einem Runner startet, daher sobald die Git-Identität des Runners Lesezugriff hat, klont der nächste Start das Repository. Vor v2.1.274 schlugen jede dieser Ablehnungen den Sitzungsstart fehl. -
Eine Sitzung startet nicht mit
This runner couldn't read: Der Runner hat den Git-Host mit seinen Git-Anmeldedaten nach einem Repository gefragt und die Antwort erhalten, dass es nicht gefunden wurde. Das Repository existiert nicht, oder diese Anmeldedaten können das Repository nicht erreichen.- Wenn Sie den Runner administrieren: Gewähren Sie seinen Git-Anmeldedaten Lesezugriff auf das Repository, und starten Sie dann eine neue Sitzung.
- Wenn Sie die Sitzung gestartet haben: Wenn das Repository nicht existiert, starten Sie eine neue Sitzung mit dem richtigen Repository. Wenn der Runner das Repository nicht erreichen kann, bitten Sie den Administrator des Runners, Zugriff zu gewähren, und starten Sie dann eine neue Sitzung.
-
Sitzungen brauchen Minuten zum Starten oder Fortsetzen: Eine Ursache ist ein frischer Clone. In einer Flotte, die jeden Runner auf einer leeren Festplatte startet, ohne
checkout-Hook, klont der Runner die Repositorys der Sitzung neu, bevor er Claude Code startet. Eine Sitzung, die auf einer leeren Festplatte fortgesetzt wird, wartet erneut auf denselben Clone. Um den frischen Clone zu überspringen, stellen Sie einen vorgewärmten Checkout bereit. Wenn Sie bereits einen bereitstellen, bestätigen Sie, dass der Runner ihn verwendet. Wo der Runner den Clone selbst erstellt und sich nach einer Sitzung beendet, senken SieCLAUDE_RUNNER_FETCH_DEPTHvon seinem Standardwert von 50 Commits, um weniger Verlauf abzurufen. Wenn Sie einen Hook verwenden, läuft er anstelle des Clones des Runners, prüfen Sie also stattdessen, was Ihr Hook tut. Beobachten Sie dieclaude_code_self_hosted_runner_session_init_duration_seconds-Metrik, um zu sehen, wie lange Starts dauern. -
Turns schlagen mit einem 401 fehl: Wenn ein Turn mit einem 401 oder 403 von der Anthropic API endet, ruft der Runner ein frisches
CLAUDE_CODE_OAUTH_TOKENvon Anthropic ab und übergibt es der Sitzung. Der fehlgeschlagene Turn wird nicht erneut versucht. Dieses Token ist kurzlebig, und der Runner rotiert es über die stdin der Sitzung. Wenn ein Abruf fehlschlägt, protokolliert der Runner eineinference_token refresh failed-Zeile, die sagt, wann er erneut versuchen wird, und er versucht es weiterhin erneut, solange die Sitzung läuft. Wenn jeder Aufruf etwa 30 Minuten in eine Sitzung hinein fehlschlägt, hat ein Wrapper-Skript wahrscheinlich die Sitzungs-stdin unterbrochen, daher können Token-Rotationen sie nicht erreichen; siehe Halten Sie stdin und Dateideskriptor 3 angehängt. Vor v2.1.274 stoppte der Runner das erneute Versuchen eines fehlgeschlagenen Abrufs nach einigen Versuchen und wartete auf den nächsten geplanten. Ein fehlgeschlagener Turn löste keinen Abruf aus, daher schlugen alle Turns mit einem 401 fehl, bis zum nächsten geplanten Abruf. -
Ein Turn schlägt in claude.ai/code mit
This model needs a newer version of Claude Codefehl: Die Claude Code-Version, mit der Ihre Runner Sitzungen starten, ist älter, als das Modell der Sitzung erfordert, daher lehnt die API die Anfrage ab. Aktualisieren Sie die Runner auf die Version, die die Meldung verlangt, oder auf eine neuere, wie in Version festlegen beschrieben. Bis dahin können Benutzer in der Sitzung ein anderes Modell auswählen. -
Pod wird Mid-Drain getötet: Erhöhen Sie
terminationGracePeriodSecondsauf mindestens den Wert, den der Runner beim Start protokolliert. Siehe Shutdown-Timing.
[runner:fatal]-Zeilen, nach stdout und Debug-Ausgabe nach stderr, alles als Plain-Text-Zeilen anstatt JSON. Die Fehler beim Basis-Verzeichnis, die in den Fehlerbehebungs-Einträgen oben beschrieben sind, werden vor diesem Punkt nach stderr ausgegeben. Erfassen Sie beide Streams mit --log-file, was auch self-hosted-runner doctor ermöglicht, sie mitzulesen, oder mit der Log-Sammlung Ihrer Plattform.
Jeder Sitzungs-Kind-Prozess schreibt ein separates Debug-Log. Bei Fehler bewahrt der Runner das Log’s Tail neben der Sitzung in claude.ai/code. Sofern Sie den Runner nicht mit --remove-session-state gestartet haben, behält er auch das Log einer fehlgeschlagenen Sitzung auf der Festplatte und druckt seinen Pfad im Runner-Log.
Wenn der Runner beendet wird
Starten Sie einen On-Demand-Runner nicht neu, da seine Arbeitsorder einmalig ist. Ein Runner, der sich direkt nach dem Start beendet, benötigt eine andere Behandlung als einer, der sich aus einem anderen Grund beendet.- Ein normaler Exit: Der Runner hat seine Sitzungen beendet und drainiert, seine Ruhezeit erreicht oder wurde angewiesen zu stoppen. Starten Sie ihn neu, damit die Umgebung wieder Kapazität hat. Runner-Lebenszyklus beschreibt diese Exits.
- Ein fehlgeschlagener Start: Der Runner kann nicht mit der Konfiguration oder dem Host starten, der ihm gegeben wurde, daher beendet er sich Sekunden nach dem Start, und er beendet sich jedes Mal auf die gleiche Weise, wenn Sie ihn neu starten. Ein schnellerer Neustart hilft nicht. Jemand muss seine Ausgabe lesen und die Ursache beheben.
- Verlorener Kontakt: Ein Runner, der Anthropic länger als seinen Lease nicht erreichen kann, zum Beispiel während sein Host schläft, kann aus der Umgebung entfernt werden. Wenn sich ein entfernter Runner wieder verbindet, beendet er sich. Sein Log kann eine
[runner:fatal]-Zeile zeigen, dierunner record gone server-sideoder, nach einem längeren Ausfall,poll auth failedenthält. Der Runner registriert sich nicht von selbst erneut, starten Sie ihn also neu.
Erkennen Sie einen fehlgeschlagenen Start
Wenn der Runner nicht starten kann, druckt er eine Zeile, die sagt warum, und dann beendet er sich. Für die meisten Ursachen enthält die Zeile[runner:fatal]. Für einige Ursachen beginnt die Zeile stattdessen mit error:, einschließlich wenn der Runner seine Flags nicht parsen kann, das Umgebungsgeheimnis nicht lesen kann oder das Basis-Verzeichnis nicht erstellen oder schreiben kann. Die nächste Zeile zeigt dann auf --help.
Die meisten Log-Zeilen beginnen mit einem Zeitstempel und [self-hosted-runner], das die Beispiel unten auslässt. Zum Beispiel druckt ein Runner, der mit dem Anthropic Git-Proxy gestartet wurde und eine Kapazität über eins hat, eine Zeile wie diese:
--log-file setzen. Der Runner druckt eine error:-Zeile, bevor er die Log-Datei öffnet, daher suchen Sie nach ihr im Terminal oder Ihren Container-Logs, wie Fehlerbehebung notiert.
Diese helfen auch, wenn Sie einen fehlgeschlagenen Start lesen:
- Keine Zeile überhaupt: Ein Runner, den der Host tötet, druckt keine. Wenn die Ausgabe mit keiner
[runner:fatal]-Zeile und keinererror:-Zeile endet, überprüfen Sie, ob der Host oder Ihr Orchestrator den Prozess gestoppt hat, zum Beispiel für das Überschreiten eines Speicherlimits. - Der Exit-Code: Der Runner setzt keinen Exit-Code für Fehler beiseite, die bei jedem Start wiederholt werden. Er beendet sich mit dem gleichen Code für einen Konfigurationsfehler, wie eine nicht unterstützte Kombination von Flags, und für einen Fehler, der sich selbst löschen kann, wie die API, die durch die eigenen Wiederholungen des Runners unerreichbar bleibt. Basieren Sie die Entscheidung, länger zu warten, darauf, wie schnell der Runner beendet wurde, und lesen Sie die Ausgabe des Runners, um zu erfahren warum.
- Eine Umgebung, die gesund aussieht: Einige Startup-Schritte laufen, nachdem sich der Runner bei Ihrer Umgebung registriert hat, wie
--configure-gitund die Credential-Einrichtung des Anthropic Git-Proxy. Wenn einer dieser Schritte fehlschlägt, kann die Umgebung diesen Runner für ein paar Minuten nach dem Prozessende weiterhin auflisten, und die Cloud-Umgebungen-Seite kann Gesund lesen, während kein Runner Arbeit aufnimmt. Wenn Sitzungen in einer Umgebung, die gesund aussieht, in der Warteschlange bleiben, überprüfen Sie, ob Ihr Supervisor den Runner neu startet.
Neustart mit einer wachsenden Wartezeit
Wie Sie eine wachsende Wartezeit bekommen, hängt von Ihrem Supervisor ab.-
Kubernetes: Die Deployment auf dieser Seite benötigt keine Änderung. Nachdem ein Container beendet wird, wartet das kubelet standardmäßig, bevor es den Container neu startet, und die Wartezeit wächst bei jedem Neustart bis zu einer Obergrenze. Die Wartezeit startet von vorne, sobald der Container eine Weile ohne Beendigung läuft.
Das kubelet wendet die gleiche Wartezeit nach einem normalen Exit an, wenn der Container nur kurz lief. Ein Runner, der oft drainiert, kann daher auch den
CrashLoopBackOff-Status zeigen, daher lesen Sie die Ausgabe, bevor Sie schließen, dass der Runner nicht starten kann. Der Befehl unten liest die letzte Lauf-Ausgabe von einem Pod der Deployment:Wenn der letzte Lauf ein fehlgeschlagener Start war, ist die[runner:fatal]- odererror:-Zeile unter den letzten Zeilen der Ausgabe. Um die letzte Lauf eines anderen Pods zu lesen, benennen Sie diesen Pod anstelle vondeploy/claude-runner. -
Docker und Docker Compose: Die Compose-Rezept auf dieser Seite benötigt keine Änderung. Mit
restart: alwayswartet Docker länger vor jedem Neustart eines Containers, der weiterhin beendet wird, bis zu einer Obergrenze. Ersetzen Sie<container>mit dem Namen des Containers im Befehl unten, der liest, wie oft Docker den Container neu gestartet hat:Der Befehl druckt eine Zahl. Eine Zahl, die weiterhin klettert, bedeutet Docker startet den Runner weiterhin neu. -
Eine systemd-Unit: Standardmäßig wartet systemd die gleiche
RestartSecvor jedem Neustart und verlängert sie nicht, daher startet eine Unit mitRestart=alwayseinen Runner, der nicht starten kann, in diesem gleichen Intervall jedes Mal neu. Wenn die Starts schnell genug kommen, um die Start-Rate-Grenze der Unit zu erreichen, fünf Starts in 10 Sekunden standardmäßig, stoppt systemd das Neustarten der Unit. Die Unit bleibt gestoppt, bis jemand sie wieder startet, was systemd erlaubt, sobald das Intervall der Rate-Grenze vergangen ist oder nachsystemctl reset-failed. WeilRestartSecauf jeden Neustart angewendet wird, verzögert ein längerer Wert auch den Neustart nach einem normalen Exit. Wählen Sie einen Wert, der die beiden ausgleicht, und warnen Sie bei der Neustart-Zählung der Unit. - Eine Shell-Schleife oder Ihr eigener Supervisor: Wenden Sie die gleiche Regel selbst an. Beginnen Sie mit einer Wartezeit von fünf Sekunden. Nach jedem Lauf, der innerhalb einer Minute endete, verdoppeln Sie die Wartezeit für den nächsten Neustart, bis zu fünf Minuten. Nach einem Lauf, der eine Minute oder länger dauerte, gehen Sie zurück zu fünf Sekunden.
Überprüfen Sie, warum der Runner weiterhin beendet wird
Wenn der Runner mehrmals hintereinander direkt nach dem Start beendet wurde, stoppen Sie und überprüfen Sie diese, bevor Sie ihn erneut neu starten.- Die letzte
[runner:fatal]- odererror:-Zeile: Sie sagt, warum der Runner gestoppt wurde. Fehlerbehebung listet die häufigen Ursachen auf. - Die Kombination von Flags: Der Anthropic Git-Proxy erfordert
--capacity 1. Die Rezepte auf dieser Seite verwenden eine höhere Kapazität, daher senken Sie sie, wenn Sie den Proxy zu einem von ihnen hinzufügen. - Was die Umgebung des Service erreichen kann: Wenn der Runner von Hand startet und unter Ihrem Supervisor fehlschlägt, vergleichen Sie den Benutzer, das Home-Verzeichnis, den
PATHund das Speicherlimit.--configure-gitund der Anthropic Git-Proxy benötigen Git auf demPATHund ein beschreibbares~/.gitconfig. - Das Umgebungsgeheimnis: Wenn Sie das Geheimnis widerrufen oder falsch eingegeben haben, druckt der Runner eine Zeile, die
RegisterRunner auth failedenthält. - Die Aktivitäts-Registerkarte der Umgebung: Öffnen Sie die Umgebung und wählen Sie Aktivität. Wenn neue Runner dort weiterhin erscheinen und keiner Arbeit aufnimmt, startet Ihr Supervisor den Runner neu.
Eine Sitzung wird aufgenommen, aber Claude beantwortet ihre erste Nachricht nie
Wenn ein Runner eine Sitzung aufnimmt, Claude aber nie auf die erste Nachricht antwortet, und Ihre Runnerapi.anthropic.com über einen Proxy erreichen, kann der Proxy die Ursache sein. Anthropic sendet einer Sitzung ihre Nachrichten über eine einzige Streaming-Antwort, die offen bleibt. Wenn Ihr Proxy sie puffert oder beendet, bevor er etwas weitergibt, kommt die erste Nachricht nie an. Andere Anfragen der Sitzung sind weiterhin erfolgreich.
Um das zu beheben, ändern Sie, wie der Proxy diese Anfrage behandelt:
- Puffern Sie die Antwort nicht: Reichen Sie sie so durch, wie sie eintrifft. Ihr Content-Type ist
text/event-stream. - Lassen Sie die Antwort offen: Sie kann bis zu einer Stunde offen bleiben. Wenn der Proxy einen Leerlauf-Timeout hat, halten Sie ihn deutlich über 15 Sekunden, da Anthropic standardmäßig mindestens so oft ein Keep-alive sendet.
Bestätigen Sie die Ursache im Log des Runners
Diese Schritte gelten für Runner mit Claude Code v2.1.287 oder neuer auf der Standardstufe--log-level info. Ältere Runner protokollieren diese Zeilen später oder gar nicht.
- Warten Sie, bis
--startup-timeout-minabgelaufen ist, standardmäßig 15 Minuten. Der Runner stoppt dann die Sitzung und protokolliert eine Zeile, dieno child output forenthält und mit— releasingendet. - Durchsuchen Sie das Log des Runners nach
SDKStartup: SSE. Diese Zeilen folgen auf einefinished: interrupted-Zeile, einige Zeilen nach der aus Schritt 1. Die meisten haben keinen Zeitstempel, daher zeigt ein Log-Collector sie möglicherweise an anderer Stelle an. - Suchen Sie die Zeile in dieser Tabelle:
Verhindern Sie, dass die Sitzung es erneut versucht
Die Sitzung hält die Nachricht ausstehend, und ein Runner, der den Owner der Sitzung bedienen kann, nimmt die Sitzung erneut auf. Bis Sie den Proxy ändern, wartet die Sitzung jedes Mal auf die gleiche Weise. Um das zu beenden, archivieren Sie die Sitzung in claude.ai/code.Was kommt als nächstes
- Passen Sie Sitzungen an: Wrapper-Skripte, Lebenszyklus-Hooks, On-Demand-Runner, MCP-Server und Berechtigungen
- Testen Sie End-to-End: Überprüfen Sie ein neues Runner-Image von CI, bevor Sie es fördern
- Referenz: Jedes CLI-Flag, jede Umgebungsvariable und jede Metrik