자체 호스팅 환경 참조
자체 호스팅 러너 및 오케스트레이터에 대한 완전한 참조: CLI 플래그, 환경 변수 및 Prometheus 메트릭.
[!NOTE]
자체 호스팅 환경은 Team 및 Enterprise 플랜에서 공개 베타 상태이며, Owner가 Cloud environments 관리자 페이지에서 Allow self-hosted environments를 켜서 활성화합니다. 이 페이지는 플래그 및 메트릭 참조이며, 설정은 빠른 시작을 참조하고 프로덕션 배포는 Deploy to production에서 플릿 레시피를 참조하세요.
이 페이지는 자체 호스팅 환경에서 실행하는 두 가지 프로세스에 대한 참조입니다: 호스트에서 Claude Code 클라우드 세션을 실행하는 러너와 세션이 대기열에 있을 때 러너를 시작하는 선택적 자동 스케일링 오케스트레이터입니다. 각각 자체 플래그 테이블이 있습니다. 둘 다 Linux 또는 macOS 호스트에서 실행되며, /workspace 및 ~/.claude와 같은 기본값을 가정합니다. 설치된 버전에서 권한 있는 목록을 보려면 claude self-hosted-runner --help를 실행하세요.
메트릭 시리즈 및 일부 API 필드는 여전히 이 페이지에서 환경이라고 부르는 것을 pool이라고 사용합니다. 두 용어 모두 동일한 것을 나타냅니다. 환경 ID는 pool_id 필드이며, ccpool_... 형식입니다: 이 페이지에서 pool 식별자를 표시하는 곳마다 환경을 나타냅니다. CLI 플래그 및 환경 변수는 --environment-secret-file과 같이 environment로 표기합니다. 더 이상 사용되지 않는 pool 표기법은 여전히 작동하며, --environment-secret-file 행에서 설명합니다.
러너 CLI 플래그
대부분의 플래그에는 대응하는 환경 변수가 있습니다. 둘 다 설정되면 플래그가 우선합니다. 기간 플래그는 CLI에서 분 또는 초 단위 값을 받지만, 짝을 이루는 환경 변수는 _MS 접미사가 나타내듯 항상 밀리초 단위이며, 기본값 열은 플래그의 단위를 표시합니다. --exit-if-unused-min 10은 SELF_HOSTED_RUNNER_IDLE_SHUTDOWN_MS=600000과 같으며, SELF_HOSTED_RUNNER_STARTUP_TIMEOUT_MS: "15"와 같은 Helm 값은 기본값인 15분이 아니라 15밀리초를 의미합니다.
| 플래그 | 환경 변수 | 기본값 | 설명 |
|---|---|---|---|
--api-url <url> |
없음 | https://api.anthropic.com |
API 기본 URL입니다. 테스트 목적으로만 재정의합니다. |
--base-dir <path> |
SELF_HOSTED_RUNNER_BASE_DIR |
/workspace; Windows에서는 없음 |
저장소 체크아웃과 세션별 작업 디렉터리를 위한 디렉터리입니다. 러너에는 이 경로 또는 그 상위 경로에 대한 쓰기 권한이 필요합니다. 러너는 시작 시 디렉터리를 생성하며, 디렉터리를 생성하거나 쓸 수 없으면 cannot create or write to base directory와 함께 종료됩니다. v2.1.225 이전에는 첫 번째 세션이 시작될 때 러너가 디렉터리를 생성했기 때문에, 사용할 수 없는 경로는 시작이 아니라 세션을 실패시켰습니다. 지원되는 러너 호스트가 아닌 Windows에서는 기본값이 없으므로, 플래그를 전달하거나 변수를 설정하지 않으면 러너가 시작 시 종료됩니다. 환경 내 모든 러너에서 동일한 값을 사용하십시오. 러너 간 기본 디렉터리와 용량을 동일하게 유지하기를 참조하십시오. |
--capacity <n> |
없음 | 1 |
이 러너가 처리하는 최대 동시 세션 수입니다. 모든 세션은 잠긴 동일한 소유자에 속합니다. 환경 내 모든 러너에서 동일한 값을 사용하십시오. 러너 간 기본 디렉터리와 용량을 동일하게 유지하기를 참조하십시오. |
--client-label <label> |
SELF_HOSTED_RUNNER_CLIENT_LABEL |
호스트의 호스트 이름 | 러너가 등록할 때 전송하는 레이블입니다. 러너는 이 값을 claude_code_self_hosted_runner_info의 client_label 레이블로도 보고합니다. Claude Code v2.1.248 이상이 필요합니다. |
--configure-git |
SELF_HOSTED_RUNNER_CONFIGURE_GIT=1 |
꺼짐 | 시작 시 전역 git ID를 기록하고, Anthropic 커밋 서명을 활성화하고, git push 협상을 켜고, Co-authored-by: 트레일러를 추가하는 커밋 훅을 설치합니다. push 협상에는 Claude Code v2.1.257 이상이 필요합니다. git 구성하기를 참조하십시오. |
--confine-repo-settings <mode> |
SELF_HOSTED_RUNNER_CONFINE_REPO_SETTINGS |
warn |
저장소에 커밋된 설정이 해당 세션 자체의 워크스페이스 외부에 대한 쓰기 또는 읽기 접근 권한을 부여하거나, 환경 변수를 설정하거나, sandbox.enabled: false 또는 disableAllHooks와 같이 운영자의 샌드박스 또는 훅 정책을 재정의하려 할 때 세션을 표시하는 가드의 모드를 설정합니다. 기본값 warn은 위반 사항을 로그에 기록하고 세션을 그대로 시작하며, enforce는 세션을 거부하고, off는 검사를 비활성화합니다. 배포 강화하기를 참조하십시오. |
--debug-token-dir <path> |
SELF_HOSTED_RUNNER_DEBUG_TOKEN_DIR |
설정 안 됨 | 검사를 위해 활성 토큰을 디스크에 기록합니다. 디버그 전용이므로 프로덕션에서는 사용하지 마십시오. |
--defer-shutdown-max-min <n> |
SELF_HOSTED_RUNNER_DEFER_SHUTDOWN_MAX_MS |
0 |
첫 번째 SIGTERM 또는 SIGINT를 받으면 이미 연결된 세션을 드레인하지 않고 계속 처리한 다음, N분 후에 여전히 연결된 세션을 해제하고 종료합니다. 이 값을 설정하기 전에 호스트의 중지 타임아웃을 늘리십시오. 첫 번째 신호 이후로 드레인 연기하기를 참조하십시오. 0은 비활성화합니다. Claude Code v2.1.238 이상이 필요합니다. |
--drain-grace-sec <n> |
SELF_HOSTED_RUNNER_DRAIN_GRACE_MS |
0 |
러너가 종료 신호를 받거나 은퇴 시간에 도달하기 전까지, 활성 세션이 끝난 후 러너가 언제 종료할지를 제어합니다. 0은 추가 작업을 폴링하지 않고 즉시 종료하며, 양수 값은 러너를 먼저 해당 초 동안 유지하면서 잠긴 소유자의 큐를 다시 폴링합니다. 이 경우 강화 섹션에 설명된 세션별 컨테이너 격리를 포기하게 됩니다. --defer-shutdown-max-min으로 연기한 첫 번째 신호 이후에는 여기서 설정한 값과 관계없이 러너가 보유한 세션이 없어지는 즉시 종료합니다. |
--drain-marker-file <path> |
SELF_HOSTED_RUNNER_DRAIN_MARKER_FILE |
설정 안 됨 | 호스트가 SIGTERM을 보내기 전에 정상적인 드레인을 알리기 위해 기록하는 마커 파일입니다. 드레인이 시작될 때 파일이 존재하면, 러너는 자신의 종료를 일반 종료 신호가 아닌 호스트 드레인으로 Anthropic에 보고합니다. --drain-wait-sec 대기를 포함한 드레인 자체는 플래그가 없을 때와 동일하게 실행됩니다. 세션이 쓸 수 없는 로컬 파일 시스템의 경로를 지정하십시오. Claude Code v2.1.271 이상이 필요합니다. |
--drain-wait-sec <n> |
SELF_HOSTED_RUNNER_DRAIN_WAIT_MS |
0 |
드레인이 시작되면(설정에서 --defer-shutdown-max-min을 지정하지 않은 경우 SIGTERM 시점), 자식 프로세스를 종료하기 전에 각 세션의 진행 중인 턴과 백그라운드 작업이 끝날 때까지 최대 N초 동안 기다립니다. 이 대기 중에 러너는 방금 끝난 백그라운드 작업을, 그 결과를 읽는 후속 턴이 시작될 때까지 최대 SELF_HOSTED_RUNNER_BG_RESULT_GRACE_MS 기간 동안 여전히 실행 중인 것으로 간주합니다. 중지 타임아웃도 늘리십시오. |
--environment-secret-file <path> |
SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET |
필수 | 환경 시크릿이 담긴 파일의 경로이며, 오케스트레이터가 생성한 러너의 경우 일회용 작업 주문 JWT가 담긴 파일의 경로입니다. SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET은 파일 경로가 아니라 시크릿 값을 직접 전달합니다. 이전의 --pool-secret-file 플래그와 SELF_HOSTED_RUNNER_POOL_SECRET 변수도 여전히 작동하며 stderr에 지원 중단 알림을 출력합니다. 2.1.216보다 오래된 프리뷰 프로그램 러너 빌드는 이러한 이전 이름만 인식합니다. |
--exec-path <path> |
SELF_HOSTED_RUNNER_EXEC_PATH |
자체 바이너리 | 각 세션마다 실행할 바이너리 또는 래퍼 스크립트입니다. 래퍼 스크립트를 참조하십시오. |
--exit-if-unused-min <n> |
SELF_HOSTED_RUNNER_IDLE_SHUTDOWN_MS |
0 |
오토스케일러 축소를 위해, 작업이 한 번도 할당되지 않은 채 N분 동안 폴링한 후 종료합니다. 0은 비활성화합니다. |
--git-host-rewrite <from>=<to> |
없음 | 설정 안 됨 | 분할 수평 DNS를 위해 클론하기 전에 https://<from>/... 소스 URL을 https://<to>/...로 다시 씁니다. 반복 지정할 수 있으며 플래그 전용입니다. |
--git-ssh-rewrite <host> |
없음 | 설정 안 됨 | SSH 전용 git 호스트를 위해 클론하기 전에 https://<host>/... 소스 URL을 git@<host>:...로 다시 씁니다. 반복 지정할 수 있으며 플래그 전용입니다. |
--health-port <port> |
SELF_HOSTED_RUNNER_HEALTH_PORT |
8080 |
/healthz 및 /metrics 리스너용 포트입니다. 비활성화하려면 0으로 설정합니다. |
--hooks-dir <path> |
SELF_HOSTED_RUNNER_HOOKS_DIR |
설정 안 됨 | 라이프사이클 훅 스크립트가 있는 디렉터리입니다. 라이프사이클 훅을 참조하십시오. |
--host-config-snapshot <mode> |
SELF_HOSTED_RUNNER_HOST_CONFIG_SNAPSHOT |
disk |
러너가 각 세션의 초기값으로 사용하는 호스트 구성 디렉터리의 시작 시점 스냅샷을 보관하는 위치입니다. disk는 스냅샷을 --base-dir 아래의 러너 소유 디렉터리에 복사하고, 각 세션 시작 시 모든 파일을 인메모리 다이제스트와 대조해 검증합니다. 복사본의 파일이 수정된 경우 세션이 실패하며, 러너를 다시 시작할 때까지 러너는 세션을 거부합니다. memory는 전체 스냅샷을 최대 64 MiB까지 힙에 보관합니다. 한도를 초과하면 세션이 호스트 구성 없이 시작되며 그 사실을 알리는 안내가 표시됩니다. 러너가 디스크 스냅샷을 쓸 수 없으면 실패를 로그에 기록하고 해당 실행에서는 memory를 사용합니다. Claude Code v2.1.271 이상이 필요합니다. |
--kill-session-after-min <n> |
SELF_HOSTED_RUNNER_MAX_LIFETIME_MS |
0 |
멈춘 세션에 대한 안전 한도로, 세션을 실제 경과 시간 기준 N분으로 제한합니다. v2.1.260 이상에서는 러너가 한도에 도달한 세션을 해제하여 사용자의 다음 메시지에서 재개할 수 있게 하며, SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS 유예 기간이 끝날 때 여전히 러너에 있는 경우에만 종료합니다. v2.1.260 이전에는 러너가 한도에서 세션을 종료했습니다. 자세한 내용과 값 선택 방법은 일부 세션은 유휴 상태로 간주되지 않음을 참조하십시오. 0은 비활성화합니다. |
--lock-to-account <id> |
SELF_HOSTED_RUNNER_LOCK_TO_ACCOUNT |
설정 안 됨 | 첫 번째 세션에서 잠그는 대신 시작 시 러너를 특정 계정에 미리 잠급니다. 환경의 조직에 속한 이메일 주소 또는 user_... ID를 받습니다. 미리 잠긴 러너는 계정이 없는 Claude Tag 채널 세션을 절대 가져가지 않습니다. |
--log-file <path> |
SELF_HOSTED_RUNNER_LOG_FILE |
설정 안 됨 | stdout 및 stderr 외에 러너 로그를 0600 권한으로 생성된 파일에도 미러링합니다. self-hosted-runner doctor가 로컬에서 로그를 tail하는 데 필요합니다. |
--log-level <level> |
없음 | info |
info 또는 debug |
--post-session-hook-timeout-sec <n> |
SELF_HOSTED_RUNNER_POST_SESSION_HOOK_TIMEOUT_MS |
60 |
러너 종료를 포함한 모든 세션 종료 시 post-session 훅에 주어지는 시간입니다 |
--proxy-authorization-command <command> |
SELF_HOSTED_RUNNER_PROXY_AUTHORIZATION_COMMAND |
설정 안 됨 | 러너가 이그레스 프록시에 연결할 때마다 실행하는 셸 명령으로, 앞뒤 공백을 제거한 stdout을 Proxy-Authorization 헤더 값으로 사용합니다. HTTPS_PROXY 또는 HTTP_PROXY가 필요하며, --proxy-authorization-file과 함께 사용할 수 없습니다. 이그레스 프록시에 인증하기를 참조하십시오. Claude Code v2.1.238 이상이 필요합니다. |
--proxy-authorization-file <path> |
SELF_HOSTED_RUNNER_PROXY_AUTHORIZATION_FILE |
설정 안 됨 | 러너가 이그레스 프록시에 연결할 때마다 읽는 파일로, 앞뒤 공백을 제거한 내용을 Proxy-Authorization 헤더 값으로 사용합니다. 다른 프로세스가 제자리에서 교체하는 토큰에 이 플래그를 사용하십시오. --proxy-authorization-command와 동일한 요구 사항이 적용되며, 함께 사용할 수 없습니다. 이그레스 프록시에 인증하기를 참조하십시오. Claude Code v2.1.238 이상이 필요합니다. |
--push-outcome-on-release |
SELF_HOSTED_RUNNER_PUSH_OUTCOME_ON_RELEASE |
꺼짐 | 드레인이나 유휴 해제와 같이 러너가 시작한 세션 종료 시, 워크스페이스를 삭제하기 전에 추적 중인 결과 브랜치를 origin에 push하여 진행 중인 커밋이 재시작 후에도 유지되도록 합니다. 최선의 노력으로 수행되며, 종료 시간에 30초가 추가되고, push된 브랜치에서 재개하려면 git 2.29 이상이 필요합니다. 활성화하기 전에 push 접근을 claude/* 참조로 제한하십시오. 재개된 세션은 push되지 않은 작업을 잃음을 참조하십시오. checkout 라이프사이클 훅으로 체크아웃한 저장소는 push되지 않으므로, 대신 post-session 훅에서 스냅샷을 만드십시오. |
--release-idle-session-min <n> |
SELF_HOSTED_RUNNER_SESSION_IDLE_MS |
0 |
턴이 끝나거나 세션이 사용자의 조치를 기다리는 상태에서 N분 동안 활동이 없으면 세션 슬롯을 해제합니다. 끝나지 않는 백그라운드 작업을 보유하거나 실행 중인 도구 호출 내부에서 승인을 요청한 세션을 포함하여 아직 턴 진행 중인 세션은 유휴 상태로 간주되지 않으므로, 강제 안전장치로 --kill-session-after-min과 함께 사용하십시오. 세션의 백그라운드 작업이 끝난 후, 러너는 그 결과를 읽는 후속 턴이 시작될 때까지 최대 SELF_HOSTED_RUNNER_BG_RESULT_GRACE_MS 기간 동안 세션을 사용 중인 것으로 간주합니다. 러너가 종료 신호를 받거나 은퇴 시간에 도달하기 전까지, 해제로 인해 러너에 활성 세션이 하나도 남지 않으면 일반 드레인과 동일한 종료 경로가 시작되며 --drain-grace-sec의 적용을 받습니다. --defer-shutdown-max-min으로 연기한 첫 번째 신호 이후에는 해제로 인해 보유한 세션이 없어지는 즉시 러너가 종료합니다. 0은 비활성화합니다. |
--remove-session-state [bool] |
SELF_HOSTED_RUNNER_REMOVE_SESSION_STATE |
꺼짐 | 세션이 이 러너에서 종료되면 결과와 관계없이 <base-dir>/_sessions/ 아래의 세션별 디렉터리를 제거합니다. 이러한 디렉터리에 무엇이 담기며 남아 있을 때 누가 읽을 수 있는지는 미리 준비된 체크아웃 재사용하기에 설명되어 있습니다. 제거는 최선의 노력으로 수행됩니다. 정리가 실행되기 전에 러너가 강제 종료되거나 드레인 기한에 도달하면 세션별 디렉터리가 그대로 남습니다. 플래그를 켜면 실패하거나 중단된 세션의 디버그 로그가 디스크에 보관되지 않습니다. Claude Code v2.1.268 이상이 필요합니다. |
--retire-at <epoch-seconds> |
SELF_HOSTED_RUNNER_RETIRE_AT |
설정 안 됨 | 알려진 시간에 러너를 종료하는 인프라를 위해, 초 단위의 절대 Unix 타임스탬프에 러너를 은퇴시킵니다. 해제 순서와 여유 시간 설정 방법은 러너 라이프사이클에 설명되어 있습니다. 2001년 이전 또는 5138년 이후의 값은 플래그에서는 거부되고 환경 변수에서는 무시됩니다. |
--server-auto-mode-lists <mode> |
SELF_HOSTED_RUNNER_SERVER_AUTO_MODE_LISTS |
no-allow |
컨트롤 플레인이 세션과 함께 보내는 자동 모드 분류기 규칙 목록 중 어떤 목록이 해당 세션에 도달할 수 있는지를 지정합니다: all, no-allow, 또는 none. 각 값이 무엇을 적용하는지는 자동 모드 규칙 목록을 참조하십시오. 잘못된 값을 지정하면 시작 시 러너가 중지됩니다. Claude Code v2.1.295 이상이 필요합니다. |
--session-stop-grace-sec <n> |
SELF_HOSTED_RUNNER_SESSION_STOP_GRACE_MS |
5 |
세션이 끝난 후 Claude 프로세스를 강제 종료하기 전에 정상적으로 종료되기를 기다리는 시간입니다. 자식 프로세스 자체의 SessionEnd 훅에 더 많은 시간이 필요하면 값을 늘리십시오. |
--startup-timeout-min <n> |
SELF_HOSTED_RUNNER_STARTUP_TIMEOUT_MS |
15 |
자식 프로세스가 N분 이내에 활동 채널에서 초기화되었음을 알리지 않으면 세션 슬롯을 해제합니다. N분은 클론 이후 프로세스 생성 시점부터 시작되며, 자식 프로세스가 초기화되거나 상태를 보고하기 전에 user 또는 assistant 메시지를 내보낼 때마다 다시 시작됩니다. v2.1.299 이전에는 이 타임아웃이 세션의 첫 번째 그러한 메시지에서 더 이상 적용되지 않았습니다. 초기화 신호 이후의 해제에 대해서는 --release-idle-session-min을 참조하십시오. 0은 비활성화합니다. |
--trust-workspace [bool] |
SELF_HOSTED_RUNNER_TRUST_WORKSPACE |
켜짐 | 각 세션의 저장소 경로에 대한 영구 신뢰를 미리 설정하여 저장소에 커밋된 permissions.allow 및 additionalDirectories가 적용되도록 합니다. 저장소에 커밋된 권한 부여를 제외하고 대신 호스트 구성의 settings.json에서 허용 규칙을 구성하려면 false로 설정하십시오. 저장소에 커밋된 sandbox.* 설정은 어느 경우든 여전히 적용되며, 이 때문에 저장소 설정 가드는 이 플래그와 관계없이 해당 설정을 검사합니다. |
--use-anthropic-git-proxy |
CLAUDE_RUNNER_USE_GIT_PROXY=1 |
꺼짐 | 고객이 관리하는 git 인증 대신 Anthropic git 프록시를 통해 github.com의 저장소를 클론합니다. --capacity 1과 git 2.32 이상이 필요하며, 그렇지 않으면 러너가 시작을 거부합니다. 다시 쓰기 플래그보다 우선합니다. |
대부분의 기간 플래그에는 최댓값이 있으며, 이는 각 타임아웃을 런타임의 32비트 타이머 상한인 약 24.85일 이내로 유지하기 위해 정해졌습니다. --*-min 플래그는 10080분(7일), --drain-grace-sec는 604800초(역시 7일), --drain-wait-sec는 86400초(24시간)가 상한입니다. --session-stop-grace-sec와 --post-session-hook-timeout-sec에는 상한이 없습니다. 상한을 초과했을 때의 동작은 사용 환경에 따라 다릅니다.
- 플래그: 오류와 함께 시작이 실패합니다.
- 환경 변수: 러너가 값을 거부하지 않고 타이머 상한으로 제한합니다.
자동 모드 규칙 목록
--server-auto-mode-lists를 사용하면 러너 외부에서 오는 자동 모드 분류기 규칙 중 어떤 것이 러너의 세션에 도달할지 결정할 수 있습니다. Anthropic의 컨트롤 플레인은 세션과 함께 규칙 목록을 보내고 러너에 이를 적용하도록 요청할 수 있습니다. 일부 항목은 조직의 관리자가 작성한 규칙일 수 있습니다. 목록은 environment, soft_deny, allow입니다.
environment: 항목은 분류기가 더 많이 허용하게 할 수도 있고 더 적게 허용하게 할 수도 있습니다.soft_deny: 항목은 사용자가 명시적으로 요청했거나allow예외가 적용되는 경우를 제외하고 작업을 차단합니다.allow:soft_deny항목에 대한 예외입니다.
플래그의 값에 따라 러너가 적용하는 목록이 결정됩니다.
no-allow: 기본값입니다.environment와soft_deny를 적용하고allow는 보류합니다.environment항목은 여전히 분류기가 더 많이 허용하게 할 수 있으므로, 기본값이 모든 완화를 배제하지는 않습니다.all: 세 가지 목록을 모두 적용합니다.none: 어떤 목록도 적용하지 않습니다. 이러한 목록으로 인한 모든 완화를 배제하려면none을 선택하십시오. 이 경우soft_deny제한도 함께 제외됩니다.
컨트롤 플레인이 러너에 목록 적용을 요청하도록 만드는 러너 설정은 없습니다. 요청하지 않으면 설정한 값과 관계없이 세션은 어떤 목록도 받지 않습니다. 어떤 경우였는지 확인하려면 --log-level debug로 러너를 시작하십시오. 그러면 러너는 각 세션에 대해 the server asked this runner to apply가 포함된 줄 또는 the server did not ask this runner to apply the auto mode lists it sends가 포함된 줄을 로그에 기록합니다.
오케스트레이터 CLI 플래그
self-hosted-runner orchestrator 서브명령은 on-demand runners를 생성하며, --api-url, --environment-secret-file, --hooks-dir, --health-port 및 --log-level을 러너와 동일한 기본값으로 허용하며, 러너의 플래그에 하나가 있는 경우 동일한 환경 변수를 허용합니다. 단, --hooks-dir은 필수이며 spawn-runner 훅을 포함해야 합니다. 또한 자체 플래그를 사용합니다:
| 플래그 | 기본값 | 설명 |
|---|---|---|
--hook-concurrency <n> |
4 |
병렬로 실행되는 최대 spawn-runner 훅입니다. 또한 폴링당 청구되는 스폰 요청 수를 제한합니다. 오케스트레이터는 자신이 시작한 모든 훅이 완료된 후에만 새 스폰 요청을 확인하므로, 느린 훅 하나가 해당 오케스트레이터의 다음 훅을 지연시킵니다. |
--hook-timeout <sec> |
60 |
이 많은 초 후 훅의 프로세스 트리를 종료합니다. 타임아웃과 5초 킬 유예는 --expected-spawn-seconds 아래에 있어야 합니다. 오케스트레이터는 시작 시 이를 적용합니다. |
--expected-spawn-seconds <sec> |
120 |
오케스트레이터가 스폰 요청을 받은 시점부터 러너가 등록될 때까지의 예상 p99 시간이며, 플랫폼에서 용량을 기다리는 시간도 포함됩니다. 서버는 10~3600 범위를 적용합니다. 모든 폴링에서 서버 측 임차로 전송됩니다. 경과하기 전에 러너가 등록되지 않으면 세션이 새 주문 ID로 다시 제공됩니다. 모든 복제본은 이 값을 공유해야 합니다. |
--min-idle <n> |
0 |
대기 중인 러너를 사전에 생성하여 최소 N개의 유휴 세션 슬롯을 무료로 유지합니다. 0은 사전 워밍을 비활성화합니다. 러너의 --exit-if-unused-min과 쌍을 이루어 잉여 대기 러너가 자신을 회수하도록 합니다. |
--debug-dir <path> |
설정되지 않음 | 각 스폰 요청의 작업 주문 및 훅 stderr을 디스크에 씁니다. 디버그 전용이며 프로덕션에서 설정하지 마세요. |
SCM 커넥터 플래그
SCM 커넥터를 사용할 수 없으므로 이 섹션의 플래그를 설정하지 않은 상태로 두세요. --scm-connector-host를 설정하면 연결이 열리지 않으며 오케스트레이터는 계속 재시도합니다. 러너는 여전히 세션 큐로 시작합니다.
커넥터는 오케스트레이터에서 Anthropic의 제어 평면으로의 상시 WebSocket 연결입니다. 저장소 선택기 및 분기 또는 ref 리졸버와 같은 호스팅된 사전 세션 흐름이 네트워크 내부에서만 라우팅 가능한 GitHub Enterprise Server 호스트에 도달할 수 있도록 설계되었습니다. GitHub Enterprise Server 페이지의 네트워크 요구 사항을 참조하여 이러한 흐름에 필요한 사항을 확인하세요.
| 플래그 | 기본값 | 설명 |
|---|---|---|
--scm-connector-host <host[:port]> |
설정되지 않음 | 요청을 전달할 GitHub Enterprise Server 호스트명입니다. 포트는 기본값이 443입니다. |
--scm-connector-id <n> |
--scm-connector-host와 필수 |
조직의 GitHub Enterprise Server 연결의 숫자 ID입니다. |
--scm-connector-provider <slug> |
ghe |
공급자를 식별하는 경로 세그먼트이며, ^[a-z0-9-]{1,32}$와 일치합니다. |
--scm-connector-ca-file <path> |
설정되지 않음 | GitHub Enterprise Server 호스트에 대한 TLS 연결을 위한 추가 CA 번들(PEM 형식)입니다. |
--scm-connector-host-rewrite <from>=<to_host:to_port> |
설정되지 않음 | 엔드투엔드 테스트 전용: Host 헤더 및 TLS SNI를 --scm-connector-host로 유지하면서 TCP 연결을 리디렉션합니다. |
각 연결 시도 시 오케스트레이터는 기존 환경 비밀을 전송하며, 30초 플러스 지터로 제한되는 지수 백오프를 사용하여 자동으로 재시도합니다.
환경 변수 전용 설정
이러한 러너 설정은 환경에서만 읽으며 대부분의 배포가 기본값으로 남겨두는 동작을 다룹니다:
| 환경 변수 | 기본값 | 설명 |
|---|---|---|
SELF_HOSTED_RUNNER_BG_RESULT_GRACE_MS |
30000 |
러너가 백그라운드 작업이 완료된 후 결과를 읽는 후속 턴이 시작되지 않은 동안 세션을 바쁜 것으로 간주하는 시간입니다. --drain-wait-sec 및 --release-idle-session-min 행은 드레인 및 유휴 해제에서 보유가 적용되는 위치를 설명하며, Runner lifecycle은 --retire-at 은퇴에서 적용되는 위치를 설명합니다. 0 또는 사용할 수 없는 값은 기본값으로 폴백되므로 보유를 끌 수 없습니다. Claude Code v2.1.228 이상이 필요합니다. |
SELF_HOSTED_RUNNER_HOST_CONFIG_DIR |
~/.claude |
러너의 시작 스냅샷으로 캡처되고 각 세션의 CLAUDE_CONFIG_DIR로 시드되는 디렉토리입니다. 디스크의 변경 사항은 러너 재시작 후 적용됩니다. 변수를 설정하면 러너가 MCP seeding을 위해 .claude.json을 읽는 위치도 이동하므로 설정하면 자체 기본값을 포함하여 해당 조회를 재배치합니다. 빈 디렉토리를 가리켜 시딩을 완전히 비활성화하세요. |
SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS |
900000 |
세션이 --kill-session-after-min 제한에 도달한 후, 러너가 세션을 종료하기 전에 실행 중인 턴이 완료되거나 해제가 완료될 때까지 대기하는 시간입니다. |
SELF_HOSTED_RUNNER_POST_TURN_SETTLE_MS |
7000 |
턴이 완료된 후 세션의 프로세스가 턴의 끝을 Anthropic에 보고하는 동안 러너가 --drain-wait-sec 드레인에 대해 세션을 바쁜 것으로 계산하는 시간의 상한입니다. 0 또는 사용할 수 없는 값은 기본값으로 폴백되므로 보유를 끌 수 없습니다. Claude Code v2.1.275 이상이 필요합니다. |
SELF_HOSTED_RUNNER_SIGKILL_GRACE_MS |
30000 |
러너가 중단 불가능한 I/O에 갇혀 있는 자식에게 OS가 SIGKILL을 전달할 때까지 기다린 후 자신을 종료하기 전까지 기다리는 시간입니다. --post-session-hook-timeout-sec 더하기 15초로 바닥이 정해지며, --push-outcome-on-release가 설정되면 30초 더 추가되므로 효과적인 최소값은 기본값에서 75초입니다. |
CLAUDE_RUNNER_FETCH_DEPTH |
50 |
신선한 복제를 위한 Git 페치 깊이입니다. 양의 정수 또는 완전한 페치를 위해 full 또는 0을 설정하세요. 워크스페이스에 이미 있는 클론의 경우 미리 준비된 체크아웃 재사용을 참조하세요. |
CLAUDE_RUNNER_FETCH_SERVER_PROGRESS_CAP_MS |
600000 |
서버가 대규모 저장소의 팩을 준비할 때처럼 Git 서버 자체의 진행률 수치가 계속 증가하는 동안, Git 페치가 첫 데이터를 기다릴 수 있는 시도당 시간(밀리초)입니다. 0 또는 off는 이 대기를 끕니다. 이 경우 해당 페치는 데이터 없이 2분이 지나면 중단됩니다. 그 외의 정수는 120000에서 1800000 사이, 즉 2분에서 30분 사이로 제한됩니다. Claude Code v2.1.295 이상이 필요합니다. |
CLAUDE_RUNNER_SKIP_GIT_VERIFY |
설정되지 않음 | 1일 때, checkout 훅이 실행된 후 .git 존재 확인을 건너뜁니다. 훅이 비git 소스를 구체화할 때 이를 설정하세요. |
FORCE_AUTOUPDATE_PLUGINS |
설정되지 않음 | 1일 때, 바이너리가 고정되어 있어도 플러그인 마켓플레이스가 자동 업데이트되도록 합니다. |
CLAUDE_CODE_DISABLE_ARTIFACT |
설정되지 않음 | 1일 때, 조직의 관리자 설정과 관계없이 세션에서 Artifact 도구를 비활성화하고 *.frame.claudeusercontent.com 이그레스 요구 사항을 삭제합니다. |
텔레메트리
세션 자식은 끄지 않으면 Anthropic에 운영 텔레메트리를 전송합니다. 코드 또는 저장소 내용은 전송되지 않습니다. 러너 프로세스에서 텔레메트리 변수를 설정하세요. 러너는 서버 제공 환경 변수를 적용한 후 다시 주장하므로 운영자의 설정이 항상 우선합니다.
한 가지 제어는 자체 호스팅 환경에만 해당됩니다: CLAUDE_CODE_BYOC_ENABLE_DATADOG=1은 Datadog 운영 메트릭을 옵트인하며, 이는 자체 호스팅 환경에서 기본적으로 꺼져 있습니다. 일반 Claude Code 텔레메트리 제어인 DISABLE_TELEMETRY, DO_NOT_TRACK, DISABLE_ERROR_REPORTING 및 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC은 environment variable reference에서 문서화된 대로 세션 자식에 적용됩니다. DISABLE_GROWTHBOOK은 관련이 있지만 다릅니다: DISABLE_GROWTHBOOK=1을 설정하면 기능 플래그 페칭이 비활성화되고, DISABLE_TELEMETRY도 설정되지 않으면 텔레메트리가 켜져 있습니다.
CLAUDE_CODE_ENABLE_TELEMETRY는 관련이 없습니다: Monitoring에서 설명한 대로 자신의 수집기로 OpenTelemetry 내보내기를 활성화하며, Anthropic의 분석을 제어하지 않습니다.
상태 엔드포인트
러너는 구성된 상태 포트에서 GET /healthz를 제공합니다. 응답은 프로세스가 살아 있을 때마다 200 OK이며, 폴 루프가 어떤 상태에 있든 관계없이, 이 엔드포인트의 HTTP 프로브는 죽은 프로세스만 감지합니다. JSON 본문은 현재 상태를 설명합니다:
{
"status": "ok",
"runner_id": "ccrunner_...",
"active_sessions": 2,
"last_poll_at": "2026-03-31T18:04:11.220Z",
"last_poll_age_ms": 842
}
사용자 정의 프로브에서 last_poll_age_ms를 생존 신호로 사용하세요. 무한정 증가하는 값은 폴 루프가 고착되었음을 나타냅니다. last_poll_at 및 last_poll_age_ms 모두 첫 번째 폴이 완료될 때까지 null입니다.
상태 포트에서 제공되는 오케스트레이터 자체의 /healthz는 항상 200을 반환합니다. 본문은 가장 최근 폴이 성공했는지 여부를 보고하는 connected 필드와 queue_counts의 상태별 스폰 큐 수를 전달합니다. connected가 false인 이유를 확인하려면 최상위 last_error 필드를 읽으세요. 이 필드는 폴이 성공할 때마다 null로 재설정됩니다. 상태 코드가 아닌 connected에 준비 및 경고를 게이트하세요.
SCM connector가 구성되면, 오케스트레이터의 /healthz 본문도 scm_connector_connected 및 connected, last_connected_at, last_error, reconnects 및 requests_forwarded를 포함하는 scm_connector 객체를 전달합니다. --scm-connector-host가 설정되지 않으면 두 필드 모두 null입니다.
Prometheus 메트릭
각 러너는 /healthz와 같은 포트의 GET /metrics에서 Prometheus 메트릭을 제공합니다. 주요 시리즈는 다음과 같습니다.
| 시리즈 | 참고 |
|---|---|
claude_code_self_hosted_runner_info{runner_id,version,client_label} |
항상 1이며, 플릿 인벤토리 파악과 버전 불일치 감지에 유용합니다 |
claude_code_self_hosted_runner_capacity |
구성된 --capacity |
claude_code_self_hosted_runner_active_sessions |
현재 실행 중인 세션 |
claude_code_self_hosted_runner_locked_account{email} |
러너가 사용자에게 잠기고 act.email 클레임을 포함한 세션 토큰이 발급된 후에 나타납니다. Claude Tag 에이전트에 잠긴 러너에서는 세션 토큰에 act.email이 없으므로 이 시리즈가 없습니다. 레이블 값은 계정 이메일입니다. 메트릭 저장소를 폭넓게 읽을 수 있다면 스크레이프 시점에 레이블을 삭제하거나 해시 처리하십시오. 예를 들어 Prometheus metric_relabel_configs를 사용할 수 있습니다. |
claude_code_self_hosted_runner_last_poll_age_seconds |
마지막으로 폴링에 성공한 이후 경과한 초입니다. 60을 초과하면 알림을 보내십시오. |
claude_code_self_hosted_runner_poll_errors_total{error_kind} |
종류별 누적 PollWork 실패 수입니다: transport, timeout, 5xx, 429, 4xx. 다섯 개 시리즈 모두 프로세스 시작 시점부터 존재하며, rate(...[5m]) > 0일 때 알림을 보내십시오. |
claude_code_self_hosted_runner_sessions_started_total{client_platform} |
러너 수명 동안 생성된 세션 자식 프로세스 수로, web_claude_ai, ios, android, desktop_app, claude_code_cli 같은 세션 출처마다 하나의 시리즈가 있으며, 서버가 출처를 보내지 않은 경우에는 unknown입니다. Slack 세션은 어떤 Slack 통합이 생성했는지에 따라 claude_in_slack 또는 claude-in-slack 중 하나를 가지므로, {client_platform=~"claude[-_]in[-_]slack"} 같은 정규식 셀렉터로 둘 다 매칭하십시오. 플릿 전체 합계는 sum()을 사용하십시오. |
claude_code_self_hosted_runner_sessions_completed_total{client_platform} |
정상적으로 종료된 세션으로, 레이블은 동일합니다. 단순한 정상 종료보다 범위가 넓습니다. 무엇이 집계되는지는 세션 수명 주기 카운터 의미를 참조하십시오. |
claude_code_self_hosted_runner_sessions_failed_total{client_platform} |
실패로 종료된 세션으로, 레이블은 동일합니다. 같은 주의 사항이 적용됩니다. 세션 수명 주기 카운터 의미를 참조하십시오. |
claude_code_self_hosted_runner_sessions_interrupted_total{client_platform} |
세션 결과가 아닌 운영상의 이유로 러너가 종료시킨 세션으로, 레이블은 동일합니다. 세션 수명 주기 카운터 의미를 참조하십시오. |
claude_code_self_hosted_runner_initializing_sessions |
할당 시점부터 자식의 init 이벤트까지, 현재 초기화 단계에 있는 세션 |
claude_code_self_hosted_runner_session_init_duration_seconds |
세션 초기화 소요 시간 히스토그램 |
claude_code_self_hosted_runner_session_init_errors_total |
init에 도달하기 전에 실패한 세션: checkout 훅 실패, git 준비, 토큰 문제 또는 init 이전 자식 크래시 |
claude_code_self_hosted_runner_session_start_hook_errors_total |
오류 결과를 보고한 SessionStart 훅으로, 실패한 훅 실행마다 하나씩 집계됩니다 |
claude_code_self_hosted_runner_session_idle_seconds{session_id,client_platform} |
세션이 유휴 상태가 된 이후 경과한 초를 나타내는 세션별 게이지입니다. 응답되지 않은 권한 프롬프트에서 멈춘 세션을 종료하는 데 유용합니다. |
오케스트레이터는 자체 /healthz와 같은 포트의 GET /metrics에서 자체 시리즈를 제공합니다.
| 시리즈 | 참고 |
|---|---|
claude_code_self_hosted_orchestrator_info{version,pool_id,orchestrator_uuid,hostname} |
항상 1 |
claude_code_self_hosted_orchestrator_connected |
가장 최근 폴링이 성공하면 1이며, 실패 종류와 관계없이 폴링이 한 번이라도 실패하면 0으로 떨어집니다 |
claude_code_self_hosted_orchestrator_last_poll_age_seconds |
성공 여부와 관계없이 마지막 폴링 시도 이후 경과한 초입니다. 이름이 같은 러너의 메트릭은 마지막 성공 이후를 측정하는 것과 다릅니다. 실패하는 폴링을 잡아내려면 connected와 함께 사용하십시오. 오케스트레이터의 폴링 루프는 훅 실행을 기다리므로, 고정값 60 대신 --hook-timeout에 여유를 더한 값, 기본값 기준 약 90초를 초과할 때 알림을 보내십시오. |
claude_code_self_hosted_orchestrator_poll_errors_total{error_kind} |
종류별 누적 PollSpawnHints 실패 수입니다: transport, timeout, 5xx, 429, 4xx. 다섯 개 시리즈 모두 프로세스 시작 시점부터 존재하며, rate(...[5m]) > 0일 때 알림을 보내십시오. |
claude_code_self_hosted_orchestrator_queue_pending_sessions |
지금 바로 가져갈 수 있는 생성 요청 |
claude_code_self_hosted_orchestrator_queue_backing_off_sessions |
재시도 가능한 훅 실패 후 재시도 백오프 중인 생성 요청 |
claude_code_self_hosted_orchestrator_queue_circuit_broken_sessions |
생성이 차단된 세션입니다. 각 세션은 사용자가 새 메시지를 보내거나 Owner가 환경의 Activity 탭에서 재시도할 때까지 차단 상태로 유지됩니다. 원인을 해결한 후에도 값이 0보다 큰 상태로 남아 있을 수 있습니다. 0보다 크면 알림을 보내십시오. |
claude_code_self_hosted_orchestrator_pool_pending_sessions |
이 환경에서 러너를 기다리는 전체 세션 수입니다. 환경 전체의 집계값이며 모든 오케스트레이터 인스턴스에서 동일하므로, 인스턴스 간에는 SUM 대신 MAX를 사용하십시오. |
claude_code_self_hosted_orchestrator_pool_active_sessions |
현재 이 환경에서 살아 있는 러너에 할당된 세션입니다. 환경 전체의 집계값이며 모든 오케스트레이터 인스턴스에서 동일하므로, 인스턴스 간에는 SUM 대신 MAX를 사용하십시오. |
claude_code_self_hosted_orchestrator_spawn_hooks_total{result} |
누적 spawn-runner 훅 결과: ok, retryable, non_retryable. 러너가 생성하는 세션 자식이 아니라 오케스트레이터의 훅 호출을 집계합니다. 1보다 큰 capacity, 웜 풀, 같은 세션에 대해 다시 생성된 러너로 인해 두 값이 달라지므로 sessions_started_total과 비교할 수 없습니다. |
claude_code_self_hosted_orchestrator_spawn_hook_duration_seconds |
훅 소요 시간 히스토그램 |
claude_code_self_hosted_orchestrator_warm_hints_dispatched_total |
프로세스 시작 이후 디스패치된 대기(standby) 생성 요청 수 |
claude_code_self_hosted_orchestrator_session_queue_wait_seconds |
오케스트레이터가 생성을 위해 가져가기 전까지 각 세션이 큐에서 대기한 시간(초)의 히스토그램으로, 컨트롤 플레인이 각 세션의 생성 요청과 함께 보내는 큐 대기 타임스탬프를 기준으로 기록됩니다. p50/p99 큐 시간 알림에 사용하십시오. 사전 워밍 생성은 샘플링되지 않습니다. |
claude_code_self_hosted_orchestrator_clock_skew_seconds |
로컬 시각에서 서버 시각을 뺀 시계 오차로, 진단용이며 측정된 후에 나타납니다 |
claude_code_self_hosted_orchestrator_scm_connector_connected |
SCM 커넥터의 WebSocket이 열려 있으면 1, 연결 시도 중이거나 백오프 중이면 0입니다. --scm-connector-host가 설정되지 않은 경우에는 없습니다. |
claude_code_self_hosted_orchestrator_scm_connector_requests_forwarded_total |
프로세스 시작 이후 구성된 SCM 호스트로 프록시된 누적 HTTP 요청 수입니다. --scm-connector-host가 설정되지 않은 경우에는 없습니다. |
오토스케일링에는 스케일링 방식에 맞는 시리즈를 선택하고, 스케일러에 전달하기 전에 게이트를 적용하십시오.
- 큐 깊이 기반 스케일링:
queue_pending_sessions가 아니라claude_code_self_hosted_orchestrator_pool_pending_sessions를 HPA 또는 KEDA 스케일러에 전달하십시오. - 용량 기반 스케일링: 러너의
active_sessions대capacity비율을 기준으로 스케일링하십시오. connected로 게이트 적용: 인스턴스별로claude_code_self_hosted_orchestrator_connected == 1로 쿼리를 필터링하여, 연결이 끊긴 레플리카의 오래된 값이 스케일러에 전달되지 않도록 하십시오.
모든 레플리카의 연결이 끊긴 전면적인 폴링 장애 중에는 게이트가 적용된 쿼리가 데이터를 반환하지 않습니다. HPA는 메트릭이 없으면 현재 레플리카 수를 유지하지만, KEDA의 Prometheus 스케일러는 기본값 ignoreNullValues: "true"에서 빈 결과를 0으로 읽고 스케일 인합니다. ScaledObject에 ignoreNullValues: "false"를 설정하고, 필요하면 fallback 레플리카 하한을 함께 설정하십시오.
다음 Prometheus Operator PodMonitor는 두 프로세스를 모두 다룹니다. Kubernetes 레시피에서 설정하는 app.kubernetes.io/part-of: claude-code-self-hosted-runner 레이블과 이름이 지정된 health 포트로 파드를 선택합니다. 배포에 맞게 네임스페이스를 조정하십시오.
# Example Prometheus Operator PodMonitor for the Claude Code self-hosted
# runner + orchestrator. Adjust the namespace and label selectors to match
# your deployment. Both the runner and the orchestrator serve /metrics on
# their --health-port (default 8080).
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: claude-code-self-hosted-runner
namespace: monitoring
spec:
namespaceSelector:
matchNames:
- claude-runners
selector:
matchExpressions:
# Matches the runner Deployment from the Kubernetes recipe, plus any
# on-demand runner Jobs and orchestrator pods you label the same way
# and give a named 'health' containerPort.
- key: app.kubernetes.io/part-of
operator: In
values: [claude-code-self-hosted-runner]
podMetricsEndpoints:
- port: health
path: /metrics
interval: 30s
샘플 알림 규칙
다음 샘플 알림 규칙은 출발점입니다. 플릿 규모에 맞게 임계값을 조정하십시오.
# Example Prometheus alert rules for the Claude Code self-hosted runner
# + orchestrator. Tune thresholds for your fleet size and SLOs.
groups:
- name: claude-code-self-hosted-runner
rules:
- alert: ClaudeRunnerPollStale
expr: claude_code_self_hosted_runner_last_poll_age_seconds > 60
for: 2m
labels: {severity: warning}
annotations:
summary: "Runner {{ $labels.pod }} has not polled in >60s"
- alert: ClaudeRunnerVersionDrift
expr: count(count by (version) (claude_code_self_hosted_runner_info)) > 1
for: 30m
labels: {severity: info}
annotations:
summary: "Runners are running mixed versions"
- alert: ClaudeRunnerInitErrorsHigh
expr: sum by (namespace) (increase(claude_code_self_hosted_runner_session_init_errors_total[10m])) > 3
for: 5m
labels: {severity: warning}
annotations:
summary: "Sessions are failing before init (checkout hook / git / token / pre-init crash)"
- alert: ClaudeRunnerPollErrors
expr: sum by (pod) (rate(claude_code_self_hosted_runner_poll_errors_total[5m])) > 0
for: 2m
labels: {severity: warning}
annotations:
summary: "Runner {{ $labels.pod }}: PollWork failing ({{ $value | humanize }}/s over 5m)"
- alert: ClaudeRunnerSessionStartHookErrors
expr: sum by (namespace) (increase(claude_code_self_hosted_runner_session_start_hook_errors_total[10m])) > 3
for: 5m
labels: {severity: warning}
annotations:
summary: "SessionStart hooks are failing"
- name: claude-code-self-hosted-orchestrator
rules:
- alert: ClaudeOrchestratorDisconnected
expr: claude_code_self_hosted_orchestrator_connected == 0
for: 2m
labels: {severity: critical}
annotations:
summary: "Orchestrator {{ $labels.pod }} cannot reach the Anthropic control plane"
- alert: ClaudeOrchestratorPollStale
expr: claude_code_self_hosted_orchestrator_last_poll_age_seconds > 90
for: 2m
labels: {severity: warning}
annotations:
summary: "Orchestrator {{ $labels.pod }} has not polled in >90s (poll loop waits on hook execution)"
- alert: ClaudeOrchestratorCircuitBroken
expr: max by (namespace) (claude_code_self_hosted_orchestrator_queue_circuit_broken_sessions and on (instance) max_over_time(claude_code_self_hosted_orchestrator_connected[2m]) == 1) > 0
for: 1m
labels: {severity: critical}
annotations:
summary: "Sessions blocked from spawning: {{ $value }}. Read each one's error in the Activity tab, fix the cause, then select Retry"
- alert: ClaudeOrchestratorPollErrors
expr: sum by (pod) (rate(claude_code_self_hosted_orchestrator_poll_errors_total[5m])) > 0
for: 2m
labels: {severity: warning}
annotations:
summary: "Orchestrator {{ $labels.pod }}: PollSpawnHints failing ({{ $value | humanize }}/s over 5m)"
- alert: ClaudeOrchestratorSpawnHookFailing
expr: sum by (pod) (increase(claude_code_self_hosted_orchestrator_spawn_hooks_total{result!="ok"}[5m])) > 3
for: 5m
labels: {severity: warning}
annotations:
summary: "Orchestrator {{ $labels.pod }}: >3 spawn-runner hook failures in 5m"
손실된 러너와 대기 중인 세션에 대한 알림
고정 플릿에서는 ClaudeRunnersBelowFloor를 로드하십시오. 온디맨드 러너를 사용하는 경우에는 대신 ClaudeOrchestratorSessionsWaiting과 ClaudeOrchestratorQueueWaitHigh를 로드하십시오.
고정 플릿에서 러너가 줄어들 때 알림
ClaudeRunnersBelowFloor는 등록되고 스크레이프되는 러너 수가 10분 동안 하한보다 적게 남아 있을 때 발생합니다.
groups:
# Fixed fleets only. With on-demand runners the count follows demand,
# so ClaudeRunnersBelowFloor would fire whenever demand is low.
- name: claude-code-self-hosted-fixed-fleet-capacity
rules:
- alert: ClaudeRunnersBelowFloor
expr: (count(claude_code_self_hosted_runner_info{namespace="claude-runners"}) or vector(0)) < 2
for: 10m
labels: {severity: critical, namespace: claude-runners}
annotations:
summary: "Runners registered and scraped: {{ $value }}, below the floor. Check the runner workloads first, then the scrape targets if all are running."
- 하한:
expr의2를 레플리카 수의 약 절반(올림)으로 설정하십시오. 레플리카가 세 개라면2를 유지하며, 러너가 하나만 남거나 하나도 남지 않으면 알림이 발생합니다. - 네임스페이스: matcher와
labels의claude-runners를 바꾸고, 추가 네임스페이스마다 알림을 복사하십시오. 대상에namespace레이블이 없다면 matcher와 레이블을 제거하십시오. 그렇지 않으면 알림이 0을 읽고 발생합니다. ClaudeRunnerPollStale및ClaudeRunnerPollErrors: 샘플 알림 규칙에서 로드한 상태로 유지하십시오.ClaudeRunnersBelowFloor는 폴링할 수 없는 러너도 여전히 집계하기 때문입니다
세션이 온디맨드 러너를 기다릴 때 알림
ClaudeOrchestratorSessionsWaiting은 러너를 기다리는 세션 수가 10분 동안 0보다 큰 상태로 유지될 때 발생합니다. ClaudeOrchestratorQueueWaitHigh는 지난 10분 동안의 큐 대기 중 1%를 넘는 대기가 160초를 초과하고, 이 상태가 5분 동안 유지될 때 발생합니다.
groups:
# On-demand runners only. Needs no edit for the namespace.
- name: claude-code-self-hosted-on-demand-capacity
rules:
- alert: ClaudeOrchestratorSessionsWaiting
expr: |
max by (namespace) (
claude_code_self_hosted_orchestrator_pool_pending_sessions
and on (instance)
max_over_time(claude_code_self_hosted_orchestrator_connected[2m]) == 1
) > 0
for: 10m
labels: {severity: warning}
annotations:
summary: "Sessions waiting for a runner: {{ $value }}, above the threshold for 10 minutes. Check claude_code_self_hosted_orchestrator_spawn_hooks_total by result, then runner workloads that don't start."
- alert: ClaudeOrchestratorQueueWaitHigh
expr: |
histogram_quantile(0.99, sum by (namespace, le) (
rate(claude_code_self_hosted_orchestrator_session_queue_wait_seconds_bucket[10m])
)) > 160
for: 5m
labels: {severity: warning}
annotations:
summary: "Over 1% of queue waits in the last 10 minutes exceeded 160 seconds. Check whether ClaudeOrchestratorDisconnected is firing, then claude_code_self_hosted_orchestrator_spawn_hooks_total by result and claude_code_self_hosted_orchestrator_spawn_hook_duration_seconds."
- 임계값: 항상 대기 중인 세션이 있다면
ClaudeOrchestratorSessionsWaiting의> 0을 평소에 보이는 수보다 높게 올리십시오 ClaudeOrchestratorDisconnected: 샘플 알림 규칙에서 로드한 상태로 유지하십시오.ClaudeOrchestratorSessionsWaiting은 네임스페이스의 마지막 오케스트레이터 연결이 끊긴 후 약 2분이 지나면 발생을 멈추기 때문입니다
세션 자식 메트릭 전달
각 세션은 자체 OpenTelemetry 메트릭을 가진 별도의 자식 프로세스에서 실행됩니다. --capacity가 1보다 크면 러너는 이러한 자식 메트릭이 노출되는 방식을 재작성합니다. 러너 호스트에 OTEL_METRICS_EXPORTER=prometheus를 설정하고, 예를 들어 래퍼 스크립트나 세션이 상속하는 러너 자체 환경에서 세션 환경에 CLAUDE_CODE_ENABLE_TELEMETRY=1을 설정하면, 각 자식의 카운터 및 게이지 계측값이 러너 자체의 /metrics 엔드포인트에서 러너의 시리즈와 함께 다시 노출됩니다. 러너는 자식의 익스포터를 재작성하여 health 포트의 루프백 전용 수신기로 OTLP를 통해 푸시하도록 하고, 각 시리즈에 session_id 및 client_platform 레이블을 붙이며, 세션이 종료되면 해당 세션의 시리즈를 제거합니다. 히스토그램은 전달되지 않으며, 이름이 러너 자체의 접두사와 충돌하는 자식 메트릭은 삭제됩니다.
기본값인 --capacity 1에서는 재작성이 적용되지 않습니다. 세션의 자식은 평소처럼 포트 9464에 자체 Prometheus 엔드포인트를 바인딩합니다.
세션 메트릭을 러너 메트릭과 조인하기
세션 자체의 메트릭을 claude_code_self_hosted_runner_session_idle_seconds 옆에 나란히 두려면 러너의 session_id를 기준으로 조인하십시오.
--capacity가 1보다 큰 경우: 직접 조인합니다. 러너의/metrics에서 세션의 시리즈는 해당 메트릭과 동일한session_id를session_...형식으로 가집니다.--capacity 1인 경우: 변환된ccr_session_id를 기준으로 조인합니다. 기본적으로 포트 9464의 각 Claude Code 메트릭에는 이 레이블이 있으며, 여기에는cse_...형식의 세션 ID가 들어 있습니다. 새 레이블에서cse_접두사를session_으로 바꾸면 러너의session_id를 얻을 수 있습니다. 메트릭 자체의session_id에는 Claude Code 자체의session.id가 들어 있으며, 이는 어떤 러너 시리즈와도 일치하지 않습니다.
세션 수명 주기 카운터 의미
sessions_started_total, sessions_completed_total, sessions_failed_total, sessions_interrupted_total 카운터는 각 세션을 종료 방식에 따라 분류합니다. 생성된 모든 세션 자식은 생성 시점에 sessions_started_total을 증가시키고, 종료 시점에 나머지 세 개 중 정확히 하나를 증가시킵니다. 따라서 sessions_started_total에서 나머지 세 개의 합을 빼면 현재 실행 중인 세션 자식의 수와 같습니다.
completed: 세션이 정상적으로 종료되었습니다. 여기에는 자식이 코드0으로 스스로 종료한 경우, 자식이 아직 연결되어 있는 동안 세션이 아카이브되거나 삭제된 경우, 그리고 러너가 슬롯을 정상적으로 반환한 경우가 포함됩니다. 슬롯 반환에는 유휴 타임아웃, 은퇴 시간 또는--kill-session-after-min한도에서 세션을 해제하는 경우, 시작 타임아웃, 자식이 종료되기 전에 폴링 루프가 감지한 서버 측 할당 해제가 해당합니다.sessions_completed_total을 증가시킵니다.failed: 자식이 0이 아닌 코드로 스스로 종료되었으며, 이는 크래시이거나 생성 후 설정 실패입니다.sessions_failed_total을 증가시킵니다.interrupted: 러너가 세션 성공도 러너 오류도 아닌 운영상의 이유로 자식을 종료했습니다. 예를 들어 드레인이나,--kill-session-after-min한도 이후의SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS유예 기간이 끝났을 때 여전히 러너에 남아 있던 세션을 종료하는 경우가 해당합니다.SIGTERM을 보내는 Kubernetes 롤링 재시작은 드레인의 한 예입니다.sessions_interrupted_total을 증가시킵니다.
v2.1.260 이전에는 러너가 --kill-session-after-min 한도에 도달한 모든 세션을 종료하고 이를 sessions_interrupted_total에 집계했습니다.
post-session 훅의 CLAUDE_RUNNER_EXIT_REASON은 정상적인 슬롯 반환을 다르게 분류합니다. 러너가 자식을 중지했기 때문에 훅은 해제, 시작 타임아웃, 서버 할당 해제, 폴링이 먼저 감지한 아카이브 또는 삭제를 interrupted로 보고합니다. 이 카운터들은 슬롯이 정상적으로 반환되었기 때문에 같은 이벤트를 completed로 기록합니다.
훅 수신 기록을 sessions_completed_total과 직접 대조하면 완료 수를 적게 집계하게 됩니다. 세션별 보장에는 훅을, 집계 비율에는 카운터를 사용하십시오.
기본값 --drain-grace-sec 0과 함께 --capacity 1을 사용하는 일회성 환경에서는 각 러너 프로세스가 하나의 세션이 끝난 직후 종료됩니다. sessions_completed_total, sessions_failed_total, sessions_interrupted_total은 세션 종료 시점, 즉 그 프로세스 종료 직전에만 증가하므로, 15~60초마다 수행되는 Prometheus 스크레이프가 러너의 시리즈가 사라지기 전에 증가분을 포착하는 경우는 드뭅니다. 이 세 개의 세션 종료 카운터가 이 섹션의 나머지 부분에서 말하는 종료 카운터입니다. sessions_started_total은 생성 시점에 증가하고 세션이 유지되는 동안 계속 보이므로 안정적으로 나타나지만, 일회성 환경에서는 누적 수라기보다는 "현재 실행 중인 세션"에 가까운 값을 나타냅니다.
종료 카운터 대신, 해당 목표에 맞게 다음 표의 시리즈를 사용하십시오.
| 목표 | 사용할 시리즈 |
|---|---|
| 처리량 | claude_code_self_hosted_orchestrator_spawn_hooks_total{result="ok"}: 오래 유지되는 오케스트레이터의 카운터로, spawn-runner 훅이 성공할 때마다 한 번씩 증가하며 rate()에서도 의미 있는 값을 유지합니다. 세션이 아니라 훅 호출을 집계하므로, 사전 워밍과 같은 세션에 대한 반복 생성으로 인해 세션 수와 달라집니다. |
| 사용률 | sum(claude_code_self_hosted_runner_active_sessions) 대 sum(claude_code_self_hosted_runner_capacity): 두 게이지 모두 러너 수명과 관계없이 모든 스크레이프에서 유효합니다 |
| 백로그 | 큐 깊이에는 claude_code_self_hosted_orchestrator_pool_pending_sessions를 사용하고, claude_code_self_hosted_orchestrator_queue_circuit_broken_sessions는 0보다 크면 알림을 보내도록 사용합니다 |
| 실패 | claude_code_self_hosted_runner_sessions_failed_total, 최선의 노력 기준: 생성 후 발생한 실제 크래시는 이 값을 증가시키며, --drain-grace-sec가 0보다 커서 러너가 세션보다 오래 유지되는 경우에는 rate()가 의미 있는 값을 냅니다. 일회성 환경에서는 다른 종료 카운터와 동일한 스크레이프 구간 문제가 있으므로, 0이 아닌 값이 보이면 조사할 가치가 있는 것으로 간주하십시오. checkout 훅 실패, git 준비, 토큰 문제 같은 생성 이전의 실패는 session_init_errors_total에만 나타납니다. |
orchestrator_* 행은 온디맨드 오케스트레이터를 실행하는 환경에만 존재합니다. --drain-grace-sec가 0보다 커서 러너가 세션보다 오래 유지되는 고정 플릿에서는 처리량에 sum(rate(claude_code_self_hosted_runner_sessions_started_total[5m]))를 사용하십시오. 일회성 플릿에서는 이 시리즈도 종료 카운터와 동일한 스크레이프 구간 문제가 있으므로, 대신 대기 중인 세션 수에 의존하십시오. 백로그는 Cloud environments 관리자 페이지에 있는 환경의 Activity 탭에서 확인하십시오. 러너는 큐 깊이 시리즈를 내보내지 않습니다.
세션별 결과 보고에는 대신 post-session 훅을 사용하십시오. 훅 자체의 계약에 따라, 이 훅은 VM 선점 같은 갑작스러운 러너 종료를 제외하고 자식 프로세스가 생성된 모든 세션 종료 시점에 실행됩니다.
다음 단계
- Self-hosted environments: 환경, 러너 및 세션 모델입니다. quickstart 및 Deploy to production은 설정 및 운영을 보유합니다.
- Customize sessions: 래퍼 스크립트, 라이프사이클 훅 및 온디맨드 러너
- Verify session identity: 세션 토큰, 해당 클레임 및 확인 방법