Docker Architecture & Build Caching¶
This page describes LLARS' Docker build strategy and how layer caching works.
Overview¶
LLARS consists of 17 Docker services. 9 are built locally, the rest use official images.
graph TD
subgraph "Locally Built Images"
FLASK["Flask Backend<br/>14 GB"]
VUE["Vue Frontend<br/>1.5 GB"]
YJS["YJS Server<br/>420 MB"]
NGINX["Nginx<br/>92 MB"]
SUPER["Supervisor<br/>280 MB"]
MKDOCS["MkDocs<br/>276 MB"]
MARIA["MariaDB x2<br/>528 MB"]
LKAGENT["LiveKit Agent<br/>500 MB"]
end
subgraph "Official Images"
AUTH["Authentik Server/Worker"]
PG["PostgreSQL"]
REDIS["Redis x2"]
MATOMO["Matomo"]
LK["LiveKit Server"]
end
Start Commands¶
| Command | What happens | When to use |
|---|---|---|
./start_llars.sh |
Starts containers with existing images. No build, no Dockerfile check. | Default. Code changes come via volume mounts. |
./start_llars.sh --build |
Docker checks all Dockerfiles. Unchanged layers come from cache, only changed layers are rebuilt. | After changes to requirements.txt, package.json, Dockerfiles, or docker-compose.yml. |
./start_llars.sh --update |
Rebuilds only backend + frontend and restarts them. Other services keep running. | Quick update after Dockerfile change to Flask or Vue. |
Additional Flags¶
| Flag | Description |
|---|---|
--detach |
Start in background (no Docker Watch) |
dev / prod |
Force development or production mode |
Variables¶
| Variable | Description |
|---|---|
REMOVE_LLARS_VOLUMES=True |
Deletes all LLARS data and automatically forces --build |
PRUNE_LLARS_SYSTEM=True |
Deletes all LLARS containers, images, volumes and build cache |
Layer Caching Strategy¶
Docker builds images in layers. Each RUN, COPY, or ADD instruction creates a layer. If a layer hasn't changed, it's taken from the cache. Once a layer changes, all subsequent layers are also rebuilt.
That's why ordering matters: rarely changed things first, frequently changed things last.
Flask Backend (14 GB)¶
The backend has the most complex layer structure:
Layer 1: texlive-full (~5 GB) ← Almost never changes
Layer 2: System packages (~200 MB) ← Rarely changes
Layer 3: Heavy ML packages (~4 GB) ← torch, transformers, flair, chromadb
(requirements-heavy.txt) Changes very rarely
Layer 4: Python packages (~500 MB) ← requirements.txt
(with BuildKit cache mount) Changes occasionally
Layer 5: Playwright Chromium (~300 MB) ← Rarely changes
Layer 6: App code (~500 MB) ← Changes frequently
Effect: A code change only rebuilds Layer 6 (~seconds). A dependency change rebuilds Layers 4+6. texlive-full and ML packages stay cached.
Vue Frontend (1.5 GB)¶
Layer 1: Start scripts ← Almost never changes
Layer 2: npm ci (~400 MB) ← Only on package.json change
(with BuildKit cache mount)
Layer 3: Source code ← Changes frequently
YJS Server (420 MB)¶
Identical strategy to Vue.
BuildKit Cache Mounts¶
All Dockerfiles use BuildKit cache mounts:
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
RUN --mount=type=cache,target=/root/.npm \
npm ci
Advantage: Even when requirements.txt changes, only changed packages are downloaded. The pip/npm download cache persists between builds.
Build Context (.dockerignore)¶
The build context is what Docker sends to the daemon when building. Everything in the project directory not listed in .dockerignore is transferred.
Current size: ~1.3 GB (reduced from 6.8 GB via .dockerignore)
Excluded large directories:
| Directory | Size | Reason |
|---|---|---|
docs/docs/projekte/anonymize/models/ |
2.1 GB | Mounted via volume |
app/data/rag/ |
638 MB | Runtime data |
Paper/ |
430 MB | Not needed for builds |
app/models/oncoco/model.safetensors |
2.1 GB | Mounted via volume |
llars-frontend/node_modules |
varies | Installed in container |
yjs-server/node_modules |
22 MB | Installed in container |
npm install at Startup¶
In development mode, Docker mounts the host directory (./llars-frontend:/vue), which overwrites the node_modules installed in the image. The start scripts check if a re-install is needed:
# start_vue.sh / start_yjs.sh
if [ ! -d node_modules ] || [ ! -f node_modules/.package-lock.json ]; then
npm install # node_modules missing
elif [ package-lock.json -nt node_modules/.install-stamp ]; then
npm install # Dependencies changed
else
echo "Skipping" # Everything up to date
fi
On the first start after a fresh build, npm install runs (~5s for Vue, ~1s for YJS). On subsequent starts it's skipped.
Tip
If you run npm install locally on the host, node_modules are immediately available on the next container start.
Service Dependencies¶
Startup order is controlled by healthchecks:
graph LR
DB["MariaDB"] -->|healthy| FLASK["Flask"]
REDIS["Redis"] -->|healthy| FLASK
FLASK -->|healthy| SUPER["Supervisor"]
FLASK -->|healthy| VUE["Vue Frontend"]
FLASK -->|healthy| LKAGENT["LiveKit Agent"]
AUTH_DB["Postgres"] -->|healthy| AUTH["Authentik"]
AUTH -->|healthy| YJS["YJS"]
AUTH -->|healthy| AUTH_INIT["Authentik Init"]
VUE -->|healthy| NGINX["Nginx"]
FLASK -->|healthy| NGINX
YJS -->|healthy| NGINX
Critical path: MariaDB → Flask → Vue → Nginx (~30s)
Image Sizes¶
| Image | Size | Base Image |
|---|---|---|
| Flask Backend | 14.2 GB | python:3.10-slim + texlive-full |
| Vue Frontend | 1.55 GB | node:23-slim |
| YJS Server | 419 MB | node:23-slim |
| LiveKit Agent | ~500 MB | python:3.11-slim |
| Supervisor | 281 MB | python:3.10-slim |
| MkDocs | 276 MB | python:3.12-alpine |
| Nginx | 92 MB | nginx:alpine |
| MariaDB | 528 MB | mariadb:11.2.6 |
Troubleshooting¶
Build is slow¶
# Check build cache usage
docker system df
# Clean up build cache (only unused layers)
docker builder prune
# Full cleanup and rebuild
PRUNE_LLARS_SYSTEM=True ./start_llars.sh --build
Layer cache not being used¶
Common causes:
- Base image update: When
python:3.10-slimhas a new digest, all layers are invalidated. - Order: If a file changes that is copied before dependencies, everything after it is rebuilt.
- Build context: Large files forgotten in
.dockerignore→ slow context transfer.
Image too large¶
npm install runs on every start¶
Check if node_modules/.install-stamp exists:
If not, npm install runs on every start. This happens when the host directory has no node_modules.
Solution: Run cd llars-frontend && npm install locally once.