콘텐츠로 이동

런타임 모드, 어댑터, 리소스 제한

포그라운드 데몬, 게이트웨이 전용 모드, 네이티브·Docker 런타임 어댑터, 데몬 수퍼바이저, 리소스 제한 조정 방법.

이 페이지는 Revka가 어떻게 실행되는지를 설명합니다. 단일 revka 바이너리로 실행할 수 있는 프로세스 모드, 에이전트 셸 명령이 실제로 실행되는 위치(호스트 또는 일회용 Docker 컨테이너)를 결정하는 런타임 어댑터, 데몬의 각 컴포넌트를 유지·관리하는 수퍼바이저, 그리고 현재 조정 가능한 리소스 제한을 다룹니다.

Revka 배포 방식을 결정하거나, 에이전트 명령이 실행되는 샌드박스를 강화하거나, 재시작 루프 또는 “Too many open files” 오류를 해결할 때 이 페이지를 참고하십시오. Revka를 관리형 OS 서비스(launchd / systemd / OpenRC / Windows Task Scheduler)로 설치하는 방법은 백그라운드 서비스로 실행을 참조하십시오. 컨테이너 이미지 및 Compose 설정은 Docker, Compose & 원클릭 PaaS를 참조하십시오.

단일 바이너리로 모든 프로세스 모드를 지원합니다. 배포 환경에 맞는 모드를 선택하십시오.

모드명령어사용 시점
포그라운드 런타임revka daemon로컬 디버깅, 단기 세션, 단일 터미널에서 전체 스택 실행
게이트웨이 전용revka gateway웹훅 엔드포인트 테스트, 채널·크론 없이 대시보드 + REST/WS만 필요할 때
사용자 서비스revka service install && revka service start운영자가 관리하는 영구 런타임
Docker / Podmandocker compose up -d컨테이너화된 배포

처음 두 모드가 이 페이지의 주제입니다. 서비스 및 컨테이너 경로는 백그라운드 서비스로 실행Docker, Compose & 원클릭 PaaS에서 설명합니다.

revka daemon — 완전한 자율 런타임

섹션 제목: “revka daemon — 완전한 자율 런타임”

revka daemon은 프로덕션 진입점입니다. 전체 Revka 런타임을 포그라운드 프로세스로 실행하며, 다음 네 가지 감독 컴포넌트를 함께 구동합니다.

  • 게이트웨이 서버 (임베디드 대시보드 + REST + SSE + WebSocket),
  • 설정된 모든 채널 수퍼바이저 (Telegram, Discord, Slack 등),
  • 하트비트 모니터, 그리고
  • 크론 스케줄러.
Terminal window
revka daemon # use config defaults
revka daemon --port 9090 # gateway on port 9090
revka daemon --host 127.0.0.1 # localhost only (default)
revka daemon --host 0.0.0.0 # all interfaces (requires allow_public_bind = true)
플래그의미
--port / -p설정 파일의 gateway.port를 재정의합니다
--host설정 파일의 gateway.host를 재정의합니다
--config-dir (전역)설정 디렉터리 경로

데몬은 SIGINT 또는 SIGTERM 수신 시 정상적으로 종료됩니다. SIGHUP명시적으로 무시되므로 SSH 또는 터미널 연결이 끊어져도 프로세스가 유지됩니다. SSH로 시작한 뒤 로그아웃해도 데몬은 계속 실행됩니다. Windows에서는 Ctrl+C가 동일한 정상 종료를 트리거합니다.

revka gateway는 임베디드 React 대시보드, REST API, SSE, WebSocket만을 http://127.0.0.1:42617에서 시작합니다. 채널 수퍼바이저, 하트비트, 크론 스케줄러는 포함되지 않습니다. 웹훅 엔드포인트 테스트나 대시보드·API만 필요할 때 사용합니다.

Terminal window
revka gateway
revka gateway start [--host HOST] [--port PORT]
revka gateway restart

기본 호스트는 127.0.0.1이고 기본 포트는 42617입니다. 전체 엔드포인트 목록은 게이트웨이 API 개요를 참조하십시오.

