-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdocker-compose.complete.yml
More file actions
187 lines (173 loc) · 6.71 KB
/
docker-compose.complete.yml
File metadata and controls
187 lines (173 loc) · 6.71 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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# Akashi: Complete local stack — TimescaleDB + Qdrant + Ollama + Akashi.
#
# Requires nothing but Docker. No API keys, no external services.
# Two Ollama models are downloaded on first launch:
# - mxbai-embed-large (~670MB): embeddings for semantic search and conflict detection
# - qwen3.5:9b (~6.6GB): LLM conflict validation (reduces false positives ~93%)
#
# Usage:
# docker compose -f docker-compose.complete.yml up -d
#
# First launch builds the server image from source and downloads both Ollama models.
# Expect 10–20 minutes on first run depending on your machine and network. Track progress:
# docker compose -f docker-compose.complete.yml logs -f ollama-init
#
# The Akashi server starts as soon as the database is ready (~2–3 min).
# Ollama model downloads run in the background; embeddings and conflict validation
# activate automatically once ready.
#
# Open http://localhost:8080 for the audit dashboard (or http://localhost:$AKASHI_PORT if overridden).
services:
# Generate persistent Ed25519 JWT signing keys into ./data on first launch.
# Skipped on subsequent launches if keys already exist.
keygen:
image: alpine:3.21
command: >
sh -c "
apk add --no-cache --quiet openssl &&
mkdir -p /data &&
if [ ! -f /data/jwt_private.pem ]; then
openssl genpkey -algorithm ed25519 -out /data/jwt_private.pem 2>/dev/null &&
openssl pkey -in /data/jwt_private.pem -pubout -out /data/jwt_public.pem 2>/dev/null &&
chown 10001:10001 /data/jwt_private.pem /data/jwt_public.pem &&
chmod 600 /data/jwt_private.pem /data/jwt_public.pem &&
echo 'Generated JWT signing keys in ./data/'
else
echo 'JWT signing keys already exist'
fi
"
volumes:
- ./data:/data
restart: "no"
postgres:
image: timescale/timescaledb-ha:pg18
restart: unless-stopped
environment:
POSTGRES_USER: akashi
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-akashi}
POSTGRES_DB: akashi
volumes:
- pgdata:/var/lib/postgresql/data
- ./docker/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
command: >
postgres
-c shared_buffers=256MB
-c effective_cache_size=768MB
-c wal_buffers=16MB
-c max_wal_size=1GB
-c synchronous_commit=off
-c max_connections=200
healthcheck:
test: ["CMD-SHELL", "PGPASSWORD=$$POSTGRES_PASSWORD psql -h 127.0.0.1 -U $$POSTGRES_USER -d $$POSTGRES_DB -tAc \"SELECT COUNT(*) = 2 FROM pg_extension WHERE extname IN ('vector','timescaledb')\" 2>/dev/null | grep -q t"]
interval: 5s
timeout: 5s
retries: 20
start_period: 10s
qdrant:
image: qdrant/qdrant:v1.13.6
restart: unless-stopped
volumes:
- qdrant_data:/qdrant/storage
healthcheck:
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/127.0.0.1/6333' 2>/dev/null"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
ollama:
image: ollama/ollama
restart: unless-stopped
volumes:
- ollama_data:/root/.ollama
healthcheck:
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/127.0.0.1/11434' 2>/dev/null"]
interval: 10s
timeout: 5s
retries: 6
start_period: 20s
# One-shot: pull both Ollama models into the shared volume.
# Waits for Ollama to be healthy, then pulls each model if not already present.
#
# akashi does NOT depend on this service — it starts immediately after
# postgres and qdrant are ready. Embeddings and conflict validation activate
# automatically once model pulls complete.
ollama-init:
image: alpine:3.21
depends_on:
ollama:
condition: service_healthy
command:
- sh
- -c
- |
apk add --no-cache --quiet curl &&
if curl -sf http://ollama:11434/api/tags | grep -q 'mxbai-embed-large'; then
echo 'mxbai-embed-large already available'
else
echo 'Pulling mxbai-embed-large (~670MB, first launch only)...' &&
curl -sf -X POST http://ollama:11434/api/pull \
-H 'Content-Type: application/json' \
-d '{"model":"mxbai-embed-large","stream":false}' > /dev/null &&
echo 'mxbai-embed-large ready'
fi &&
if curl -sf http://ollama:11434/api/tags | grep -q 'qwen3.5:9b'; then
echo 'qwen3.5:9b already available'
else
echo 'Pulling qwen3.5:9b (~6.6GB, first launch only)...' &&
curl -sf -X POST http://ollama:11434/api/pull \
-H 'Content-Type: application/json' \
-d '{"model":"qwen3.5:9b","stream":false}' > /dev/null &&
echo 'qwen3.5:9b ready'
fi
restart: "no"
akashi:
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
ports:
- "127.0.0.1:${AKASHI_PORT:-8080}:${AKASHI_PORT:-8080}"
environment:
DATABASE_URL: postgres://akashi:${POSTGRES_PASSWORD:-akashi}@postgres:5432/akashi?sslmode=disable
NOTIFY_URL: postgres://akashi:${POSTGRES_PASSWORD:-akashi}@postgres:5432/akashi?sslmode=disable
AKASHI_PORT: ${AKASHI_PORT:-8080}
AKASHI_ADMIN_API_KEY: ${AKASHI_ADMIN_API_KEY:-admin}
AKASHI_LOG_LEVEL: ${AKASHI_LOG_LEVEL:-info}
QDRANT_URL: http://qdrant:6333
QDRANT_COLLECTION: ${QDRANT_COLLECTION:-akashi_decisions}
AKASHI_EMBEDDING_PROVIDER: ollama
AKASHI_EMBEDDING_DIMENSIONS: "1024"
OLLAMA_URL: http://ollama:11434
OLLAMA_MODEL: ${OLLAMA_MODEL:-mxbai-embed-large}
# LLM conflict validation — reduces false positives ~93%.
# qwen3.5:9b is pulled automatically by ollama-init on first launch.
# Override with a smaller model (e.g. qwen2.5:3b) for faster inference.
AKASHI_CONFLICT_LLM_MODEL: ${AKASHI_CONFLICT_LLM_MODEL:-qwen3.5:9b}
AKASHI_JWT_PRIVATE_KEY: /data/jwt_private.pem
AKASHI_JWT_PUBLIC_KEY: /data/jwt_public.pem
AKASHI_JWT_EXPIRATION: ${AKASHI_JWT_EXPIRATION:-24h}
# Hooks API key — set by dev-setup.sh or manually in .env.
AKASHI_HOOKS_API_KEY: ${AKASHI_HOOKS_API_KEY:-}
OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT:-}
OTEL_SERVICE_NAME: ${OTEL_SERVICE_NAME:-akashi}
volumes:
- ./data:/data
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:${AKASHI_PORT:-8080}/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
depends_on:
postgres:
condition: service_healthy
qdrant:
condition: service_healthy
keygen:
condition: service_completed_successfully
# NOT ollama-init: akashi starts independently and activates Ollama embeddings
# automatically once the model pull completes in the background.
volumes:
pgdata:
qdrant_data:
ollama_data: