# Docker Development

> Local Docker development workflow for the Orient. Use when asked to build Docker images, run containers locally, debug container issues, optimize builds, use docker-compose, or troubleshoot containerization problems. Covers per-package Dockerfiles, compose layering, build optimization, and local debugging.

- Skill: `majiayu000/docker-development` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/docker-development`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/docker-development/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/docker-development

---


# Docker Development

## Quick Reference

```bash
# Development mode (hot-reload, uses local code)
./run.sh dev              # Start dev environment
./run.sh dev stop         # Stop services
./run.sh dev logs         # View logs
./run.sh dev status       # Show service status

# Testing mode (full Docker stack)
./run.sh test             # Build and start containers
./run.sh test pull        # Use pre-built images
./run.sh test status      # Check health
./run.sh test stop        # Stop containers
./run.sh test clean       # Remove volumes (fresh start)
```

## Instance Naming Conventions

| Mode             | Container Names | Ports            |
| ---------------- | --------------- | ---------------- |
| Dev (instance 0) | `orienter-*-0`  | 80, 9000, 9001   |
| Test             | `orienter-*`    | 80, 9000, 9001   |
| Instance N       | `orienter-*-N`  | 80+N\*1000, etc. |

## Compose File Layering

```bash
# Base configuration
docker-compose.v2.yml           # Service definitions

# Environment overlays
docker-compose.local.yml        # Local builds
docker-compose.prod.yml         # Production images
docker-compose.staging.yml      # Staging config

# Usage
docker compose -f docker-compose.v2.yml -f docker-compose.local.yml up
```

## Database: SQLite (File-Based)

The Orient uses SQLite for all database operations. No separate database container is needed.

**Database location:**

- Dev mode: `.dev-data/instance-N/orient.db`
- Docker: `/app/data/orient.db` (volume-mounted)

**Environment variables:**

```bash
DATABASE_TYPE=sqlite
SQLITE_DATABASE=/app/data/orient.db
```

## Container Lifecycle

### Starting Containers

```bash
# With build (slow, may hang on metadata)
docker compose --env-file ../.env -f docker-compose.v2.yml -f docker-compose.local.yml --profile slack up -d

# Without build (use existing images)
docker compose --env-file ../.env -f docker-compose.v2.yml -f docker-compose.local.yml --profile slack up -d --no-build
```

### Stopping Containers

```bash
# Stop test stack
./run.sh test stop

# Stop specific containers (dev instance 0)
docker stop orienter-nginx-0 orienter-minio-0
docker rm orienter-nginx-0 orienter-minio-0
```

### Viewing Logs

```bash
docker logs orienter-opencode --tail 100 -f    # Follow logs
docker logs orienter-bot-slack 2>&1 | tail -50 # Last 50 lines
```

### Health Checks

```bash
./run.sh test status    # Quick health overview
docker ps               # Container status
docker inspect --format='{{.State.Health.Status}}' orienter-opencode
```

## Common Issues

### 1. Port Conflicts

**Symptom**: `Bind for 0.0.0.0:9000 failed: port is already allocated`

**Fix**: Stop conflicting containers:

```bash
# Find what's using the port
lsof -i :9000

# Stop dev containers before starting test
docker stop orienter-nginx-0 orienter-minio-0
docker rm orienter-nginx-0 orienter-minio-0
```

### 2. Build Hangs on Metadata Loading (macOS)

**Symptom**: `./run.sh test` hangs at "load metadata for docker.io/library/node:20-alpine"

**Cause**: Docker buildx slow to fetch from Docker Hub.

**Workarounds**:

```bash
# Option 1: Pre-pull images
docker pull node:20-alpine
docker pull node:20-slim

# Option 2: Use existing local images
docker compose ... up -d --no-build

# Option 3: Use ghcr.io images (requires auth)
./run.sh test pull
```

### 3. ECONNRESET During Tests

**Symptom**: E2E tests fail with `fetch failed` / `ECONNRESET`

**Cause**: Container crashed or restarted during test run.

**Debug**:

```bash
# Check container status
docker ps -a | grep opencode

# Check if recently restarted
# Look for "Up X seconds" when tests ran for minutes

# View crash logs
docker logs orienter-opencode 2>&1 | tail -100
```

### 4. Container Won't Start

**Debug steps**:

```bash
# Check exit code
docker ps -a --filter "name=orienter-opencode"

# Check logs for errors
docker logs orienter-opencode 2>&1

# Check if image exists
docker images | grep docker-opencode

# Rebuild single service
docker compose ... build opencode
```

### 5. ghcr.io Authentication

**Symptom**: `./run.sh test pull` fails with 401 Unauthorized

**Fix**:

```bash
# Authenticate to GitHub Container Registry
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
```

### 6. SQLite Database Issues

**Symptom**: Database not persisting or permission errors

**Fix**:

```bash
# Check volume mount
docker inspect orienter-dashboard | grep -A 5 Mounts

# Ensure data directory exists with correct permissions
mkdir -p .dev-data/instance-0
chmod 755 .dev-data/instance-0

# Verify database schema
sqlite3 .dev-data/instance-0/orient.db ".tables"
```

## Switching Between Stacks

**Always stop one stack before starting another:**

```bash
# From dev to test
./run.sh dev stop
./run.sh test

# From test to dev
./run.sh test stop
./run.sh dev
```

## Building Images

```bash
# Build all services
docker compose -f docker-compose.v2.yml -f docker-compose.local.yml build

# Build single service
docker compose -f docker-compose.v2.yml -f docker-compose.local.yml build dashboard

# Build with no cache
docker compose ... build --no-cache opencode

# Build with progress output
docker compose ... build dashboard --progress=plain
```

## Environment Variables

Compose files use `--env-file ../.env` to load environment. Required vars:

- `MINIO_ROOT_USER`, `MINIO_ROOT_PASSWORD`
- `ANTHROPIC_API_KEY`
- `DASHBOARD_JWT_SECRET`
- `ORIENT_MASTER_KEY`
- `SLACK_BOT_TOKEN`, `SLACK_SIGNING_SECRET` (for Slack profile)

## Services Architecture

The Docker stack includes:

| Service   | Purpose                         | Port(s)    |
| --------- | ------------------------------- | ---------- |
| dashboard | Dashboard API + WhatsApp routes | 4098       |
| opencode  | OpenCode API                    | 4099       |
| bot-slack | Slack bot (profile-activated)   | -          |
| minio     | Object storage                  | 9000, 9001 |
| nginx     | Reverse proxy                   | 80         |

**Note:** WhatsApp functionality is integrated into the Dashboard service (single port 4098).

