A docker-managed named volume lives at /var/lib/docker/volumes/, which is INSIDE docker.img (a 200 GB loop file shared with all images, container layers, and every other docker volume on the host). The Plutarch + haskell-nix closure for Liqwid-Labs/agora is tens of GB. Running nix develop against agora ONCE was enough to fill docker.img to 100% (196/200 GB used, 2 GB free). Every container on Lucy was about to start failing writes. Recovery: kill nix process, docker compose down, free 66 GB of BuildKit cache via `docker builder prune -a`, switch /nix to /mnt/cache bind mount (88+ GB free on that pool, completely separate from docker.img). Bind mount caveat: bare bind to an empty host dir shadows the image's /nix install (the previous bug we caught with the named-volume fix). One-time seed required: mkdir -p /mnt/cache/appdata/crafting-table/nix chown 1000:1000 /mnt/cache/appdata/crafting-table/nix docker create --name ct-seed crafting-table:local docker cp ct-seed:/nix/. /mnt/cache/appdata/crafting-table/nix/ docker rm ct-seed After seed, the bind mount works because the host path has the nix tree already populated. Subsequent docker compose up -d picks up the populated /nix and `nix --version` works in-container.
66 lines
2.5 KiB
YAML
66 lines
2.5 KiB
YAML
# crafting-table v0.1 — wave 1 compose (steps 2+3+4 wired in).
|
|
#
|
|
# Default `command` is the API server. To run the per-language smoke after
|
|
# a rebuild, do:
|
|
# docker compose run --rm crafting-table /usr/local/bin/smoke.sh
|
|
#
|
|
# Volumes mount real Lucy appdata paths so /data + /workspace + /caches
|
|
# survive container recreation. Port is bound to LAN only — no Rackham
|
|
# proxy.
|
|
name: crafting-table
|
|
|
|
services:
|
|
crafting-table:
|
|
build: .
|
|
image: crafting-table:local
|
|
container_name: crafting-table
|
|
command:
|
|
- uvicorn
|
|
- crafting_table.server:app
|
|
- --host
|
|
- "0.0.0.0"
|
|
- --port
|
|
- "8810"
|
|
user: crafter
|
|
working_dir: /home/crafter
|
|
# env_file is optional; copy .env.example to .env to override defaults.
|
|
env_file:
|
|
- path: .env
|
|
required: false
|
|
- path: /mnt/cache/appdata/secrets/crafting-table.env
|
|
required: false
|
|
ports:
|
|
- "192.168.0.5:8810:8810"
|
|
volumes:
|
|
- /mnt/user/appdata/crafting-table/data:/data
|
|
- /mnt/user/appdata/crafting-table/workspace:/workspace
|
|
- /mnt/user/appdata/crafting-table/caches:/caches
|
|
# Nix store — bind mount to /mnt/cache (88+ GB free) NOT a bare
|
|
# docker-managed volume. A docker-managed volume lives at
|
|
# /var/lib/docker/volumes/, which is INSIDE the docker.img loop
|
|
# file (200 GB allocated, shared with all images + container layers
|
|
# + every other volume). The Plutarch + haskell-nix closure is
|
|
# tens of GB; running nix develop against Liqwid-Labs/agora once
|
|
# was enough to fill docker.img to 100% and break every container
|
|
# on Lucy. Caught 2026-05-06 mid-build.
|
|
#
|
|
# Bind to /mnt/cache so Plutarch + haskell-nix closures live on
|
|
# the cache pool, not docker.img. Pre-seed the host path with the
|
|
# image's stock /nix install ONCE at container init (or by
|
|
# `docker create + docker cp` when the path is empty) — bare bind
|
|
# mount to an empty host dir shadows the image's /nix install.
|
|
#
|
|
# If the bind path is missing or empty when you `docker compose
|
|
# up -d` for the first time, do this once:
|
|
# mkdir -p /mnt/cache/appdata/crafting-table/nix
|
|
# chown 1000:1000 /mnt/cache/appdata/crafting-table/nix
|
|
# docker create --name ct-seed crafting-table:local
|
|
# docker cp ct-seed:/nix/. /mnt/cache/appdata/crafting-table/nix/
|
|
# docker rm ct-seed
|
|
- /mnt/cache/appdata/crafting-table/nix:/nix
|
|
networks: [sulkta]
|
|
restart: unless-stopped
|
|
|
|
networks:
|
|
sulkta:
|
|
external: true
|