Skip to content

Latest commit

 

History

History
1161 lines (986 loc) · 21.2 KB

File metadata and controls

1161 lines (986 loc) · 21.2 KB

CodeBeaker 사용 가이드

🚀 빠른 시작

1. Docker 이미지 빌드

# Windows
.\scripts\build-runtime-images.ps1

# Linux/Mac
./scripts/build-runtime-images.sh

2. API 서버 실행

방법 1: 개발 환경

# API 서버 실행 (WebSocket + JSON-RPC)
cd src/CodeBeaker.API
dotnet run

방법 2: Docker Compose (프로덕션)

docker-compose up -d

📡 WebSocket 연결

기본 URL

  • Development: ws://localhost:5000/ws/jsonrpc
  • Production: ws://your-domain/ws/jsonrpc

WebSocket 클라이언트 예제

JavaScript (브라우저):

const ws = new WebSocket('ws://localhost:5000/ws/jsonrpc');

ws.onopen = () => {
  console.log('Connected to CodeBeaker');
};

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  console.log('Response:', response);
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

// JSON-RPC 요청 전송
function sendRequest(method, params, id = 1) {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: id,
    method: method,
    params: params
  }));
}

Node.js:

const WebSocket = require('ws');

const ws = new WebSocket('ws://localhost:5000/ws/jsonrpc');

ws.on('open', () => {
  // 세션 생성
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'session.create',
    params: { language: 'python' }
  }));
});

ws.on('message', (data) => {
  const response = JSON.parse(data);
  console.log('Response:', response);
});

Python:

import asyncio
import websockets
import json

async def codebeaker_client():
    uri = "ws://localhost:5000/ws/jsonrpc"
    async with websockets.connect(uri) as ws:
        # 세션 생성
        request = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "session.create",
            "params": {"language": "python"}
        }
        await ws.send(json.dumps(request))
        response = await ws.recv()
        print(json.loads(response))

asyncio.run(codebeaker_client())

🎯 세션 기반 실행 (권장)

세션 기반 실행은 컨테이너를 재사용하여 50-75% 성능 향상을 제공합니다.

1. 세션 생성

요청:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": {
    "language": "python",
    "idleTimeoutMinutes": 30,
    "maxLifetimeMinutes": 120,
    "memoryLimitMB": 512
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "sessionId": "abc123def456",
    "containerId": "xyz789",
    "language": "python",
    "createdAt": "2025-10-27T12:00:00Z",
    "state": "Active",
    "config": {
      "idleTimeoutMinutes": 30,
      "maxLifetimeMinutes": 120
    }
  }
}

2. 파일 작성

요청:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123def456",
    "command": {
      "type": "write_file",
      "path": "/workspace/hello.py",
      "content": "print('Hello, World!')",
      "mode": "Create"
    }
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "success": true,
    "result": {
      "path": "/workspace/hello.py",
      "bytes": 22
    },
    "error": null,
    "durationMs": 45
  }
}

3. 코드 실행

요청:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123def456",
    "command": {
      "type": "execute_shell",
      "commandName": "python3",
      "args": ["/workspace/hello.py"],
      "workingDirectory": "/workspace"
    }
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "success": true,
    "result": {
      "exitCode": 0,
      "stdout": "Hello, World!\n",
      "stderr": "",
      "durationMs": 120
    },
    "error": null,
    "durationMs": 125
  }
}

4. 파일 읽기

요청:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123def456",
    "command": {
      "type": "read_file",
      "path": "/workspace/hello.py"
    }
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "success": true,
    "result": {
      "content": "print('Hello, World!')",
      "bytes": 22
    },
    "error": null,
    "durationMs": 35
  }
}

5. 세션 목록 조회

요청:

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "session.list",
  "params": {}
}

응답:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "count": 1,
    "sessions": [
      {
        "sessionId": "abc123def456",
        "containerId": "xyz789",
        "language": "python",
        "createdAt": "2025-10-27T12:00:00Z",
        "lastActivity": "2025-10-27T12:15:30Z",
        "state": "Idle",
        "executionCount": 3,
        "idleMinutes": 2.5,
        "lifetimeMinutes": 15.5
      }
    ]
  }
}

6. 세션 종료

요청:

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "session.close",
  "params": {
    "sessionId": "abc123def456"
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "sessionId": "abc123def456",
    "closed": true
  }
}

🔥 언어별 사용 예제

Python 예제

const ws = new WebSocket('ws://localhost:5000/ws/jsonrpc');

