Skip to main content
Gli ambienti self-hosted sono in beta pubblica sui piani Team ed Enterprise; un Owner li abilita attivando Allow self-hosted environments nella pagina di amministrazione Cloud environments. Questa pagina è il riferimento per flag e metriche; consultare la guida rapida per la configurazione e Deploy to production per le ricette della flotta.
Questa pagina è il riferimento per i due processi che eseguite in un ambiente self-hosted: il runner, che esegue le sessioni cloud di Claude Code sui vostri host, e l’orchestrator di autoscaling opzionale, che avvia i runner mentre le sessioni si accodano. Ognuno ha la propria tabella di flag. Entrambi vengono eseguiti su host Linux o macOS, per i quali i valori predefiniti come /workspace e ~/.claude sono presupposti. Eseguite claude self-hosted-runner --help per l’elenco autorevole sulla vostra versione installata. Le serie di metriche e alcuni campi API utilizzano ancora pool per quello che queste pagine chiamano un ambiente; entrambi i termini denominano la stessa cosa. L’ID dell’ambiente è il campo pool_id, con la forma ccpool_...: ovunque queste pagine mostrino un identificatore pool, esso denomina l’ambiente. I flag CLI e le variabili d’ambiente lo scrivono come environment, come in --environment-secret-file; i nomi deprecati pool continuano a funzionare, come la riga --environment-secret-file descrive.

Flag CLI del runner

La maggior parte dei flag ha una variabile d’ambiente corrispondente. Quando entrambi sono impostati, il flag ha la precedenza. I flag di durata accettano minuti o secondi sulla CLI, ma la variabile d’ambiente associata è sempre in millisecondi, indicata dal suffisso _MS, e la colonna Default mostra l’unità del flag: --exit-if-unused-min 10 è equivalente a SELF_HOSTED_RUNNER_IDLE_SHUTDOWN_MS=600000, e un valore Helm come SELF_HOSTED_RUNNER_STARTUP_TIMEOUT_MS: "15" significa 15 millisecondi, non il valore predefinito di 15 minuti. La maggior parte dei flag di durata ha un massimo, scelto per mantenere ogni timeout entro il limite del timer a 32 bit del runtime di circa 24,85 giorni. I flag --*-min hanno un limite di 10080 minuti, 7 giorni; --drain-grace-sec a 604800 secondi, anche 7 giorni; e --drain-wait-sec a 86400 secondi, 24 ore. --session-stop-grace-sec e --post-session-hook-timeout-sec non hanno limiti. Superare un limite si comporta diversamente per superficie:
  • Flag: l’avvio fallisce con un errore.
  • Variabile d’ambiente: il runner fissa il valore al limite del timer piuttosto che rifiutarlo.

Timeout di avvio della sessione

Se una sessione ha perso il suo slot durante un turno come /code-review, aggiorna il runner e il binario figlio alla v2.1.309 o successiva. Dalla v2.1.299 alla v2.1.308, il runner rilasciava una sessione, anche a metà turno, una volta trascorso il timeout di avvio senza un messaggio user o assistant. Con --startup-timeout-min <n>, il runner rilascia lo slot di una sessione quando il suo figlio non si è inizializzato entro <n> minuti dopo la clonazione. Durante un turno che inizia prima che il figlio si inizializzi, la sessione mantiene il suo slot finché non trascorrono <n> minuti senza alcuna riga sul canale di attività del figlio. Una volta che il figlio si inizializza, il runner azzera quel conteggio e il rilascio è governato da --release-idle-session-min. Per limitare una sessione il cui figlio è attivo ma bloccato, imposta --kill-session-after-min.

Elenchi di regole della modalità auto

--server-auto-mode-lists ti permette di decidere quali regole del classificatore della modalità auto provenienti dall’esterno del runner raggiungono le sessioni sui tuoi runner. Il control plane di Anthropic può inviare elenchi di regole con una sessione e chiedere al runner di applicarli. Alcune voci possono essere regole scritte da un amministratore della tua organizzazione. Gli elenchi sono environment, soft_deny e allow:
  • environment: una voce può far sì che il classificatore consenta di più così come di meno.
  • soft_deny: una voce blocca un’azione a meno che l’utente non l’abbia richiesta esplicitamente o non si applichi un’eccezione allow.
  • allow: le eccezioni alle voci soft_deny.
Il valore del flag sceglie quali elenchi applica il runner:
  • no-allow: il valore predefinito. Applica environment e soft_deny e trattiene allow. Una voce environment può comunque far sì che il classificatore consenta di più, quindi il valore predefinito non esclude ogni allentamento.
  • all: applica tutti e tre gli elenchi.
  • none: non ne applica nessuno. Scegli none per escludere ogni allentamento proveniente da questi elenchi. Elimina anche le restrizioni di soft_deny.