프로세스 모드는 어떤 서브시스템을 실행할지를 결정합니다. 런타임 어댑터에이전트 셸 명령이 어디서 실행될지를 결정합니다. 어댑터는 config.tomlruntime.kind로 선택하며, 프로세스 모드와는 독립적입니다. revka daemon을 네이티브 어댑터 또는 Docker 어댑터 중 하나와 함께 실행할 수 있습니다.

어댑터는 런타임의 기능(셸 접근, 파일시스템 접근, 장기 실행 프로세스 지원, 메모리 예산)을 선언하고, 각 도구 호출에 대한 실제 명령 프로세스를 생성합니다.

네이티브 런타임 어댑터 default

섹션 제목: “네이티브 런타임 어댑터 ”

네이티브 어댑터는 기본 실행 환경입니다. 에이전트 명령을 호스트 OS(macOS, Linux, Windows, Docker 내부, Raspberry Pi)에서 직접 실행하며, 셸과 파일시스템에 완전히 접근할 수 있습니다.

[runtime]
kind = "native"

이것이 기본값이므로, Docker 모드로 전환하지 않는 한 [runtime] 섹션을 완전히 생략해도 됩니다.

속성
runtime.kind"native"
Unix: sh -c, Windows: cmd.exe /C
파일시스템 접근전체
스토리지 경로~/.revka (실행 사용자의 홈 디렉터리)
장기 실행 프로세스지원됨
메모리 예산0 (무제한)

크로스 플랫폼에서 주의해야 할 두 가지 사항이 있습니다.

  • 셸 차이. Unix에서는 명령이 sh -c "<command>"를 통해 실행되고, Windows에서는 cmd.exe /C "<command>"를 통해 실행됩니다. POSIX 셸을 전제로 하는 명령은 Windows에서 동일하게 동작하지 않을 수 있습니다.
  • 이 어댑터에서는 스토리지 경로를 설정할 수 없습니다. 항상 OS 사용자 디렉터리에서 확인된 실행 사용자의 홈 디렉터리 아래 ~/.revka로 고정됩니다. 네이티브 어댑터는 메모리 예산을 0(무제한)으로 보고하며, Revka 자체는 호스트 명령에 메모리 제한을 적용하지 않습니다.

Docker 어댑터는 샌드박스 실행 환경입니다. 모든 에이전트 셸 명령을 설정 가능한 이미지를 대상으로 하는 새로운 docker run --rm 호출로 래핑한 후 컨테이너를 폐기합니다. 이를 통해 읽기 전용 루트 파일시스템, 네트워크 격리, 명령별 메모리/CPU 제한을 제공합니다.

[runtime]
kind = "docker"
[runtime.docker]
image = "alpine:3.20" # default
network = "none" # default — full network isolation
memory_limit_mb = 512 # default
cpu_limit = 1.0 # default
read_only_rootfs = true # default
mount_workspace = true # default
allowed_workspace_roots = [] # default — empty = all paths allowed
타입 / 기본값의미
runtime.docker.imagestring, "alpine:3.20"샌드박스 컨테이너에 사용할 이미지
runtime.docker.networkstring, "none"docker --network에 전달하는 값; "none" = 네트워크 접근 없음
runtime.docker.memory_limit_mbint 또는 null, 512MB 단위 --memory; null(또는 0) = 제한 없음
runtime.docker.cpu_limitfloat 또는 null, 1.0--cpus 값; null(또는 0) = 제한 없음
runtime.docker.read_only_rootfsbool, true--read-only를 전달하여 컨테이너 루트를 읽기 전용으로 마운트
runtime.docker.mount_workspacebool, true호스트 워크스페이스를 /workspace:rw로 마운트
runtime.docker.allowed_workspace_roots경로 목록, []절대 루트 허용 목록; 워크스페이스가 모든 항목의 외부에 있으면 마운트 거부. 비어 있으면 모든 경로 허용

각 명령은 대략 다음과 같이 실행됩니다.

Terminal window
docker run --rm --init --interactive \
--network none \
--memory 512m \
--cpus 1 \
--read-only \
--volume <host-workspace>:/workspace:rw \
--workdir /workspace \
alpine:3.20 \
sh -c "<command>"