ws.onopen = async () => {
  // 1. 세션 생성
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'session.create',
    params: { language: 'python' }
  }));
};

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);

  if (response.id === 1) {
    // 세션 생성 완료
    const sessionId = response.result.sessionId;

    // 2. Python 코드 작성
    ws.send(JSON.stringify({
      jsonrpc: '2.0',
      id: 2,
      method: 'session.execute',
      params: {
        sessionId: sessionId,
        command: {
          type: 'write_file',
          path: '/workspace/script.py',
          content: 'for i in range(5):\n    print(f"Count: {i}")'
        }
      }
    }));
  } else if (response.id === 2) {
    // 파일 작성 완료, Python 실행
    const sessionId = 'abc123def456'; // 실제로는 저장된 값 사용

    ws.send(JSON.stringify({
      jsonrpc: '2.0',
      id: 3,
      method: 'session.execute',
      params: {
        sessionId: sessionId,
        command: {
          type: 'execute_shell',
          commandName: 'python3',
          args: ['/workspace/script.py']
        }
      }
    }));
  } else if (response.id === 3) {
    // 실행 완료
    console.log('Output:', response.result.result.stdout);
    // Output: Count: 0\nCount: 1\nCount: 2\nCount: 3\nCount: 4\n
  }
};

JavaScript (Node.js) 예제

// 1. 세션 생성
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": { "language": "javascript" }
}

// 2. JavaScript 코드 작성
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "write_file",
      "path": "/workspace/app.js",
      "content": "const numbers = [1, 2, 3, 4, 5];\nconst sum = numbers.reduce((a, b) => a + b, 0);\nconsole.log(`Sum: ${sum}`);"
    }
  }
}

// 3. Node.js 실행
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_shell",
      "commandName": "node",
      "args": ["/workspace/app.js"]
    }
  }
}

Go 예제

// 1. 세션 생성
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": { "language": "go" }
}

// 2. Go 코드 작성
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "write_file",
      "path": "/workspace/main.go",
      "content": "package main\n\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"Hello from Go\")\n}"
    }
  }
}

// 3. Go 실행
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_shell",
      "commandName": "go",
      "args": ["run", "/workspace/main.go"]
    }
  }
}

C# (.NET) 예제

// 1. 세션 생성
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": { "language": "csharp" }
}

// 2. C# 코드 작성
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "write_file",
      "path": "/workspace/Program.cs",
      "content": "using System;\n\nclass Program\n{\n    static void Main()\n    {\n        Console.WriteLine(\"Hello from C#\");\n    }\n}"
    }
  }
}

// 3. C# 컴파일 및 실행
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_shell",
      "commandName": "dotnet",
      "args": ["script", "/workspace/Program.cs"]
    }
  }
}

Deno Runtime 예제 ⚡ NEW

Deno는 JavaScript/TypeScript용 경량 런타임으로 25배 빠른 시작 속도를 제공합니다.

기본 TypeScript 실행

// 1. 세션 생성 (Deno 런타임)
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": {
    "language": "deno",
    "idleTimeoutMinutes": 30
  }
}

// 2. TypeScript 코드 직접 실행 (ExecuteCodeCommand)
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_code",
      "code": "const greeting: string = 'Hello from Deno!';\nconsole.log(greeting);\nconst sum = (a: number, b: number): number => a + b;\nconsole.log(`Sum: ${sum(10, 20)}`);"
    }
  }
}

// 응답:
// {
//   "jsonrpc": "2.0",
//   "id": 2,
//   "result": {
//     "success": true,
//     "result": "Hello from Deno!\nSum: 30",
//     "durationMs": 50
//   }
// }

파일 기반 실행

// 1. TypeScript 파일 작성
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "write_file",
      "path": "calculator.ts",
      "content": "interface Calculator {\n  add(a: number, b: number): number;\n}\n\nconst calc: Calculator = {\n  add: (a, b) => a + b\n};\n\nconsole.log('Result:', calc.add(15, 25));"
    }
  }
}

// 2. Deno로 TypeScript 실행
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_code",
      "code": "// Import from file\nimport('./calculator.ts');"
    }
  }
}

권한 제어 예제

// 1. 제한된 권한으로 세션 생성
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": {
    "language": "deno",
    "permissions": {
      "allowRead": ["/workspace"],
      "allowWrite": ["/workspace"],
      "allowNet": false,      // 네트워크 차단
      "allowEnv": false       // 환경 변수 접근 차단
    }
  }
}

// 2. 파일 읽기/쓰기 (허용됨)
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_code",
      "code": "await Deno.writeTextFile('/workspace/data.txt', 'Hello!');\nconst content = await Deno.readTextFile('/workspace/data.txt');\nconsole.log(content);"
    }
  }
}