Nessuna impostazione del runner fa sì che il control plane chieda al runner di applicare gli elenchi. Quando non lo chiede, le sessioni non ricevono alcun elenco, qualunque cosa tu imposti. Per vedere cosa è successo, avvia il runner con --log-level debug. Per ogni sessione il runner registra quindi una riga contenente the server asked this runner to apply, oppure una contenente the server did not ask this runner to apply the auto mode lists it sends.

Flag CLI dell’orchestrator

Il sottocomando self-hosted-runner orchestrator, che genera runner on-demand, accetta --api-url, --environment-secret-file, --hooks-dir, --health-port e --log-level con gli stessi valori predefiniti del runner e, dove il flag del runner ne ha uno, la stessa variabile d’ambiente, tranne che --hooks-dir è obbligatorio e deve contenere un hook spawn-runner. Accetta anche i suoi flag:

Flag del connettore SCM

Il connettore SCM non è disponibile, quindi lascia i flag in questa sezione non impostati. Se imposti --scm-connector-host, la connessione non si apre e l’orchestrator continua a ritentare. I runner comunque si avviano mentre la coda delle sessioni si accumula. Il connettore è una connessione WebSocket permanente dall’orchestrator al piano di controllo di Anthropic. È progettato per consentire ai flussi pre-sessione ospitati, come il selettore di repository e il risolutore di ramo o ref, di raggiungere un host GitHub Enterprise Server che è instradabile solo dall’interno della tua rete. Vedi Requisiti di rete nella pagina GitHub Enterprise Server per sapere cosa richiedono questi flussi. Ad ogni tentativo di connessione l’orchestrator invia il suo segreto d’ambiente esistente e ritenta automaticamente con backoff esponenziale, limitato a 30 secondi più jitter.

Impostazioni solo variabili d’ambiente

Queste impostazioni del runner vengono lette solo dall’ambiente e coprono il comportamento che la maggior parte delle distribuzioni lascia al valore predefinito:

Telemetria

I figli della sessione inviano telemetria operativa ad Anthropic a meno che non la disattivi. Nessun codice o contenuto del repository viene inviato. Imposta le variabili di telemetria sul processo del runner; il runner le ri-asserisce dopo aver applicato le variabili d’ambiente fornite dal server, quindi l’impostazione dell’operatore ha sempre la precedenza. Un controllo è specifico per gli ambienti self-hosted: CLAUDE_CODE_BYOC_ENABLE_DATADOG=1 acconsente alle metriche operative di Datadog, che sono disattivate per impostazione predefinita negli ambienti self-hosted. I controlli generali di telemetria di Claude Code, DISABLE_TELEMETRY, DO_NOT_TRACK, DISABLE_ERROR_REPORTING e CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, si applicano ai figli della sessione come documentato nel riferimento delle variabili d’ambiente. DISABLE_GROWTHBOOK è correlato ma diverso: impostare DISABLE_GROWTHBOOK=1 disabilita il recupero dei flag di funzionalità, e la telemetria rimane attiva a meno che DISABLE_TELEMETRY non sia anche impostato. CLAUDE_CODE_ENABLE_TELEMETRY non è correlato: abilita l’esportazione OpenTelemetry al tuo collettore, come descritto in Monitoring, e non controlla l’analittica di Anthropic.

Endpoint di salute

Il runner serve GET /healthz sulla porta di salute configurata. La risposta è 200 OK ogni volta che il processo è attivo, qualunque stato sia il ciclo di polling, quindi un probe HTTP su questo endpoint rileva solo un processo morto. Il corpo JSON descrive lo stato attuale:
Usa last_poll_age_ms come segnale di vivacità nei probe personalizzati; un valore che cresce senza limiti indica che il ciclo di polling è bloccato. Sia last_poll_at che last_poll_age_ms sono null fino al completamento del primo polling. Il /healthz dell’orchestrator, sulla sua porta di salute, restituisce sempre 200. Il corpo porta un campo connected che segnala se il polling più recente ha avuto successo, più i conteggi della coda di spawn per stato in queue_counts. Per capire perché connected è false, leggi il campo di primo livello last_error, che ogni polling riuscito reimposta a null. Basa readiness e alerting su connected piuttosto che sul codice di stato. Quando il connettore SCM è configurato, il corpo /healthz dell’orchestrator porta anche scm_connector_connected e un oggetto scm_connector con connected, last_connected_at, last_error, reconnects e requests_forwarded. Entrambi i campi sono null quando --scm-connector-host non è impostato.

Metriche Prometheus

