-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
128 lines (127 loc) · 6.97 KB
/
Copy pathdocker-compose.yml
File metadata and controls
128 lines (127 loc) · 6.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
services:
code-index-api:
image: dvcdsys/code-index:latest
# No container_name on purpose. A fixed name is global to the docker
# daemon, so a second cix on the same host (a Portainer stack, another
# clone, a re-run from a different directory) dies with "the container
# name /code-index is already in use". Compose's own
# <project>-<service>-1 naming keeps them side by side; ask for the real
# name with `docker compose ps` when a command needs it.
restart: unless-stopped
ports:
- "${PORT:-21847}:21847"
environment:
- CIX_API_KEY=${CIX_API_KEY}
# Defense in depth — the image already defaults to 21847 (since
# v0.5.1) but pinning it here keeps the host:container port mapping
# honest if a third-party fork or custom build sets a different
# default.
- CIX_PORT=${CIX_PORT:-21847}
- CIX_EMBEDDING_MODEL=${CIX_EMBEDDING_MODEL:-awhiteside/CodeRankEmbed-Q8_0-GGUF}
# Legacy chromem-go store: read once on startup for the one-time import
# into the SQLite vector store, then left untouched as the rollback path.
- CIX_CHROMA_PERSIST_DIR=/data/chroma
# Optional. Vector store: one SQLite database per embedding namespace.
# Defaults to a sibling of CIX_CHROMA_PERSIST_DIR (/data/vectors), so it
# already lands on the volume below — set it only to move the vectors to
# a different mount.
# - CIX_VECTORS_DIR=/data/vectors
# Optional. PRAGMA mmap_size for the vector store, in bytes; 0 (default)
# is off. Roughly 40% lower search latency in exchange for resident
# memory — mapped database pages count in RSS, per connection. Leave it
# off under the 2G limit below.
# - CIX_VECTOR_MMAP_SIZE=2147483648
- CIX_SQLITE_PATH=/data/sqlite/projects.db
- CIX_MAX_FILE_SIZE=${CIX_MAX_FILE_SIZE:-524288}
- CIX_EXCLUDED_DIRS=${CIX_EXCLUDED_DIRS:-node_modules,.git,.venv,__pycache__,dist,build,.next,.cache,.DS_Store}
# GGUF cache lives on the named volume below — survives `docker compose
# down` (without -v) and is owned by the image's 65532:65532 (nonroot)
# user on the CPU image, so the cix-server process can always write to
# it regardless of host bind-mount permissions.
- CIX_GGUF_CACHE_DIR=/data/models
- CIX_LLAMA_BIN_DIR=/app
- CIX_LLAMA_STARTUP_TIMEOUT=120
- CIX_EMBEDDINGS_ENABLED=${CIX_EMBEDDINGS_ENABLED:-true}
# ── First-boot admin seed (required when the DB has no users yet) ──
# cix-server refuses to start when the users table is empty AND these
# are unset. Set BOTH in your .env, log in once, change the password
# immediately (the user is flagged must_change_password=true).
- CIX_BOOTSTRAP_ADMIN_EMAIL=${CIX_BOOTSTRAP_ADMIN_EMAIL:-}
- CIX_BOOTSTRAP_ADMIN_PASSWORD=${CIX_BOOTSTRAP_ADMIN_PASSWORD:-}
# ── PR-E runtime tunables (all DB-overridable from /dashboard/server) ──
# 0 = auto. Threads → runtime.NumCPU()/2; batch → match n_ctx.
- CIX_LLAMA_THREADS=${CIX_LLAMA_THREADS:-0}
- CIX_LLAMA_BATCH=${CIX_LLAMA_BATCH:-0}
# Embedding queue parallelism. Default 5 (was 1) — pipelines host-side
# prep with device inference. Drop to 1 if you observe contention.
- CIX_MAX_EMBEDDING_CONCURRENCY=${CIX_MAX_EMBEDDING_CONCURRENCY:-5}
- CIX_EMBEDDING_QUEUE_TIMEOUT=${CIX_EMBEDDING_QUEUE_TIMEOUT:-300}
# Optional: skip the first-boot HF download by pointing at a GGUF
# file the operator already has on disk. cix copies it into the
# cix-models named volume once (atomic .partial → rename) and never
# touches the source again. Subsequent boots find the file in cache
# and ignore the env. See volumes block below for an example bind.
- CIX_BOOTSTRAP_GGUF_PATH=${CIX_BOOTSTRAP_GGUF_PATH:-}
# ── Pluggable embedding providers (added in migration 12) ──
# The active provider is selected from the dashboard
# (/dashboard/server → Embedding provider). On first boot with an
# empty runtime_settings row, cix-server seeds the ollama provider
# using the CIX_EMBEDDING_MODEL + CIX_LLAMA_* vars above — so the
# default deployment is unchanged.
#
# To use a remote provider (OpenAI-compatible or Voyage AI) you
# MUST export the API-key env var below. The dashboard reads it on
# every embed call; cix-server NEVER persists API keys in the DB,
# only the env-var NAME a provider should look up. Switching
# providers triggers a full reindex per project on the next clone
# job (existing model-change pipeline).
#
# OpenAI-compatible (api.openai.com, vLLM, TEI, LocalAI, …):
# - CIX_OPENAI_API_KEY=${CIX_OPENAI_API_KEY:-}
#
# Voyage AI:
# - CIX_VOYAGE_API_KEY=${CIX_VOYAGE_API_KEY:-}
volumes:
# Operator-managed bind for sqlite + chroma so backups and inspection
# are one `cd` away on the host. The CPU image runs as
# nonroot:nonroot (uid 65532) — on Linux chown your bind directory to
# 65532:65532 OR add `user: "0:0"` to fall back to root (less safe).
# install-server.sh does the chown for you. See
# doc/SECURITY_DEPLOYMENT.md.
- ${HOME}/.cix/data:/data
# Docker-managed named volume layered ON TOP of /data/models. This
# isolates the GGUF cache from host-side bind permission issues and
# guarantees the model is downloaded exactly once across container
# recreates (`docker compose up --force-recreate`, image bumps, etc.).
- cix-models:/data/models
# Optional bootstrap: bind a host-side .gguf read-only into
# /bootstrap/model.gguf and set CIX_BOOTSTRAP_GGUF_PATH=/bootstrap/model.gguf
# in your .env. cix imports it into the cix-models cache on first boot,
# then ignores both the env and the bind. After verifying the cache is
# seeded, the bind can be removed entirely.
# - /Users/me/.cache/huggingface/hub/.../coderankembed-q8_0.gguf:/bootstrap/model.gguf:ro
deploy:
resources:
limits:
memory: 2G
cpus: "${CPUS:-2.0}"
reservations:
memory: 1G
# /health only answers once the whole boot is done — llama model load
# (minutes from cold) and, on the first start after an upgrade, the
# one-time chromem -> SQLite vector-store import. Failures inside
# start_period do not count, so this window is simply "how long before a
# slow boot may be called broken". Nothing acts on `unhealthy` here
# (restart: unless-stopped reacts to exits, not health), so an over-long
# window costs nothing, while a short one paints the container red mid-boot
# and invites a restart that throws the boot away.
healthcheck:
test: ["CMD", "/cix-server", "-healthcheck"]
interval: 30s
timeout: 10s
start_period: 600s
retries: 3
volumes:
cix-models:
# GGUF model cache. Persisted by Docker; only `docker compose down -v`
# (or explicit `docker volume rm cix_cix-models`) wipes it.