주요 동작 및 제한 사항:

  • 장기 실행 프로세스를 지원하지 않습니다. Docker 어댑터는 supports_long_running = false를 보고합니다. 개별 셸 명령을 샌드박싱하기 위한 것이며, 게이트웨이·하트비트·스케줄러를 호스팅하기 위한 용도가 아닙니다. 데몬 자체는 호스트(또는 별도 컨테이너)에서 실행하고, 에이전트가 발행하는 명령을 샌드박싱할 때만 이 어댑터를 사용하십시오.
  • 스토리지 경로는 워크스페이스가 마운트된 경우 /workspace/.revka, 그렇지 않으면 /tmp/.revka입니다.
  • 메모리 예산memory_limit_mb를 바이트로 변환하여 보고되므로, 에이전트가 버퍼링을 조정할 수 있습니다.

팩토리 함수 create_runtimeruntime.kind를 기반으로 어댑터를 선택합니다. 지원되는 값은 "native""docker"입니다. 실패를 명확하게 파악할 수 있도록, 그 외의 값에 대해서는 명시적 오류를 반환합니다.

  • runtime.kind = "cloudflare"예약되어 있으나 구현되지 않은 값으로, 다음 메시지와 함께 실패합니다: “runtime.kind=‘cloudflare’ is not implemented yet. Use runtime.kind=‘native’ for now.”
  • 빈 값은 다음 메시지와 함께 실패합니다: “runtime.kind cannot be empty. Supported values: native, docker”
  • 그 외 값은 다음 메시지와 함께 실패합니다: “Unknown runtime kind ‘<value>’. Supported values: native, docker”

어댑터를 지정하는 CLI 플래그는 없습니다. config.toml을 통해서만 제어됩니다.

revka daemon 내에서 네 가지 컴포넌트(게이트웨이, 채널, 하트비트, 스케줄러) 각각은 수퍼바이저로 래핑된 자체 태스크에서 실행됩니다. 컴포넌트가 오류로 충돌하거나 정상적으로 반환되거나 관계없이 종료되면, 수퍼바이저는 지수 백오프를 적용하여 재시작합니다.

[reliability]
channel_initial_backoff_secs = 1 # default — first retry delay (min 1)
channel_max_backoff_secs = 60 # default — cap; must be >= initial
타입 / 기본값의미
reliability.channel_initial_backoff_secsint, 1첫 번째 재시작 시도 전 대기 시간. 최소 1초
reliability.channel_max_backoff_secsint, 60백오프 상한값. 초기값보다 낮게 설정하면 초기값으로 상향 조정됨

백오프 진행 방식:

  1. 컴포넌트가 실행됩니다. 종료 시 수퍼바이저는 재시작 횟수와 마지막 오류를 헬스 스냅샷에 기록합니다.
  2. 현재 백오프 시간 동안 대기한 후, 다음 시도를 위해 대기 시간을 두 배로 늘립니다(channel_max_backoff_secs를 초과하지 않음).
  3. 정상 종료(컴포넌트가 Ok를 반환)도 예기치 않은 것으로 처리됩니다. 데몬이 실행 중인 동안 어떤 컴포넌트도 종료되어서는 안 되기 때문입니다. 단, 정상 종료는 백오프를 초기값으로 리셋하고, 오류 종료는 계속 백오프를 늘립니다.

데몬이 실행 중인 동안 모든 컴포넌트 헬스의 JSON 스냅샷을 5초마다 config.toml 옆에 위치한 daemon_state.json에 기록합니다.

<config_dir>/daemon_state.json

각 기록에는 written_at RFC 3339 타임스탬프와 컴포넌트별 헬스 스냅샷이 포함됩니다. 이 파일은 두 가지 목적으로 사용됩니다.

  • 외부 활성 모니터링. 운영자가 이 파일을 감시할 수 있습니다. 스냅샷이 45초 이상 오래된 경우 데몬이 종료된 것을 의미합니다. 이것이 Revka 자체가 사용하는 신선도 임계값입니다.
  • Windows 프로세스 감지. Windows Task Scheduler는 안정적으로 조회할 수 없으므로, revka service startrevka service status는 이 파일을 읽어(그리고 기록된 PID가 살아있는지 확인하여) 직접 데몬 폴백이 이미 실행 중인지 감지합니다.
Terminal window
# Inspect the latest daemon health snapshot
cat ~/.revka/daemon_state.json

상태 파일은 운영 런북의 표준 헬스 신호 중 하나입니다.

