Sprint 4 deployment artifacts: Dockerfile + docker-compose
Parallel deploy target to the systemd units that landed in a59ef5b.
Single image carries all 11 daemons; docker-compose runs one
container per daemon with the same dependency graph as the systemd
units. Useful when systemd isn't available (Mac dev, remote VMs
without root) or when isolation to a private docker network is
preferred.
Dockerfile (multi-stage):
- Builder: golang:1.25-bookworm. DuckDB cgo needs gcc + glibc;
alpine's musl doesn't link the official duckdb-go bindings cleanly.
- Runtime: debian:bookworm-slim — same libc, much smaller surface.
Adds ca-certificates (outbound HTTPS to OpenRouter/OpenCode/Kimi),
curl + jq (in-container healthchecks + smoke probes), tini (PID 1
signal forwarding so docker stop sends SIGTERM to the daemon, not
to a wrapper).
- Single image, multiple binaries. Ships all 11 cmd/* + 3 scripts/
(staffing_workers, playbook_lift, multi_coord_stress) so deployed
stacks can run reality tests against themselves.
- Non-root runtime user (uid 999 lakehouse). Layout matches
/usr/local/bin/lakehouse/<daemon> from REPLICATION.md.
- ENTRYPOINT=tini; no default CMD — operators / compose pick
which daemon explicitly.
docker-compose.yml (11 services):
- Same dependency graph as deploy/systemd/. depends_on with
service_healthy condition matches Requires= equivalents:
catalogd → storaged
ingestd → storaged + catalogd
queryd → catalogd
matrixd → embedd + vectord
- Gateway uses bare depends_on (no health condition) — Wants=
equivalent so single-upstream restart doesn't cascade.
- chatd has per-provider env_file entries (one each for
ollama_cloud, openrouter, opencode, kimi) — missing files are
silently OK, matching the systemd unit's EnvironmentFile=- list.
- Persistent state on the lakehouse-state named volume; commented
driver_opts shows how to bind to a host path for off-volume
backups.
.dockerignore:
- Excludes bin/ + reports/ + data/ + git metadata + .env files.
- Especially excludes lakehouse.toml/secrets-go.toml/auth.env so
local dev configs don't accidentally bake into a published image.
REPLICATION.md gains a Docker section between systemd setup and
the logs section. Ten-line copy-paste from "git clone" to
"docker compose up -d", plus a docker-vs-systemd differences
table covering process supervision, logs, restart policy, file
ownership, host networking quirks, and backup targets.
Validation: docker compose config --quiet → exit 0 (with
placeholder env files in place).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -149,6 +149,60 @@ sudo sed -i "s|^AUTH_SECONDARY_TOKEN=.*|AUTH_SECONDARY_TOKEN=|" /etc/lakehouse/a
|
||||
sudo systemctl restart lakehouse-go.target
|
||||
```
|
||||
|
||||
## Docker / docker-compose deploy (alternative to systemd)
|
||||
|
||||
The single-image `Dockerfile` carries all 11 daemons; `docker-compose.yml`
|
||||
runs one container per daemon with the same dependency graph as the
|
||||
systemd units. Useful when the host doesn't have systemd (Mac dev
|
||||
boxes, remote VMs without root) or when you want all of Lakehouse-Go
|
||||
isolated to a private docker network.
|
||||
|
||||
```bash
|
||||
# Build the image (multi-stage; ~3 min on first build, ~30s with
|
||||
# cached go module download).
|
||||
docker build -t lakehouse-go:latest .
|
||||
|
||||
# Place config + secrets next to docker-compose.yml. The compose file
|
||||
# bind-mounts these into every container at /etc/lakehouse/.
|
||||
cp lakehouse.toml lakehouse.toml # already in repo; edit if needed
|
||||
cp deploy/etc-lakehouse/secrets-go.toml.example secrets-go.toml
|
||||
chmod 0600 secrets-go.toml
|
||||
cp deploy/etc-lakehouse/auth.env.example auth.env
|
||||
chmod 0600 auth.env
|
||||
# Per-provider chatd keys (each its own file so missing == provider
|
||||
# unregistered, NOT chatd startup failure):
|
||||
for p in ollama_cloud openrouter opencode kimi; do
|
||||
echo "${p^^}_API_KEY=" > $p.env
|
||||
chmod 0600 $p.env
|
||||
done
|
||||
|
||||
# $EDITOR each file to fill in real values...
|
||||
|
||||
# Bring up the stack.
|
||||
docker compose up -d
|
||||
docker compose ps # all 11 services Healthy
|
||||
docker compose logs -f gateway
|
||||
|
||||
# Validate via the gateway like the systemd path.
|
||||
curl -sS http://127.0.0.1:3110/v1/chat/providers | jq
|
||||
|
||||
# Tear down.
|
||||
docker compose down
|
||||
# State volume (pathway/observer JSONLs) survives `down`. To wipe:
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
### Key docker-vs-systemd differences
|
||||
|
||||
| Concern | systemd | docker-compose |
|
||||
|---|---|---|
|
||||
| Process supervision | systemd | tini + docker daemon |
|
||||
| Logs | journald | `docker logs` (or routed to a sink via logging driver) |
|
||||
| Restarts on failure | `Restart=on-failure` | `restart: unless-stopped` |
|
||||
| File ownership | `User=lakehouse` (uid varies) | `user: 999:999` (uid is fixed in the image) |
|
||||
| Reaches MinIO/Ollama | host network | host's address from inside the bridge network — typically `host.docker.internal` (Mac/Win) or `172.17.0.1` (Linux). Set `[s3].endpoint` + `[embedd].provider_url` accordingly. |
|
||||
| Backup target | `/var/lib/lakehouse/` on host | the `lakehouse-state` named volume; bind to a host path via the commented-out `driver_opts` in compose if needed |
|
||||
|
||||
## Logs
|
||||
|
||||
systemd routes everything to journald with per-daemon SyslogIdentifier:
|
||||
|
||||
Reference in New Issue
Block a user