Docker Deployment¶
Schakel publishes pre-built Docker images to the GitHub Container Registry. The Compose file runs both Schakel and Ollama.
Quick Start¶
# Start all services (pulls the image automatically)
make docker-up
# Check logs
make docker-logs
# Stop everything
make docker-down
Using a specific version
By default, compose.yaml uses the latest tag. To pin a version, edit the image reference:
Available tags follow semver: 1.2.3 (exact), 1.2 (latest patch), 1 (latest minor).
Docker Compose¶
The compose.yaml defines two services:
services:
schakel:
image: ghcr.io/ragnarok22/schakel:latest
# build: . # uncomment to build locally instead
ports:
- "8000:8000"
volumes:
- ./config.yaml:/app/config.yaml:ro
- ./.spotify_cache:/app/.spotify_cache
- huggingface-cache:/root/.cache/huggingface
- ./models/piper:/app/models/piper:ro
restart: unless-stopped
depends_on:
- ollama
ollama:
image: ollama/ollama:latest
ports:
- "11434:11434"
volumes:
- ollama-data:/root/.ollama
restart: unless-stopped
volumes:
huggingface-cache:
ollama-data:
Services¶
schakel -- the main application container.
- Exposes port 8000 for the HTTP/WebSocket server.
- Mounts
config.yamlas read-only. - Mounts the Spotify token cache for persistence across restarts.
- Uses a named volume for the HuggingFace cache (Whisper models).
- Mounts the Piper voice models directory as read-only.
ollama -- the local LLM backend.
- Exposes port 11434 for the Ollama API.
- Uses a named volume for model storage.
Volume Mounts¶
| Mount | Purpose |
|---|---|
./config.yaml:/app/config.yaml:ro |
Configuration file (read-only) |
./.spotify_cache:/app/.spotify_cache |
Spotify OAuth token cache |
huggingface-cache:/root/.cache/huggingface |
Whisper STT models (auto-downloaded on first run) |
./models/piper:/app/models/piper:ro |
Piper TTS voice files (read-only) |
ollama-data:/root/.ollama |
Ollama LLM models |
Building Locally¶
If you prefer to build the image yourself instead of using the pre-built one, switch compose.yaml to use a local build:
Then build and start:
Dockerfile¶
The Dockerfile uses a two-stage build for a minimal runtime image:
Stage 1 (Builder) -- uses the uv base image to install dependencies:
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev
COPY app/ app/
Stage 2 (Runtime) -- slim Python image with only runtime dependencies:
FROM python:3.13-slim-bookworm
RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /app/.venv .venv/
COPY --from=builder /app/app app/
ENV PATH="/app/.venv/bin:$PATH"
RUN python -c "import faster_whisper; import openwakeword; import piper"
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
The libgomp1 package is required for OpenMP support (used by faster-whisper). The pre-import step ensures all native libraries load correctly at build time.
Configuration for Docker¶
When running in Docker, adjust the following in config.yaml:
llm:
ollama_url: "http://ollama:11434" # Docker service name, not localhost
audio:
tts_voice: "/app/models/piper/es_ES-davefx-medium.onnx" # Absolute path inside the container
Running Ollama on the host
If you prefer running Ollama on the host machine (e.g., to use a GPU), set ollama_url to your host IP instead of the Docker service name, and remove the ollama service from compose.yaml.
Piper Voice Files¶
Before starting the containers, download the Piper voice model into the mounted directory:
mkdir -p models/piper
cd models/piper
wget https://huggingface.co/rhasspy/piper-voices/resolve/main/es/es_ES/davefx/medium/es_ES-davefx-medium.onnx
wget https://huggingface.co/rhasspy/piper-voices/resolve/main/es/es_ES/davefx/medium/es_ES-davefx-medium.onnx.json
cd ../..
Pulling Ollama Models¶
After starting the containers, pull the required model into the Ollama service:
This only needs to be done once -- the model is persisted in the ollama-data volume.