Ogni runner serve metriche Prometheus su GET /metrics sulla stessa porta di /healthz. Serie chiave: L’orchestrator serve le sue serie su GET /metrics sulla stessa porta del suo /healthz: Per l’autoscaling, scegli la serie che corrisponde al tuo stile di scaling e gated prima che si nutra nello scaler:
  • Scaling della profondità della coda: alimenta claude_code_self_hosted_orchestrator_pool_pending_sessions nel tuo HPA o scaler KEDA, non queue_pending_sessions.
  • Scaling della capacità: scala sul rapporto tra active_sessions e capacity del runner.
  • Gate su connected: filtra la query con claude_code_self_hosted_orchestrator_connected == 1 per istanza, quindi il valore stantio di una replica disconnessa non si nutre nello scaler.
Durante un’interruzione completa del polling, ogni replica disconnessa, la query gated non restituisce dati. HPA mantiene il numero di replica attuale su una metrica mancante, ma lo scaler Prometheus di KEDA al suo ignoreNullValues: "true" predefinito legge il risultato vuoto come zero e scala in; imposta ignoreNullValues: "false" su ScaledObject, facoltativamente con un floor di replica fallback. Il seguente PodMonitor di Prometheus Operator copre entrambi i processi. Seleziona i pod per l’etichetta app.kubernetes.io/part-of: claude-code-self-hosted-runner e la porta denominata health che la ricetta Kubernetes imposta; regola gli spazi dei nomi per corrispondere alla tua distribuzione:

Regole di avviso di esempio

Queste regole di avviso di esempio sono un punto di partenza; sintonizza le soglie per la dimensione della tua flotta:

Avvisi su runner persi e sessioni in attesa

Su una flotta fissa, carica ClaudeRunnersBelowFloor. Con i runner on-demand, carica invece ClaudeOrchestratorSessionsWaiting e ClaudeOrchestratorQueueWaitHigh.

Avviso quando una flotta fissa perde runner

ClaudeRunnersBelowFloor si attiva quando per 10 minuti restano meno runner registrati e raccolti della soglia minima:
  • Soglia minima: imposta il 2 in expr a circa metà del numero di repliche, arrotondato per eccesso. Con tre repliche mantieni 2, e l’avviso si attiva quando resta un solo runner o nessuno.
  • Namespace: sostituisci claude-runners nel matcher e in labels, e copia l’avviso per ogni ulteriore namespace. Se i tuoi target non hanno un’etichetta namespace, rimuovi il matcher e l’etichetta, altrimenti l’avviso legge 0 e si attiva.
  • ClaudeRunnerPollStale e ClaudeRunnerPollErrors: mantienili caricati dalle regole di avviso di esempio, perché ClaudeRunnersBelowFloor conta comunque un runner che non riesce a eseguire il polling

Avviso quando le sessioni attendono runner on-demand

ClaudeOrchestratorSessionsWaiting si attiva quando il numero di sessioni in attesa di un runner resta sopra 0 per 10 minuti. ClaudeOrchestratorQueueWaitHigh si attiva quando oltre l’1% delle attese in coda negli ultimi 10 minuti ha superato i 160 secondi, e questa condizione persiste per 5 minuti:
  • Soglia: se c’è sempre qualche sessione in attesa, alza il > 0 in ClaudeOrchestratorSessionsWaiting sopra il numero che vedi di solito
  • ClaudeOrchestratorDisconnected: mantienilo caricato dalle regole di avviso di esempio, perché ClaudeOrchestratorSessionsWaiting smette di attivarsi circa 2 minuti dopo che l’ultimo orchestrator nel namespace si disconnette

Passa attraverso le metriche del figlio della sessione

Ogni sessione viene eseguita nel suo processo figlio con le sue metriche OpenTelemetry; a --capacity superiore a uno, il runner riscrive come quelle metriche figlio vengono esposte. L’impostazione di OTEL_METRICS_EXPORTER=prometheus sull’host del runner e CLAUDE_CODE_ENABLE_TELEMETRY=1 nell’ambiente della sessione, ad esempio dal tuo script wrapper o dall’ambiente del runner stesso, che le sessioni ereditano, ri-espone gli strumenti di contatore e gauge di ogni figlio sull’endpoint /metrics del runner, insieme alle serie del runner. Il runner riscrive l’esportatore del figlio per eseguire il push su OTLP a un ricevitore solo loopback sulla porta di salute, etichetta ogni serie con etichette session_id e client_platform, e rimuove le serie di una sessione quando quella sessione termina. Gli istogrammi non passano, e una metrica figlio il cui nome entrerebbe in collisione con il prefisso del runner è eliminata. Al --capacity 1 predefinito, la riscrittura non si applica: il figlio della sessione lega il suo endpoint Prometheus sulla porta 9464 come al solito.

Unire le metriche di una sessione a quelle del runner

