Migrating from Docker
If you’re coming from Docker, this guide helps you translate concepts and migrate your workloads.
Concept Mapping
Section titled “Concept Mapping”| Docker | tenement | Notes |
|---|---|---|
| Dockerfile | Your app code | No container images needed |
| docker-compose.yml | tenement.toml | Similar structure, simpler |
| Container | Instance | Running process |
| Image | Command | Just the executable |
| Volume | data_dir | Persistent storage |
| Network | (automatic) | tenement handles routing |
| Port mapping | PORT env var | Auto-allocated |
| Health check | health = “/health” | Same concept |
Migration Steps
Section titled “Migration Steps”1. Extract Your App
Section titled “1. Extract Your App”From Docker:
FROM python:3.11WORKDIR /appCOPY . .RUN pip install -r requirements.txtCMD ["python", "app.py"]To tenement:
# Just run directly with your package manageruv run python app.py# or: bun run server.tsKey point: No container image. Your app runs directly on the host with its dependencies.
2. Convert docker-compose.yml
Section titled “2. Convert docker-compose.yml”From docker-compose:
version: "3"services: api: build: . ports: - "3000:3000" environment: - DATABASE_URL=postgres://... healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] deploy: resources: limits: memory: 256MTo tenement.toml:
[service.api]command = "uv run python app.py"health = "/health"memory_limit_mb = 256
[service.api.env]DATABASE_URL = "postgres://..."3. Update Your App
Section titled “3. Update Your App”Before (Docker): Hardcoded port
app.run(host="0.0.0.0", port=3000)After (tenement): Read from PORT
import osport = int(os.getenv("PORT", "3000"))app.run(host="127.0.0.1", port=port)Key changes:
- Read
PORTfrom environment (tenement sets it) - Bind to
127.0.0.1not0.0.0.0(tenement handles external access)
What You Lose
Section titled “What You Lose”| Docker Feature | tenement Alternative |
|---|---|
| Container images | Pre-install deps, use uv/bun/nix |
| Image registry | Deploy binaries directly |
| Layer caching | Not needed (no build step) |
| Compose networks | Localhost + routing |
docker exec | ten health, API logs |
| Multi-arch images | Build for target arch |
What You Gain
Section titled “What You Gain”| Benefit | Why |
|---|---|
| Faster startup | No container overhead |
| Less memory | ~20MB vs ~50-100MB per container |
| Simpler debugging | No container abstraction |
| Native performance | Syscalls go directly to kernel |
| Smaller footprint | No Docker daemon |
| Scale-to-zero | Built-in idle timeout |
Common Patterns
Section titled “Common Patterns”Multi-Service (formerly docker-compose)
Section titled “Multi-Service (formerly docker-compose)”services: api: build: ./api ports: ["3000:3000"] worker: build: ./worker[service.api]command = "uv run python api/app.py"health = "/health"
[service.worker]command = "./worker/worker"health = "/health"
[instances]api = ["prod"]worker = ["bg-1", "bg-2"]Environment Files
Section titled “Environment Files”services: api: env_file: .env[service.api.env]DATABASE_URL = "${DATABASE_URL}" # From host environmentSECRET_KEY = "${SECRET_KEY}"Load with: source .env && ten serve
Volumes / Persistent Data
Section titled “Volumes / Persistent Data”services: api: volumes: - ./data:/app/data[settings]data_dir = "./data"
[service.api]storage_persist = true
[service.api.env]DATA_PATH = "{data_dir}/{id}"Deployment Workflow
Section titled “Deployment Workflow”Docker
Section titled “Docker”docker build -t myapp .docker push registry.example.com/myapp:v2docker-compose up -dtenement
Section titled “tenement”# Build locally (if compiled)cargo build --release# or just deploy code directly
# Deployrsync -avz ./app server:/opt/myapp/ssh server "ten deploy api --version v2"Q: Do I need to rewrite my Dockerfile?
A: No Dockerfile needed. Just ensure your app reads PORT from environment.
Q: What about my CI/CD pipeline? A: Skip the image build step. Deploy code directly via rsync, git pull, or your preferred method.
Q: Can I use container images with tenement? A: No. tenement runs processes, not containers. Extract your app from the container.
Q: What about Docker secrets? A: Use environment variables. For production, inject secrets at runtime (Vault, Doppler, etc.).
Next Steps
Section titled “Next Steps”- Quick Start - Get running in 5 minutes
- Configuration Reference - Full config options
- Production Deployment - TLS and systemd setup