Skip to content

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:

image: ghcr.io/ragnarok22/schakel:1.2.3

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.yaml as 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:

services:
  schakel:
    # image: ghcr.io/ragnarok22/schakel:latest
    build: .

Then build and start:

make docker-build
make docker-up

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:

docker compose exec ollama ollama pull llama3:8b

This only needs to be done once -- the model is persisted in the ollama-data volume.