// 3. 네트워크 접근 시도 (차단됨)
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "session.execute",
  "params": {
    "sessionId": "abc123",
    "command": {
      "type": "execute_code",
      "code": "const response = await fetch('https://api.github.com');"
    }
  }
}
// 응답: PermissionDenied: Requires net access to "api.github.com"

성능 비교: Docker vs Deno

// Docker Runtime (기존 방식)
// 세션 생성: ~2000ms
// 코드 실행: ~100ms
// 총 시간: ~2100ms

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": { "language": "javascript" }  // Docker 사용
}

// Deno Runtime (경량 방식)
// 세션 생성: ~80ms
// 코드 실행: ~50ms
// 총 시간: ~130ms (25배 빠름!)

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.create",
  "params": { "language": "deno" }  // Deno 사용
}

AI 에이전트 시나리오

// AI가 10번 연속 코드 실행 요청
for (let i = 0; i < 10; i++) {
  // Docker: ~3초 소요 (환경 생성 오버헤드)
  // Deno: ~1초 소요 (빠른 프로세스 시작)

  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: i,
    method: 'session.create',
    params: { language: 'deno' }
  }));

  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: i + 100,
    method: 'session.execute',
    params: {
      sessionId: sessionId,
      command: {
        type: 'execute_code',
        code: `console.log('Iteration ${i}');`
      }
    }
  }));
}

// 결과: 3배 빠른 응답 속도 🚀

Deno Runtime 장점

특징 Docker Runtime Deno Runtime
시작 시간 2000ms 80ms (25배 빠름)
메모리 사용량 250MB 30MB (8배 적음)
TypeScript 지원 별도 컴파일 필요 네이티브 지원
격리 수준 9/10 (컨테이너) 7/10 (권한 기반)
권한 제어 네트워크/파일 모두 격리 세밀한 권한 제어
추천 용도 복잡한 의존성 빠른 실행, AI 에이전트

📦 Command 타입 상세

1. WriteFileCommand

파일 작성 또는 생성

{
  "type": "write_file",
  "path": "/workspace/file.txt",
  "content": "파일 내용",
  "mode": "Create"
}

모드:

  • Create: 새 파일 생성 (기존 파일 덮어쓰기)
  • Append: 기존 파일에 추가

2. ReadFileCommand

파일 읽기

{
  "type": "read_file",
  "path": "/workspace/file.txt"
}

3. ExecuteShellCommand

Shell 명령 실행

{
  "type": "execute_shell",
  "commandName": "python3",
  "args": ["/workspace/script.py"],
  "workingDirectory": "/workspace"
}

4. CreateDirectoryCommand

디렉토리 생성

{
  "type": "create_directory",
  "path": "/workspace/data"
}

5. CopyFileCommand

파일 복사

{
  "type": "copy_file",
  "sourcePath": "/workspace/file1.txt",
  "destinationPath": "/workspace/file2.txt"
}

6. DeleteFileCommand

파일 삭제

{
  "type": "delete_file",
  "path": "/workspace/file.txt"
}

7. ListDirectoryCommand

디렉토리 목록 조회

{
  "type": "list_directory",
  "path": "/workspace"
}

🎬 실전 시나리오

시나리오 1: 멀티턴 대화 (파일시스템 상태 유지)

// 1. 세션 생성
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 1,
  method: 'session.create',
  params: { language: 'python' }
}));

// 2. 첫 번째 코드 실행 (변수 정의)
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 2,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'write_file',
      path: '/workspace/data.py',
      content: 'x = 10\ny = 20'
    }
  }
}));

// 3. 두 번째 코드 실행 (변수 사용)
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 3,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'write_file',
      path: '/workspace/calc.py',
      content: 'from data import x, y\nprint(f"Sum: {x + y}")'
    }
  }
}));

// 4. 실행
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 4,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'execute_shell',
      commandName: 'python3',
      args: ['/workspace/calc.py']
    }
  }
}));
// Output: Sum: 30

시나리오 2: 패키지 설치 및 사용

// 1. 세션 생성
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 1,
  method: 'session.create',
  params: { language: 'python' }
}));

// 2. pip 패키지 설치
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 2,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'execute_shell',
      commandName: 'pip',
      args: ['install', '--no-cache-dir', 'requests']
    }
  }
}));

// 3. 패키지 사용 코드 작성
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 3,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'write_file',
      path: '/workspace/api_test.py',
      content: 'import requests\nprint("requests version:", requests.__version__)'
    }
  }
}));

// 4. 실행
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 4,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'execute_shell',
      commandName: 'python3',
      args: ['/workspace/api_test.py']
    }
  }
}));

