An open API service indexing awesome lists of open source software.

https://github.com/sohaibqasem/dockexec

dockexec is a lightweight Go service to safely execute LLM-generated Python (and other languages) inside Docker. It supports ephemeral & pooled containers, utilization-aware schedulers, configurable resource limits, and optional gVisor integration for stronger isolation.
https://github.com/sohaibqasem/dockexec

docker generated-code go llm python sandbox

Last synced: 3 months ago
JSON representation

dockexec is a lightweight Go service to safely execute LLM-generated Python (and other languages) inside Docker. It supports ephemeral & pooled containers, utilization-aware schedulers, configurable resource limits, and optional gVisor integration for stronger isolation.

Awesome Lists containing this project

README

          

# Dockexec

![Go](https://img.shields.io/badge/Go-1.22+-blue)
![Docker](https://img.shields.io/badge/Docker-ready-blue)
![License](https://img.shields.io/badge/license-MIT-green)
![Version](https://img.shields.io/badge/version-v0.1.0-orange)


Dockexec Logo

**dockexec** is a lightweight Go service to safely run Python (and future languages) inside Docker.
It supports ephemeral one-off containers, pooled warm containers, utilization-aware scheduling, and optional gVisor isolation.

---

## Features

- **Ephemeral execution** → runs each job in a fresh container (isolated but slower).
- **Pooled execution** → reuses warm containers for faster execution.
- **Scheduling modes** → round-robin (default) or utilization-based.
- **Resource limits** → configurable memory, CPU, and network.
- **Log levels** → off, basic, or verbose with container stats.
- **gVisor support** → syscall-level isolation with `runsc` runtime.
- **Cross-platform** → works on Linux, macOS, and Windows.
- **Extensible** → design allows multi-language execution in the future.

---

## Setup

### 1. Install Go dependencies
```bash
go mod tidy
```

### 2. Build the Docker image
```bash
docker build -t python-executor:latest -f docker/Dockerfile .
```

### 3. Run the service
Ephemeral mode:
```bash
EXECUTOR_MODE=docker PORT=9090 DOCKER_IMAGE=python-executor:latest go run main.go
```

Pool mode (3 containers):
```bash
EXECUTOR_MODE=pool POOL_SIZE=3 PORT=9090 DOCKER_IMAGE=python-executor:latest go run main.go
```

---

## Environment Variables

| Variable | Default | Description |
|------------------|--------------------------|--------------------------------------------------|
| `EXECUTOR_MODE` | `docker` | `docker` (ephemeral) or `pool` (container pool). |
| `DOCKER_IMAGE` | `python-executor:latest` | Docker image used for execution. |
| `DOCKER_RUNTIME` | *(unset)* | `runc` (default) or `runsc` (gVisor). |
| `DOCKER_MEMORY` | `256m` | Memory limit per container (ephemeral). |
| `DOCKER_CPUS` | `0.5` | CPU limit per container (ephemeral). |
| `POOL_SIZE` | `3` | Number of containers in pool mode. |
| `POOL_MEMORY` | `256m` | Memory limit per pooled container. |
| `POOL_CPUS` | `0.5` | CPU limit per pooled container. |
| `SCHEDULER_MODE` | `roundrobin` | `roundrobin` (default) or `utilization`. |
| `DEBUG` | *(unset)* | Log level: `true` (basic) or `verbose` (detailed). |
| `PORT` | `8080` | API port. |

---

## API

**POST** `/run`

### Request
```json
{ "code": "print(2+3)" }
```

### Response
```json
{
"jobId": 1756386494986306000,
"stdout": "5\n",
"stderr": "",
"exitCode": 0,
"timeMs": 200
}
```

---

## Example

```bash
curl -X POST localhost:9090/run \\
-H "Content-Type: application/json" \\
-d '{"code":"print(10*10)"}'
```

Response:
```json
{
"jobId": 1756386494986306000,
"stdout": "100\n",
"stderr": "",
"exitCode": 0,
"timeMs": 215
}
```

---

## Scheduling Modes

When using **pooled executor mode**, you can control how jobs are assigned:

- **Round Robin (default)**
Cycles evenly through containers.
```bash
EXECUTOR_MODE=pool SCHEDULER_MODE=roundrobin go run main.go
```

- **Utilization-Based**
Picks the container with the lowest CPU/memory load (via `docker stats`).
```bash
EXECUTOR_MODE=pool SCHEDULER_MODE=utilization go run main.go
```
Slight overhead (~2s polling interval).

---

## Log Levels

Use the `DEBUG` environment variable to control logging:

Basic:
```bash
DEBUG=true PORT=9090 EXECUTOR_MODE=pool go run main.go
```
Example log:
```
[DEBUG] Job 1757649737223951000 → Goroutine 53 → Container py-pool-a (mem=256m, cpu=0.5)
```

Verbose:
```bash
DEBUG=verbose PORT=9090 EXECUTOR_MODE=pool go run main.go
```
Example log:
```
[DEBUG] Job 1757649737223951000 → Utilization snapshot:
- py-pool-a → CPU=0.00%, Mem=0.00 MiB
- py-pool-b → CPU=12.34%, Mem=45.00 MiB
- py-pool-c → CPU=0.50%, Mem=10.50 MiB
[DEBUG] Job 1757649737223951000 → picked py-pool-b (CPU=12.34%, Mem=45.00 MiB)
```

---

## Using gVisor

This executor supports running containers under **gVisor** for syscall-level isolation.

1. Follow the official installation instructions:
https://gvisor.dev/docs/user_guide/install/

2. Verify:
```bash
docker run --rm --runtime=runsc hello-world
```

3. Run with gVisor:
```bash
EXECUTOR_MODE=docker DOCKER_RUNTIME=runsc go run main.go
```

Notes:
- On macOS, requires Colima or another Linux VM.
- Performance impact:
- CPU-heavy jobs → minimal.
- Network/DB/syscall-heavy jobs → noticeable slowdown.

---

## Windows Support

This project works on Windows as well as Linux/macOS.

The executor uses Go’s `os.TempDir()` automatically, so no manual changes are needed.

- **Environment variables**
- **PowerShell**
```powershell
$env:EXECUTOR_MODE="pool"
$env:POOL_SIZE="3"
$env:DOCKER_IMAGE="python-executor:latest"
go run main.go
```
- **CMD**
```cmd
set EXECUTOR_MODE=pool
set POOL_SIZE=3
set DOCKER_IMAGE=python-executor:latest
go run main.go
```
- **Git Bash**
```bash
export EXECUTOR_MODE=pool
export POOL_SIZE=3
export DOCKER_IMAGE=python-executor:latest
go run main.go
```

---

## What's Next

1. **Session Mode** *(optional)*
- Containers mapped 1:1 to users.
- Preserves imports/variables across requests.

2. **Multi-Language Support** *(optional)*
- Add an `EXECUTOR_CMD` env variable (default: `python`).
- Combined with `DOCKER_IMAGE`, this allows execution of Node.js, Ruby, etc.