⚠️ Note: This document describes the session/runtime core. The security layers added later are summarized in the project README; this document has not been rewritten around them.
CodeBeaker는 Multi-Runtime 지원 세션 기반 코드 실행 플랫폼으로, WebSocket + JSON-RPC 2.0 프로토콜을 사용하여 실시간 양방향 통신을 제공합니다.
- Multi-Runtime Architecture: 개발환경별 최적 런타임 자동 선택 (Docker, Deno, Bun 등)
- Stateful Execution: 환경 재사용으로 50-75% 성능 향상
- Command Pattern: Type-safe 명령 시스템
- Runtime Abstraction: IExecutionRuntime 인터페이스 기반 확장 가능 설계
- JSON-RPC 2.0: 표준 프로토콜 준수
┌─────────────────────────────────────────────────────────┐
│ WebSocket Client │
│ (Browser / Node.js / Python) │
└───────────────────────┬─────────────────────────────────┘
│
│ JSON-RPC 2.0 over WebSocket
▼
┌─────────────────────────────────────────────────────────┐
│ CodeBeaker API Server │
│ (ASP.NET Core 8 + Kestrel) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ WebSocket Handler │ │
│ │ - Connection management │ │
│ │ - Message framing │ │
│ │ - Keep-alive (2min interval) │ │
│ └────────────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ JSON-RPC Router │ │
│ │ - Method dispatch (reflection-based) │ │
│ │ - Request validation │ │
│ │ - Error handling │ │
│ │ - Notification support │ │
│ └────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────┴──────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Session Handlers │ │ Metadata Handlers│ │
│ │ - create │ │ - language.list │ │
│ │ - execute │ │ - initialize │ │
│ │ - list │ │ │ │
│ │ - close │ │ │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Session Manager │ │
│ │ - ConcurrentDictionary<string, Session> │ │
│ │ - SemaphoreSlim for concurrency control │ │
│ │ - Session lifecycle management │ │
│ │ - Auto cleanup (IdleTimeout: 30min) │ │
│ └────────────────────┬───────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Command Executor │ │
│ │ - Pattern matching dispatch │ │
│ │ - Docker API direct calls │ │
│ │ - 7 command types support │ │
│ └────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌────────────────────┴───────────────────────────────┐ │
│ │ Background Services │ │
│ │ - SessionCleanupWorker (1min interval) │ │
│ │ - Health check monitoring │ │
│ └────────────────────────────────────────────────────┘ │
└───────────────────────┬─────────────────────────────────┘
│
│ Docker API
▼
┌─────────────────────────────────────────────────────────┐
│ Docker Engine │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Session Containers (Long-running) │ │
│ │ - sleep infinity (keep alive) │ │
│ │ - Filesystem persistence │ │
│ │ - Resource limits (Memory: 512MB, CPU: 1024) │ │
│ │ - Network: none (isolated) │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ Runtime Images: │
│ - codebeaker-python:latest (Python 3.12) │
│ - codebeaker-nodejs:latest (Node.js 20) │
│ - codebeaker-golang:latest (Go 1.21) │
│ - codebeaker-dotnet:latest (.NET 8) │
└─────────────────────────────────────────────────────────┘
Phase 4에서 도입된 Multi-Runtime Architecture는 개발환경별로 최적의 런타임을 자동 선택하여 성능과 격리 수준을 최적화합니다.
public enum RuntimeType
{
Docker, // 컨테이너 기반 (강력한 격리)
Deno, // 프로세스 기반 (빠른 시작)
Bun, // 프로세스 기반 (초고속)
NodeJs, // 프로세스 기반 (호환성)
WebAssembly, // WASM 기반 (극한 격리)
V8Isolate, // V8 격리 (경량)
NativeProcess // 네이티브 프로세스
}핵심 추상화 계층:
public interface IExecutionRuntime
{
string Name { get; }
RuntimeType Type { get; }
string[] SupportedEnvironments { get; }
Task<bool> IsAvailableAsync(CancellationToken cancellationToken);
Task<IExecutionEnvironment> CreateEnvironmentAsync(
RuntimeConfig config,
CancellationToken cancellationToken);
RuntimeCapabilities GetCapabilities();
}
public interface IExecutionEnvironment : IAsyncDisposable
{
string EnvironmentId { get; }
RuntimeType RuntimeType { get; }
EnvironmentState State { get; }
Task<CommandResult> ExecuteAsync(Command command, CancellationToken ct);
Task<EnvironmentState> GetStateAsync(CancellationToken ct);
Task CleanupAsync(CancellationToken ct);
}성능 특성 정의:
public sealed class RuntimeCapabilities
{
public int StartupTimeMs { get; set; } // 시작 시간
public int MemoryOverheadMB { get; set; } // 메모리 오버헤드
public int IsolationLevel { get; set; } // 격리 수준 (0-10)
public bool SupportsFilesystemPersistence { get; set; }
public bool SupportsNetworkAccess { get; set; }
public int MaxConcurrentExecutions { get; set; }
}4가지 선택 전략:
| 전략 | 기준 | 선택 알고리즘 |
|---|---|---|
| Speed | 시작 속도 우선 | MIN(StartupTimeMs) |
| Security | 격리 수준 우선 | MAX(IsolationLevel) |
| Memory | 메모리 최소화 | MIN(MemoryOverheadMB) |
| Balanced | 균형 점수 | (속도 + 메모리 + 격리/2) |
var selector = new RuntimeSelector(runtimes);
// 속도 우선 → Deno 선택
var runtime = await selector.SelectBestRuntimeAsync(
"javascript", RuntimePreference.Speed);
// 보안 우선 → Docker 선택
var runtime = await selector.SelectBestRuntimeAsync(
"python", RuntimePreference.Security);JavaScript/TypeScript용 경량 런타임:
- 시작 시간: 80ms (Docker 대비 25배 빠름)
- 메모리: 30MB (Docker 대비 8배 적음)
- 격리: 권한 기반 샌드박스 (7/10)
- TypeScript: 네이티브 지원
// RuntimeConfig에서 권한 설정
{
"Permissions": {
"AllowRead": ["/workspace"],
"AllowWrite": ["/workspace"],
"AllowNet": false,
"AllowEnv": false
}
}
// Deno CLI 인자로 변환
deno run \
--no-prompt \
--allow-read=/workspace \
--allow-write=/workspace \
script.ts- ExecuteCodeCommand: TypeScript/JavaScript 코드 직접 실행
- WriteFileCommand: 파일 생성/수정
- ReadFileCommand: 파일 읽기
- CreateDirectoryCommand: 디렉토리 생성
- ListDirectoryCommand: 디렉토리 목록
| 메트릭 | Docker Runtime | Deno Runtime | 개선 |
|---|---|---|---|
| 시작 시간 | 2000ms | 80ms | 25배 |
| 메모리 | 250MB | 30MB | 8배 |
| 격리 수준 | 9/10 | 7/10 | -2 |
10번 연속 실행:
- Docker: ~3초 (환경 생성 오버헤드)
- Deno: ~1초 (빠른 프로세스 시작)
→ 3배 빠른 응답 속도
향후 추가 예정 런타임:
- Bun Runtime: JavaScript/TypeScript (Deno보다 빠름)
- Wasmer Runtime: WebAssembly (극한 격리)
- V8 Isolate: JavaScript (클라우드 엣지용)
- Native Process: Go, Rust (컴파일 언어)
책임: Stateful 컨테이너 생명주기 관리
- 세션 생성: Docker 컨테이너 시작 (
sleep infinity) - 세션 풀링:
ConcurrentDictionary<string, Session>기반 - 명령 실행: 기존 컨테이너 재사용
- 자동 정리: IdleTimeout (30분), MaxLifetime (120분)
Creating → Active → Idle → Closing → Closed
↑ ↓ ↓ ↓
└────────┴───────┴────────┘
UpdateActivity()
public sealed class SessionManager : ISessionManager
{
private readonly ConcurrentDictionary<string, Session> _sessions;
private readonly DockerClient _docker;
private readonly CommandExecutor _commandExecutor;
private readonly SemaphoreSlim _lock;
public async Task<Session> CreateSessionAsync(SessionConfig config)
{
// 1. Docker 컨테이너 생성 (sleep infinity)
// 2. 컨테이너 시작
// 3. Session 객체 생성 및 풀에 추가
// 4. 세션 ID 반환
}
public async Task<CommandResult> ExecuteInSessionAsync(
string sessionId, Command command)
{
// 1. 세션 조회
// 2. 활동 시각 업데이트
// 3. CommandExecutor로 명령 실행
// 4. 세션 상태를 Idle로 전환
}
public async Task CleanupExpiredSessionsAsync()
{
// 1. 만료된 세션 필터링
// 2. 각 세션에 대해 CloseSessionAsync() 호출
}
}책임: Docker API 직접 호출로 명령 실행
7가지 Command 타입 (JSON 다형성):
| Command | 용도 | Docker API |
|---|---|---|
| WriteFileCommand | 파일 작성 | tee <path> |
| ReadFileCommand | 파일 읽기 | cat <path> |
| ExecuteShellCommand | Shell 실행 | 직접 명령 |
| CreateDirectoryCommand | 디렉토리 생성 | mkdir -p <path> |
| CopyFileCommand | 파일 복사 | cp <src> <dst> |
| DeleteFileCommand | 파일 삭제 | rm -rf <path> |
| ListDirectoryCommand | 목록 조회 | ls -la <path> |
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(WriteFileCommand), typeDiscriminator: "write_file")]
[JsonDerivedType(typeof(ReadFileCommand), typeDiscriminator: "read_file")]
// ... 7개 타입
public abstract class Command
{
public abstract string Type { get; }
public string? Id { get; set; }
}public async Task<CommandResult> ExecuteAsync(
Command command, string containerId)
{
return command switch
{
WriteFileCommand write => await ExecuteWriteFileAsync(write, containerId),
ReadFileCommand read => await ExecuteReadFileAsync(read, containerId),
ExecuteShellCommand shell => await ExecuteShellAsync(shell, containerId),
// ... 7가지 패턴
_ => throw new NotSupportedException($"Command type {command.Type}")
};
}
private async Task<CommandResult> ExecuteWriteFileAsync(
WriteFileCommand cmd, string containerId)
{
// Docker Exec API 사용 (shell 없이!)
var execConfig = new ContainerExecCreateParameters
{
Cmd = new[] { "tee", cmd.Path },
AttachStdin = true,
AttachStdout = true
};
var execResponse = await _docker.Exec.ExecCreateContainerAsync(
containerId, execConfig);
using var stream = await _docker.Exec.StartAndAttachContainerExecAsync(
execResponse.ID, false);
var bytes = Encoding.UTF8.GetBytes(cmd.Content);
await stream.WriteAsync(bytes, 0, bytes.Length);
return CommandResult.Ok(new { path = cmd.Path, bytes = bytes.Length });
}책임: 메서드 디스패칭 및 에러 처리
public sealed class JsonRpcRouter
{
private readonly ConcurrentDictionary<string, IJsonRpcHandler> _handlers;
public void RegisterHandler(IJsonRpcHandler handler)
{
_handlers[handler.Method] = handler;
}
public async Task<JsonRpcResponse?> ProcessRequestAsync(JsonRpcRequest request)
{
// 1. 요청 검증 (jsonrpc: "2.0", method 존재)
// 2. Notification 처리 (id가 없으면 응답 없음)
// 3. 메서드 실행
// 4. 성공/실패 응답 반환
}
}public interface IJsonRpcHandler
{
string Method { get; }
Task<object?> HandleAsync(object? @params, CancellationToken ct);
}Metadata:
- initialize
- language.list
Session:
- session.create
- session.execute
- session.list
- session.close
책임: 언어별 실행 환경 제공
실행 경로는 두 인터페이스로 나뉜다 — 언어 메타데이터(IRuntime)와 실행 환경의 수명주기(IExecutionRuntime / IExecutionEnvironment). 세션 기반 실행이 유일한 실행 모델이며, SessionManager가 후자를 구동한다.
public interface IRuntime
{
string LanguageName { get; } // "python", "javascript", "go", "csharp"
string DockerImage { get; } // "codebeaker-python:latest"
}BaseRuntime은 이 인터페이스의 추상 기반 클래스이고, 언어별 구현은 두 속성만 채운다. 실행 방법을 여기서 기술하지 않는다 — 명령 조립은 CodeBeaker.Commands가, 실행은 아래 실행 환경이 맡는다.
public sealed class PythonRuntime : BaseRuntime
{
public override string LanguageName => "python";
public override string DockerImage => "codebeaker-python:latest";
}language.list / initialize JSON-RPC 메서드는 이 메타데이터만 읽는다.
public interface IExecutionRuntime
{
string Name { get; } // "docker", "deno", "bun"
RuntimeType Type { get; }
string[] SupportedEnvironments { get; }
Task<bool> IsAvailableAsync(CancellationToken ct = default);
Task<IExecutionEnvironment> CreateEnvironmentAsync(RuntimeConfig config, CancellationToken ct = default);
RuntimeCapabilities GetCapabilities();
}RuntimeCapabilities(기동 시간·메모리 오버헤드·격리 수준·네트워크 지원 여부 등)를 RuntimePreference(Speed / Security / Memory / Balanced)와 맞춰 런타임을 고르는 것이 RuntimeSelector다.
선택적 능력 인터페이스: 모든 런타임이 제공할 수 없는 기능은 별도 인터페이스로 표현하고, 지원하는 런타임만 구현한다.
IResourceMonitor— 자원 사용량 조회·위반 판정IReconnectableRuntime— 이미 살아 있는 환경에 다시 붙기. 컨테이너처럼 호스트 프로세스보다 오래 사는 환경만 구현한다(프로세스 기반 런타임은 원리적으로 불가능).
public interface IExecutionEnvironment : IAsyncDisposable
{
string EnvironmentId { get; } // 컨테이너 id 등, 환경 자신의 식별자
RuntimeType RuntimeType { get; }
EnvironmentState State { get; }
Task<CommandResult> ExecuteAsync(Command command, CancellationToken ct = default);
Task<EnvironmentState> GetStateAsync(CancellationToken ct = default);
Task CleanupAsync(CancellationToken ct = default);
Task<ResourceUsage?> GetResourceUsageAsync(CancellationToken ct = default);
}EnvironmentId는 환경 자신의 식별자다 — Docker 런타임에서는 컨테이너 id 그대로이며, 세션 저장소에도 그 값이 실린다. 다른 호스트 인스턴스가 세션을 이어받을 때 이 값만으로 컨테이너에 재연결하므로, 합성 식별자를 쓰면 재연결·정리·조회가 모두 불가능해진다.
Docker 환경은 컨테이너를 sleep infinity로 띄워 두고 명령마다 exec한다 — 그래서 세션 안에서 파일시스템 상태가 유지된다. 컨테이너의 HostConfig는 RuntimeConfig의 ResourceLimits(메모리·CPU 상한)와 PermissionSettings(AllowNet → 네트워크 모드)에서 만들어진다.
public sealed class Session
{
public string SessionId { get; set; } // GUID
public string EnvironmentId { get; set; } // runtime-issued environment id
// (Docker: container id)
public RuntimeType RuntimeType { get; set; } // Docker, Deno, Bun, Node, ...
public string Language { get; set; } // python, javascript, go, csharp
public DateTime CreatedAt { get; set; }
public DateTime LastActivity { get; set; }
public SessionState State { get; set; }
public SessionConfig Config { get; set; }
public Dictionary<string, object> Metadata { get; set; }
public int ExecutionCount { get; set; }
public bool IsExpired(DateTime now)
{
var idleTime = now - LastActivity;
var lifetime = now - CreatedAt;
return idleTime.TotalMinutes > Config.IdleTimeoutMinutes ||
lifetime.TotalMinutes > Config.MaxLifetimeMinutes;
}
}public sealed class SessionConfig
{
public string Language { get; set; }
public string? DockerImage { get; set; }
public int IdleTimeoutMinutes { get; set; } = 30;
public int MaxLifetimeMinutes { get; set; } = 120;
public bool PersistFilesystem { get; set; } = true;
public long? MemoryLimitMB { get; set; }
public long? CpuShares { get; set; }
}public sealed class CommandResult
{
public string? Id { get; set; }
public bool Success { get; set; }
public object? Result { get; set; }
public string? Error { get; set; }
public int DurationMs { get; set; }
public static CommandResult Ok(object? result = null, int durationMs = 0);
public static CommandResult Fail(string error, int durationMs = 0);
}Before (Stateless):
- Container create: ~200ms
- Code execution: 100-500ms
- Container cleanup: ~100ms
- Total: 400-800ms per execution
After (Session):
- First execution: ~400ms (create session)
- Subsequent: ~100-200ms (reuse container)
- Improvement: 50-75% faster
Before (Shell-based):
Request → "/bin/sh -c 'command'" → Parse → Execute
- Shell overhead: ~20-50ms
After (Direct API):
Request → Docker API → Direct Execute
- No shell parsing
- Improvement: ~20% faster
- 세션 풀링:
ConcurrentDictionary기반 - 명령 실행:
SemaphoreSlim동시성 제어 - 자동 정리: Background worker (1분 간격)
var createParams = new CreateContainerParameters
{
Image = dockerImage,
Cmd = new[] { "sleep", "infinity" },
HostConfig = new HostConfig
{
Memory = 512 * 1024 * 1024, // 512MB 제한
CPUShares = 1024, // CPU 제한
NetworkMode = "none", // 네트워크 격리
AutoRemove = false // 수동 관리
}
};- 메모리: 기본 512MB (설정 가능)
- CPU: 기본 1024 shares
- 네트워크: 격리 (
none) - 실행 시간: ExecutionConfig.TimeoutSeconds
- IdleTimeout: 30분 (기본)
- MaxLifetime: 120분 (기본)
- 자동 정리: Background worker
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ API Server 1 │ │ API Server 2 │ │ API Server 3 │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└──────────────────┴──────────────────┘
│
▼
┌─────────────────┐
│ Redis (Sessions)│
└─────────────────┘
- 단일 인스턴스: 세션이 메모리에 저장
- 로컬 Docker: 단일 Docker 엔진
- Redis 기반 세션 스토리지
- 분산 Docker 오케스트레이션
- Kubernetes 배포
- 로드 밸런싱
GET http://localhost:5000/health
- 활성 세션 수
- 평균 실행 시간
- 에러율
- 컨테이너 리소스 사용량
- Serilog 통합 (Console + File)
- 구조화된 로그
- 에러 추적