신호명령어 / 파일예상 상태
설정 유효성revka doctor치명적 오류 없음
채널 연결성revka channel doctor설정된 채널이 정상
런타임 요약revka status예상 프로바이더 / 모델 / 채널
데몬 하트비트 / 상태~/.revka/daemon_state.json파일이 주기적으로 업데이트됨 (45초 미만)
게이트웨이 / 대시보드GET http://127.0.0.1:42617/health200 OK

현재 Revka는 두 가지 위치에서 구체적인 리소스 제한을 적용합니다. 관리형 서비스의 파일 디스크립터 제한과 Docker 런타임 어댑터의 메모리/CPU 제한입니다. 프로세스 전체에 대한 더 광범위한 리소스 제한은 로드맵 항목입니다(아래 참조).

Revka가 실행하는 각 MCP 서버는 파일 디스크립터를 소비합니다. 사이드카와 채널이 많이 실행되면 기본 소프트 제한(launchd의 경우 256)이 쉽게 소진되어 “Too many open files” 오류가 발생합니다. 관리형 서비스는 데몬 프로세스의 디스크립터 제한을 다음과 같이 높입니다.

제한
소프트 NOFILE4096
하드 NOFILE8192

Revka를 서비스로 설치하면 자동으로 적용됩니다.

  • macOS (launchd): 생성된 com.revka.daemon.plistNumberOfFiles에 대해 SoftResourceLimits / HardResourceLimits4096 / 8192로 설정합니다.
  • Linux (systemd): 사용자 유닛이 LimitNOFILE=4096:8192를 설정합니다.
  • Linux (OpenRC): init 스크립트가 rc_ulimit="-n 4096"을 선언합니다.

서비스를 사용하지 않고 revka daemon을 직접 실행하는 경우, Unix에서 실행 전에 직접 제한을 높이십시오.

Terminal window
ulimit -n 4096
revka daemon

Docker 런타임 어댑터가 활성화된 경우, 각 샌드박싱된 명령은 runtime.docker에 의해 제한됩니다.

[runtime.docker]
memory_limit_mb = 512 # passed as docker --memory 512m
cpu_limit = 1.0 # passed as docker --cpus 1
  • memory_limit_mbdocker run --memory <mb>m에 대응합니다. null 또는 0으로 설정하면 플래그가 생략됩니다(메모리 제한 없음).
  • cpu_limitdocker run --cpus <value>에 대응합니다. null 또는 0으로 설정하면 플래그가 생략됩니다(CPU 제한 없음).

이 제한은 명령별로 적용됩니다(각 명령이 자체 docker run --rm). 장기 실행 데몬에는 적용되지 않습니다. Compose 배포에서 전체 컨테이너를 제한하려면 Compose 레벨 리소스 제한을 사용하십시오. Docker, Compose & 원클릭 PaaS를 참조하십시오.

프로세스 전체 리소스 제한 roadmap

섹션 제목: “프로세스 전체 리소스 제한 ”

runtime.docker.allowed_workspace_roots는 Docker 어댑터의 워크스페이스 마운트 보호 장치입니다. 절대 디렉터리 루트의 허용 목록으로, 워크스페이스 경로가 목록의 항목 중 하나 내에 있을 때만 허용됩니다.

[runtime.docker]
mount_workspace = true
allowed_workspace_roots = ["/srv/revka/workspaces", "/home/agent/work"]
  • 빈 목록(기본값): 모든 경로가 허용됩니다. 개발 환경에서는 편리하지만, 에이전트가 확인하는 모든 워크스페이스 경로가 샌드박스에 읽기·쓰기로 마운트될 수 있습니다.
  • 비어있지 않은 목록: 워크스페이스가 나열된 루트 중 하나로 시작해야 합니다. 그렇지 않으면 거부된 경로를 명시한 오류와 함께 마운트가 거부됩니다.
  • 파일시스템 루트(/)는 항상 거부됩니다. 이 설정에 관계없이 전체 호스트 마운트를 방지합니다.

이것은 공유 또는 프로덕션 호스트에서 조작된 워크스페이스 경로를 통한 권한 상승을 방지하는 주요 수단입니다. 엄격하게 제한된 샌드박스를 구성하려면 read_only_rootfs = truenetwork = "none"(모두 기본값)과 함께 사용하십시오.