시나리오 3: 데이터 파일 처리

// 1. CSV 데이터 작성
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 1,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'write_file',
      path: '/workspace/data.csv',
      content: 'name,age\nAlice,30\nBob,25\nCharlie,35'
    }
  }
}));

// 2. 데이터 처리 코드
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 2,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'write_file',
      path: '/workspace/process.py',
      content: `
import csv

with open('/workspace/data.csv', 'r') as f:
    reader = csv.DictReader(f)
    total_age = sum(int(row['age']) for row in reader)

print(f"Total age: {total_age}")
`
    }
  }
}));

// 3. 실행
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 3,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'execute_shell',
      commandName: 'python3',
      args: ['/workspace/process.py']
    }
  }
}));

// 4. 결과 파일 읽기
ws.send(JSON.stringify({
  jsonrpc: '2.0',
  id: 4,
  method: 'session.execute',
  params: {
    sessionId: sessionId,
    command: {
      type: 'read_file',
      path: '/workspace/data.csv'
    }
  }
}));

⚙️ 세션 설정 옵션

SessionConfig 파라미터

{
  "language": "python",
  "idleTimeoutMinutes": 30,
  "maxLifetimeMinutes": 120,
  "memoryLimitMB": 512,
  "cpuShares": 1024,
  "dockerImage": "codebeaker-python:latest"
}

파라미터 설명:

  • language: 언어 선택 (python, javascript, go, csharp)
  • idleTimeoutMinutes: 유휴 타임아웃 (기본: 30분)
  • maxLifetimeMinutes: 최대 생명 주기 (기본: 120분)
  • memoryLimitMB: 메모리 제한 (기본: 512MB)
  • cpuShares: CPU 점유율 (기본: 1024)
  • dockerImage: 커스텀 Docker 이미지 (선택 사항)

🔍 에러 처리

에러 응답 형식

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Invalid Request",
    "data": "Additional error details"
  }
}

일반적인 에러 코드

코드 의미 해결 방법
-32600 Invalid Request JSON-RPC 형식 확인
-32601 Method not found 메서드 이름 확인 (session.create, session.execute 등)
-32602 Invalid params 파라미터 형식 확인
-32603 Internal error 서버 로그 확인

명령 실행 에러

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "success": false,
    "result": null,
    "error": "File not found: /workspace/missing.py",
    "durationMs": 15
  }
}

📊 성능 특성

세션 기반 vs 단일 실행

단일 실행 (Stateless):
- Container create: ~200ms
- Code execution: 100-500ms
- Container cleanup: ~100ms
- Total: ~400-800ms

세션 실행 (Stateful):
- First execution: ~400ms (세션 생성)
- Subsequent: ~100-200ms (컨테이너 재사용)
- Improvement: 50-75% faster

최적화 팁

  1. 세션 재사용: 여러 실행이 필요한 경우 세션을 유지하세요
  2. 배치 명령: 여러 명령을 순차적으로 실행하여 왕복 시간 절약
  3. 메모리 관리: 필요한 만큼만 메모리 할당 (기본 512MB)
  4. 세션 정리: 사용 완료 후 session.close로 명시적 종료

🔧 문제 해결

WebSocket 연결 실패

  1. API 서버 실행 확인:
curl http://localhost:5000/health
  1. WebSocket 엔드포인트 확인:
wscat -c ws://localhost:5000/ws/jsonrpc

세션 생성 실패

  1. Docker 이미지 확인:
docker images | grep codebeaker
  1. Docker 서비스 상태:
docker ps
docker info

명령 실행 실패

  1. 세션 상태 확인:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session.list",
  "params": {}
}
  1. 컨테이너 로그 확인:
docker logs <container-id>

세션 자동 종료

세션은 다음 조건에서 자동 종료됩니다:

  • IdleTimeout (기본 30분) 동안 활동이 없는 경우
  • MaxLifetime (기본 120분) 초과

세션 유지 방법:

  • 주기적으로 명령 실행
  • IdleTimeout 값 조정
  • session.list로 세션 상태 모니터링

🛡️ 보안 고려사항

  1. 컨테이너 격리: 각 세션은 독립된 Docker 컨테이너에서 실행
  2. 네트워크 격리: 기본적으로 네트워크 비활성화 (NetworkMode: "none")
  3. 리소스 제한: 메모리와 CPU 제한으로 DoS 방지
  4. 자동 정리: 유휴 세션 자동 종료로 리소스 관리
  5. 파일시스템 격리: /workspace 디렉토리 내부로 제한

📝 라이선스

MIT License - 자유롭게 사용, 수정, 배포 가능