Skip to content

Commit d74efbc

Browse files
authored
Merge pull request #585 from chetanr25/optimisations
Optimize Docker dev workflow: faster builds, startup, and dependency iteration
2 parents 64d2da2 + 8bbb1d2 commit d74efbc

8 files changed

Lines changed: 92 additions & 34 deletions

File tree

.github/workflows/lint.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ jobs:
1919
with:
2020
python-version: "3.11"
2121

22+
- name: Install uv
23+
uses: astral-sh/setup-uv@v6
24+
2225
- name: Install linter
23-
run: |
24-
python -m pip install --upgrade pip
25-
pip install ruff
26+
run: uv pip install --system ruff
2627

2728
- name: Run linter
2829
run: |

.github/workflows/tests.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ jobs:
1818
with:
1919
python-version: "3.11"
2020

21+
- name: Install uv
22+
uses: astral-sh/setup-uv@v6
23+
2124
- name: Install dependencies
22-
run: |
23-
python -m pip install --upgrade pip
24-
pip install -r requirements.txt
25+
run: uv pip install --system -r requirements.txt
2526

2627
- name: Run tests
2728
env:

Makefile

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: help init fireform build up down logs logs-app logs-ollama shell pull-model test clean super-clean migrate migration
1+
.PHONY: help init fireform build up down logs logs-app logs-ollama shell pull-model test clean super-clean status ready-banner sync
22

33
COMPOSE = docker compose -f docker/dev/compose.yml --env-file docker/.env.dev
44
ENV_DEV = docker/.env.dev
@@ -22,6 +22,8 @@ help:
2222
@echo "make build - Build Docker images"
2323
@echo "make up - Start all containers (detached)"
2424
@echo "make down - Stop all containers"
25+
@echo "make sync - Fast-install new requirements.txt deps into running app (no rebuild)"
26+
@echo "make status - Show compact container health summary"
2527
@echo "make logs - Stream all container logs"
2628
@echo "make logs-app - Stream app container logs"
2729
@echo "make logs-ollama - Stream Ollama container logs"
@@ -46,30 +48,38 @@ init:
4648
*) echo "Run 'make fireform' when ready." ;; \
4749
esac
4850

49-
fireform: build up
50-
@printf "Waiting for Ollama to be ready..."
51-
@until $(COMPOSE) exec -T ollama ollama list > /dev/null 2>&1; do \
52-
printf '.'; sleep 2; \
53-
done
54-
@echo " ready."
51+
fireform:
52+
@$(COMPOSE) up -d --build
5553
@if $(COMPOSE) exec -T ollama ollama list 2>/dev/null | grep -q "^$(OLLAMA_MODEL)"; then \
5654
echo " Model $(OLLAMA_MODEL) already pulled."; \
5755
else \
5856
echo " Pulling $(OLLAMA_MODEL)..."; \
5957
$(COMPOSE) exec -T ollama ollama pull $(OLLAMA_MODEL); \
6058
fi
61-
@echo ""
62-
@echo "FireForm is ready!"
63-
@echo " API: http://localhost:8000"
64-
@echo " API Docs: http://localhost:8000/docs"
65-
@echo ""
66-
@echo "Run 'make logs' to view live logs, 'make down' to stop."
59+
@$(MAKE) --no-print-directory ready-banner
6760

6861
build:
6962
@$(COMPOSE) build
7063

7164
up:
7265
@$(COMPOSE) up -d
66+
@$(MAKE) --no-print-directory ready-banner
67+
68+
# Fast path for "I added a package": install the delta into the running container
69+
# (no image rebuild, no 1.6GB layer re-export). uv installs only what's missing in
70+
sync:
71+
@$(COMPOSE) exec -T app sh -c "UV_TORCH_BACKEND=cpu uv pip install --system -r requirements.txt"
72+
73+
status:
74+
@$(COMPOSE) ps --format 'table {{.Service}}\t{{.Status}}'
75+
76+
ready-banner:
77+
@echo ""
78+
@echo "FireForm is ready!"
79+
@echo " API: http://localhost:8000"
80+
@echo " API Docs: http://localhost:8000/docs"
81+
@echo ""
82+
@echo "Run 'make logs' to view live logs, 'make down' to stop."
7383

7484
down:
7585
@$(COMPOSE) down --remove-orphans

docker/dev/Dockerfile

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@ FROM python:3.11-slim
33

44
WORKDIR /app
55

6-
# Use apt cache mount to speed up system package installation across builds
6+
# apt cache mounts keep downloaded .debs across builds
77
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
88
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
99
--mount=type=cache,target=/var/lib/apt \
1010
apt-get update && apt-get install -y \
1111
curl \
1212
libgl1 \
1313
libglib2.0-0 \
14-
libxcb1
14+
libxcb1 \
15+
libpq-dev \
16+
build-essential \
17+
g++
18+
19+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
1520

1621
COPY requirements.txt .
1722

