# Docker to Run 2.0 Migration Guide
Run 2.0 is experimental and opt-in. Use `run v2` to access the v2 commands.
This guide helps you migrate from Docker/Docker Compose to Run 2.0.
## Table of Contents
1. [Why Migrate?](#why-migrate)
2. [Migration Strategy](#migration-strategy)
3. [Step-by-Step Migration](#step-by-step-migration)
4. [Command Mapping](#command-mapping)
5. [Architecture Changes](#architecture-changes)
6. [Common Patterns](#common-patterns)
7. [Troubleshooting](#troubleshooting)
## Why Migrate?
| Startup time | 5-10s | <10ms | **500-1000x** |
| Image size | 50-500MB | <5MB | **10-100x** |
| Memory usage | 256MB+ | <10MB | **25x+** |
| Build time | 1-5min | <10s | **6-30x** |
| Cold start | 500ms+ | <10ms | **50x+** |
**Additional Benefits:**
- No Docker daemon required
- Capability-based security (no root)
- Cross-platform (Linux, macOS, Windows)
- Reproducible builds
- Component isolation
- Multi-language interop via WIT
## Migration Strategy
### Phase 1: Hybrid Mode (Recommended Start)
Keep Docker for stateful services (databases, caches), migrate application logic to WASI.
```
Docker Compose -> Run 2.0 Hybrid
App (Docker) -> App (WASI) <10ms
DB (Docker) -> DB (Docker) Keep
Cache -> Cache Keep
```
### Phase 2: Pure WASI (Goal)
Migrate everything to WASI components.
```
Run 2.0 Hybrid -> Run 2.0 Pure
App (WASI) -> App (WASI)
DB (Docker) -> DB (WASI) All WASI
Cache -> Cache
```
## Step-by-Step Migration
### Step 1: Analyze Your Docker Setup
```bash
# Install Run 2.0
# Analyze compose file
cd your-project
run v2 compose analyze docker-compose.yml
```
Output:
```
Services:
OK web-api -> WASI component (can migrate)
OK worker -> WASI component (can migrate)
WARN postgres -> Docker bridge (stateful, keep Docker)
WARN redis -> Docker bridge (stateful, keep Docker)
Recommendation: Hybrid mode (2 WASI + 2 Docker)
Estimated startup: 5s (Docker) + 10ms (WASI)
Estimated size: 128MB (Docker) + 3MB (WASI)
```
### Step 2: Auto-Generate run.toml
```bash
run v2 compose migrate docker-compose.yml run.toml
```
This creates a `run.toml` with:
- Application services as WASI components
- Stateful services as Docker bridge
**Before: docker-compose.yml**
```yaml
version: '3'
services:
web:
build: .
ports:
- "8080:8080"
environment:
DATABASE_URL: postgres://db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
```
**After: run.toml**
```toml
[package]
name = "my-app"
version = "1.0.0"
[[component]]
name = "web"
source = "src/lib.rs"
language = "rust"
wit = "wit/http.wit"
[component.web.env]
DATABASE_URL = "postgres://localhost:5432/mydb"
[bridge.postgres]
image = "postgres:15"
ports = { 5432 = 5432 }
env = { POSTGRES_PASSWORD = "secret" }
```
### Step 3: Convert Application to WASI Component
#### Option A: Rust
```bash
# Install cargo-component
cargo install cargo-component
# Initialize component
cargo component new web --lib
# Write code
cat > src/lib.rs <<'EOF'
wit_bindgen::generate!({
world: "http-handler",
exports: {
"wasi:http/handler": Handler,
},
});
struct Handler;
impl exports::wasi::http::handler::Guest for Handler {
fn handle(request: Request) -> Response {
Response::new(200, b"Hello from Run 2.0!")
}
}
EOF
# Build
cargo component build --release
```
#### Option B: Python
```bash
# Install componentize-py
pip install componentize-py
# Write code
cat > app.py <<'EOF'
def handle_request(request):
return {
"status": 200,
"body": b"Hello from Run 2.0!"
}
EOF
# Build
componentize-py -d http.wit -o app.wasm app.py
```
#### Option C: TypeScript
```bash
# Install jco
npm install -g @bytecodealliance/jco
# Write code
cat > index.ts <<'EOF'
export function handleRequest(request: Request): Response {
return new Response("Hello from Run 2.0!", { status: 200 });
}
EOF
# Build
jco transpile index.ts -o app.wasm
```
### Step 4: Test Hybrid Setup
```bash
# Start dev server
run v2 dev
# Output:
[run] Starting WASI components...
[web] OK Built in 8ms
[run] Starting Docker bridge...
[docker] postgres -> postgres:15
[run] All services ready:
[run] http://localhost:8080 (web)
# Test
curl http://localhost:8080
# Hello from Run 2.0!
```
### Step 5: Deploy
```bash
# Production build
run v2 build --release --reproducible
# Deploy (examples)
run v2 deploy --target local
run v2 deploy --target edge --provider cloudflare
run v2 deploy --target registry
```
## Command Mapping
| `docker-compose up` | `run v2 dev` | <10ms startup for WASI |
| `docker-compose build` | `run v2 build` | <10s builds |
| `docker-compose down` | `run stop` | Stops all components |
| `docker-compose logs` | `run v2 dev` (shows logs) | Unified logs |
| `docker-compose ps` | `run v2 info` | Component status |
| `docker-compose exec` | `run v2 exec` | Execute in component |
| `docker build` | `run v2 build` | No Dockerfile needed |
| `docker run` | `run v2 exec` | Direct execution |
| `docker push` | `run v2 deploy --target registry` | WASI registry |
| `docker pull` | `run v2 install` | Download components |
## Architecture Changes
### Before: Docker Compose
```
docker-compose.yml
|-- Service A (container)
| `-- app.js
|-- Service B (container)
| |-- Dockerfile
| |-- venv/
| `-- app.py
`-- Database (container)
`-- postgres:15
Docker Daemon (required)
|-- Network bridge
|-- Volume management
`-- Container orchestration
```
**Issues:**
- Docker daemon required
- 500MB+ images
- 5-10s startup
- Complex networking
- Root access risks
### After: Run 2.0
```
run.toml
|-- Component A (WASI) <10ms, 2MB
|-- Component B (WASI) <10ms, 3MB
`-- Database (Docker*) 5s, 128MB
Run Runtime (no daemon)
|-- Component Model (WASI 0.2)
|-- Capability security
`-- Direct host process
*Docker bridge optional
```
**Benefits:**
- No daemon needed
- <5MB components
- <10ms startup
- Capability-based security
- Cross-platform
## Common Patterns
### Pattern 1: HTTP Service
**Before (Dockerfile):**
```dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "server.js"]
```
**After (run.toml):**
```toml
[[component]]
name = "api"
source = "src/lib.rs"
language = "rust"
wit = "wit/http.wit"
```
### Pattern 2: Database Connection
**Before:**
```yaml
services:
app:
depends_on:
- db
environment:
DATABASE_URL: postgres://db:5432/mydb
db:
image: postgres:15
```
**After:**
```toml
[[component]]
name = "app"
source = "src/lib.rs"
env = { DATABASE_URL = "postgres://localhost:5432/mydb" }
[bridge.postgres]
image = "postgres:15"
ports = { 5432 = 5432 }
```
### Pattern 3: Multi-service Application
**Before (docker-compose.yml):**
```yaml
services:
frontend:
build: ./frontend
ports: ["3000:3000"]
backend:
build: ./backend
ports: ["8080:8080"]
worker:
build: ./worker
```
**After (run.toml):**
```toml
[[component]]
name = "frontend"
source = "frontend/src/lib.rs"
[[component]]
name = "backend"
source = "backend/src/lib.rs"
[[component]]
name = "worker"
source = "worker/src/lib.rs"
```
All start in <10ms, no containers needed.
### Pattern 4: Environment Variables
**Before:**
```yaml
services:
app:
environment:
NODE_ENV: production
API_KEY: ${API_KEY}
```
**After:**
```toml
[[component]]
name = "app"
env = { NODE_ENV = "production", API_KEY = "${API_KEY}" }
[env.production]
NODE_ENV = "production"
LOG_LEVEL = "info"
```
## Troubleshooting
### Issue 1: "Docker is not available"
If you see this error but have Docker installed:
```bash
# Check Docker is running
docker info
# Enable Docker bridge in run.toml
[bridge]
enabled = true
```
### Issue 2: Port conflicts
```bash
# Error: Port 8080 already in use
# Solution: Change port in run.toml
[[component]]
name = "web"
dev.port = 8081 # Changed from 8080
```
### Issue 3: Missing dependencies
```bash
# Error: Cannot find module 'xyz'
# For Rust: Add to Cargo.toml
[dependencies]
xyz = "1.0"
# For Python: Add to requirements.txt
xyz==1.0.0
# For JS/TS: Add to package.json
{
"dependencies": {
"xyz": "^1.0.0"
}
}
```
### Issue 4: WASI compatibility
Not all code can run in WASI yet. Use Docker bridge for:
- Native dependencies (e.g., `libpq`, `openssl`)
- GPU access
- Kernel modules
- X11/GUI applications
```toml
# Keep these in Docker bridge
[bridge.legacy-service]
image = "my-legacy-app"
```
### Issue 5: Performance regression
If WASI is slower than Docker:
```bash
# Enable release builds
run v2 build --release
# Verbose logs
run v2 dev --verbose
# Check component size
ls -lh target/wasm/*.wasm
# Optimize
[component.my-component]
opt_level = 3
strip_debug = true
```
## Migration Checklist
- [ ] Install Run 2.0
- [ ] Analyze `docker-compose.yml` with `run v2 compose analyze`
- [ ] Generate `run.toml` with `run v2 compose migrate`
- [ ] Convert application code to WASI components
- [ ] Test with `run v2 dev`
- [ ] Verify functionality matches Docker setup
- [ ] Deploy to production
- [ ] (Optional) Remove Docker for pure WASI
## Success Stories
### Case 1: Microservices API
**Before:**
- 5 services in Docker
- 10s startup
- 800MB total images
**After:**
- 5 WASI components
- <10ms startup
- 8MB total size
**Result:** 100x smaller, 1000x faster startup
### Case 2: Serverless Edge
**Before:**
- Node.js Lambda function
- 200MB deployment
- 300ms cold start
**After:**
- WASI component
- 3MB deployment
- <10ms cold start
**Result:** 66x smaller, 30x faster
### Case 3: CI/CD Pipeline
**Before:**
- Docker builds in CI
- 5 min build time
- Non-reproducible
**After:**
- Run 2.0 builds
- <30s build time
- Reproducible (same hash)
**Result:** 10x faster, verifiable
## Next Steps
1. Start with **hybrid mode** (WASI + Docker bridge)
2. Gradually migrate stateful services to WASI
3. Optimize component size and startup time
4. Deploy to edge/serverless if applicable
5. Remove Docker entirely when ready
## Support
- Documentation: https://run.esubalew.et/docs
- Examples: `examples/v2/docker-hybrid/`
- Issues: https://github.com/esubaalew/run/issues