Per vedere quanto sono costate le sessioni inattive, esegui il join tra claude_code_self_hosted_runner_session_idle_seconds del runner e la metrica di costo di Claude Code su ccr_session_id. La metrica del runner non porta quell’etichetta, quindi assegnagliela con label_replace, come in questa query:
La query restituisce un risultato per ogni sessione inattiva da oltre dieci minuti: il costo in dollari USA che il suo processo Claude Code ha conteggiato finora. Per eseguire il join con un’altra metrica di Claude Code, sostituisci claude_code_cost_usage_total nella query. La query funziona con qualsiasi --capacity.
  • session_id: sulla porta 9464, quell’etichetta sulle metriche di Claude Code contiene il session.id proprio di Claude Code, che non corrisponde ad alcuna serie del runner. Un join su di essa non restituisce nulla, quindi esegui il join su ccr_session_id.
  • Le metriche di Claude Code non hanno ccr_session_id: verifica che OTEL_METRICS_INCLUDE_SESSION_ID non sia impostato su false

Semantica del contatore del ciclo di vita della sessione

I contatori sessions_started_total, sessions_completed_total, sessions_failed_total e sessions_interrupted_total classificano ogni sessione in base a come è terminata. Ogni figlio della sessione generato incrementa sessions_started_total al momento della generazione, e esattamente uno degli altri tre incrementa all’uscita, quindi sessions_started_total meno la somma degli altri tre è uguale al numero di figli della sessione attualmente in esecuzione.
  • completed: la sessione è terminata correttamente. Questo copre il figlio che esce da solo con codice 0, la sessione archiviata o eliminata mentre il figlio era ancora connesso, e il runner che restituisce lo slot in modo pulito: il rilascio della sessione al timeout di inattività, al tempo di ritiro o al limite --kill-session-after-min; un timeout di avvio; o un deassign lato server che il ciclo di polling ha notato prima che il figlio uscisse. Incrementa sessions_completed_total.
  • failed: il figlio è uscito da solo con un codice diverso da zero, sia un crash che un errore di configurazione dopo la generazione. Incrementa sessions_failed_total.
  • interrupted: il runner ha terminato il figlio per un motivo operativo che non è né un successo della sessione né un errore del runner, come un drenaggio, o terminando una sessione che era ancora sul runner quando la finestra di grazia SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS dopo il suo limite --kill-session-after-min è terminata. Un riavvio rolling di Kubernetes che invia SIGTERM è un esempio di drenaggio. Incrementa sessions_interrupted_total.
Prima della v2.1.260, il runner terminava ogni sessione che raggiungeva il suo limite --kill-session-after-min e la contava in sessions_interrupted_total. Il CLAUDE_RUNNER_EXIT_REASON dell’hook post-session classifica gli handoff puliti diversamente. L’hook li segnala come interrupted, perché il runner ha fermato il figlio: un rilascio, un timeout di avvio, un deassign del server e un’archiviazione o eliminazione che il polling ha notato per primo. Questi contatori registrano gli stessi eventi come completed, perché lo slot è stato restituito correttamente. Se riconcili le ricevute dell’hook direttamente contro sessions_completed_total, sottostimi i completamenti. Usa l’hook per le garanzie per sessione e i contatori per i tassi aggregati. Su un ambiente monouso, --capacity 1 con il --drain-grace-sec 0 predefinito, ogni processo del runner esce momenti dopo la fine della sua sessione. sessions_completed_total, sessions_failed_total e sessions_interrupted_total incrementano solo alla fine della sessione, subito prima di quell’uscita, quindi un raschiamento Prometheus ogni 15-60 secondi raramente cattura l’incremento prima che le serie del runner scompaiano; questi tre contatori di fine sessione sono i contatori terminali a cui il resto di questa sezione si riferisce. sessions_started_total incrementa alla generazione e rimane visibile per la vita della sessione, quindi si mostra in modo affidabile, ma su un ambiente monouso legge più vicino a “sessioni attualmente in esecuzione” che a un conteggio cumulativo. Usa la serie in questa tabella per l’obiettivo corrispondente invece dei contatori terminali: Le righe orchestrator_* esistono solo su ambienti che eseguono l’orchestrator on-demand. Su una flotta fissa i cui runner sopravvivono alle loro sessioni, con --drain-grace-sec superiore a 0, usa sum(rate(claude_code_self_hosted_runner_sessions_started_total[5m])) per il throughput; su una flotta monouso quella serie ha lo stesso problema della finestra di raschiamento dei contatori terminali, quindi affidati al conteggio delle sessioni in coda. Controlla il backlog nella scheda Activity dell’ambiente, nella pagina di amministrazione Cloud environments: i runner non esportano una serie di profondità della coda. Per la segnalazione dei risultati per sessione, usa l’hook post-session invece: si attiva alla fine di ogni sessione dove un processo figlio è stato generato, a parte la terminazione abrupte del runner come una preemption VM, per il contratto proprio dell’hook.

Prossimi passi