18-
# Use pip cache mount so it remembers downloaded wheels
19-
RUN --mount=type=cache,target=/root/.cache/pip \
20-
pip install -r requirements.txt
23+
RUN --mount=type=cache,target=/root/.cache/uv \
24+
UV_TORCH_BACKEND=cpu \
25+
uv pip install --system -r requirements.txt
26+
27+
# Bake a hash of the deps the image was built with. The entrypoint compares this
28+
# against the live (bind-mounted) requirements.txt to decide whether to reinstall.
29+
RUN sha256sum requirements.txt | cut -d' ' -f1 > /opt/req_hash
2130

2231
ENV PYTHONPATH=/app
2332

docker/dev/compose.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ services:
1717
interval: 10s
1818
timeout: 5s
1919
retries: 5
20+
start_period: 30s
21+
start_interval: 1s
2022

2123
ollama:
2224
image: ollama/ollama:latest
@@ -33,6 +35,7 @@ services:
3335
timeout: 5s
3436
retries: 5
3537
start_period: 30s
38+
start_interval: 2s
3639

3740
whisper:
3841
image: onerahmet/openai-whisper-asr-webservice:latest
@@ -53,6 +56,7 @@ services:
5356
timeout: 5s
5457
retries: 5
5558
start_period: 60s
59+
start_interval: 3s
5660

5761
redis:
5862
image: redis:7-alpine
@@ -68,6 +72,8 @@ services:
6872
interval: 10s
6973
timeout: 5s
7074
retries: 5
75+
start_period: 30s
76+
start_interval: 1s
7177

7278
app:
7379
build:

docker/entrypoint.sh

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
#!/bin/sh
22
set -e
33

4-
# Ensure data directories exist (volumes may be empty on first run)
54
mkdir -p /data/uploads
65

7-
# Run DB migrations / init before starting the server
6+
# Reinstall deps only when the live requirements.txt differs from what the image
7+
# was built with. The image bakes the hash at /opt/req_hash; in dev the live file
8+
# comes from the bind mount. Matching hash => deps already baked in => skip (instant).
9+
BAKED_HASH=$(cat /opt/req_hash 2>/dev/null || echo "none")
10+
LIVE_HASH=$(sha256sum requirements.txt 2>/dev/null | cut -d' ' -f1 || echo "unknown")
11+
12+
if [ "$BAKED_HASH" = "$LIVE_HASH" ]; then
13+
echo "[entrypoint] dependencies up to date — skipping install"
14+
else
15+
echo "[entrypoint] requirements.txt changed since image build — syncing deps..."
16+
if command -v uv > /dev/null 2>&1; then
17+
UV_TORCH_BACKEND=cpu uv pip install --system -r requirements.txt
18+
else
19+
pip install -r requirements.txt
20+
fi
21+
fi
22+
823
python3 -m app.db.init_db
924

1025
exec "$@"

docker/prod/Dockerfile

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,44 @@
1+
# ---- builder ----
12
FROM python:3.11-slim AS builder
23

3-
WORKDIR /build
4+
RUN apt-get update && apt-get install -y --no-install-recommends \
5+
build-essential g++ libpq-dev && \
6+
rm -rf /var/lib/apt/lists/*
7+
8+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
49

10+
WORKDIR /build
511
COPY requirements.txt .
6-
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
712

13+
RUN --mount=type=cache,target=/root/.cache/uv \
14+
UV_TORCH_BACKEND=cpu \
15+
uv pip install --system -r requirements.txt
816

17+
# ---- runtime ----
918
FROM python:3.11-slim
1019

1120
WORKDIR /app
1221

13-
RUN apt-get update && apt-get install -y \
22+
RUN apt-get update && apt-get install -y --no-install-recommends \
1423
curl \
1524
libgl1 \
1625
libglib2.0-0 \
1726
libxcb1 \
18-
&& rm -rf /var/lib/apt/lists/*
27+
libpq5 && \
28+
rm -rf /var/lib/apt/lists/*
1929

20-
COPY --from=builder /install /usr/local
30+
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
31+
COPY --from=builder /usr/local/bin /usr/local/bin
2132

22-
# Copy only app code, not data/ temp/ tests/ docs/ etc.
2333
COPY app/ ./app/
2434
COPY requirements.txt .
2535
COPY docker/entrypoint.sh /entrypoint.sh
2636

37+
# Bake deps hash so the entrypoint can skip the redundant install when unchanged.
38+
RUN sha256sum requirements.txt | cut -d' ' -f1 > /opt/req_hash
39+
2740
ENV PYTHONPATH=/app
2841

29-
# Data dirs created here; actual storage comes from mounted volumes at runtime.
3042
RUN mkdir -p /data/db /data/uploads && chmod +x /entrypoint.sh
3143

3244
EXPOSE 8000

scripts/setup-dockers-env.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
#!/bin/bash
22

33
source venv/bin/activate
4-
pip install -r requirements.txt
4+
if command -v uv > /dev/null 2>&1; then
5+
uv pip install -r requirements.txt
6+
else
7+
pip install -r requirements.txt
8+
fi

0 commit comments

Comments
 (0)