Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a38d77ed23 | |||
| f1ed5b6e23 | |||
| 3ab8a81c14 | |||
| 739c3ff30c |
@@ -101,6 +101,15 @@ Override the registry and org via environment variables:
|
|||||||
REGISTRY=ghcr.io IMAGE_ORG=myorg ./release-engine.sh --github
|
REGISTRY=ghcr.io IMAGE_ORG=myorg ./release-engine.sh --github
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Pushes are retried on transient registry failures. The engine images carry a
|
||||||
|
~5.6GB torch layer, and uploading it can fail with a 502 from the proxy in
|
||||||
|
front of the registry (or a 500 on the manifest PUT that follows), which
|
||||||
|
clears on a retry. Tune with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PUSH_RETRIES=8 PUSH_RETRY_DELAY=20 ./release-engine.sh --gitea
|
||||||
|
```
|
||||||
|
|
||||||
## API reference
|
## API reference
|
||||||
|
|
||||||
All endpoints are under `/api/v1/`. Requires `Authorization: Bearer <key>` header when `KB_API_KEY` is set.
|
All endpoints are under `/api/v1/`. Requires `Authorization: Bearer <key>` header when `KB_API_KEY` is set.
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
3.2.0
|
3.3.0
|
||||||
|
|||||||
+20
-4
@@ -13,16 +13,32 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install CPU torch first, on its own, from the CPU index.
|
||||||
|
#
|
||||||
|
# Order matters: anything that depends on torch (sentence-transformers) will
|
||||||
|
# otherwise resolve the default CUDA build and pull ~2.7GB of nvidia-* wheels.
|
||||||
|
# Reinstalling torch afterwards replaces torch but leaves those wheels behind,
|
||||||
|
# orphaned and unused — which is how the CPU image ended up larger than the
|
||||||
|
# CUDA one. Installing CPU torch up front means nothing ever requests CUDA.
|
||||||
|
#
|
||||||
|
# Keeping it in its own layer also bounds the blob size: the registry drops
|
||||||
|
# uploads that take longer than 60s, so no single layer should approach ~3GB.
|
||||||
|
# Placing it before the source COPYs keeps this expensive layer cached when
|
||||||
|
# only application code changes.
|
||||||
|
RUN uv venv .venv && \
|
||||||
|
. .venv/bin/activate && \
|
||||||
|
UV_HTTP_TIMEOUT=600 uv pip install torch torchvision \
|
||||||
|
--index-url https://download.pytorch.org/whl/cpu
|
||||||
|
|
||||||
COPY pyproject.toml ./
|
COPY pyproject.toml ./
|
||||||
COPY kb/ kb/
|
COPY kb/ kb/
|
||||||
COPY main.py ./
|
COPY main.py ./
|
||||||
COPY VERSION ./
|
COPY VERSION ./
|
||||||
|
|
||||||
RUN uv venv .venv && \
|
# Remaining dependencies resolve against the CPU torch already present.
|
||||||
. .venv/bin/activate && \
|
RUN . .venv/bin/activate && \
|
||||||
uv pip install -e . && \
|
|
||||||
uv pip install "sentence-transformers[onnx]" && \
|
uv pip install "sentence-transformers[onnx]" && \
|
||||||
uv pip install --reinstall torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
uv pip install -e .
|
||||||
|
|
||||||
ENV PATH="/app/.venv/bin:$PATH"
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
ENV VIRTUAL_ENV="/app/.venv"
|
ENV VIRTUAL_ENV="/app/.venv"
|
||||||
|
|||||||
@@ -13,14 +13,23 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install CUDA torch on its own, before the source COPYs.
|
||||||
|
#
|
||||||
|
# This is the bulk of the image (~2.8GiB compressed). Splitting it from the
|
||||||
|
# application install keeps it cached when only code changes, and keeps the
|
||||||
|
# app layer small. The registry drops any blob upload that takes longer than
|
||||||
|
# 60s, so this layer is deliberately the only large one.
|
||||||
|
RUN uv venv .venv && \
|
||||||
|
. .venv/bin/activate && \
|
||||||
|
UV_HTTP_TIMEOUT=600 uv pip install torch torchvision \
|
||||||
|
--index-url https://download.pytorch.org/whl/cu130
|
||||||
|
|
||||||
COPY pyproject.toml ./
|
COPY pyproject.toml ./
|
||||||
COPY kb/ kb/
|
COPY kb/ kb/
|
||||||
COPY main.py ./
|
COPY main.py ./
|
||||||
COPY VERSION ./
|
COPY VERSION ./
|
||||||
|
|
||||||
RUN uv venv .venv && \
|
RUN . .venv/bin/activate && \
|
||||||
. .venv/bin/activate && \
|
|
||||||
UV_HTTP_TIMEOUT=600 uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130 && \
|
|
||||||
uv pip install -e .
|
uv pip install -e .
|
||||||
|
|
||||||
ENV PATH="/app/.venv/bin:$PATH"
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
|
|||||||
+47
-9
@@ -15,10 +15,18 @@ ENGINE_DIR="$SCRIPT_DIR/engine"
|
|||||||
VERSION_FILE="$ENGINE_DIR/VERSION"
|
VERSION_FILE="$ENGINE_DIR/VERSION"
|
||||||
|
|
||||||
# Container registry
|
# Container registry
|
||||||
|
#
|
||||||
|
# --provenance=false --sbom=false on every build: buildx would otherwise attach
|
||||||
|
# attestation manifests, making the image an OCI image index. The Registry v2
|
||||||
|
# host at docker.dcglab.co.uk rejects those with a 500 on manifest PUT.
|
||||||
REGISTRY="${REGISTRY:-docker.dcglab.co.uk}"
|
REGISTRY="${REGISTRY:-docker.dcglab.co.uk}"
|
||||||
IMAGE_ORG="${IMAGE_ORG:-}"
|
IMAGE_ORG="${IMAGE_ORG:-}"
|
||||||
IMAGE_BASE="${REGISTRY}${IMAGE_ORG:+/${IMAGE_ORG}}/kb"
|
IMAGE_BASE="${REGISTRY}${IMAGE_ORG:+/${IMAGE_ORG}}/kb"
|
||||||
|
|
||||||
|
# Push retries — see push_image() below
|
||||||
|
PUSH_RETRIES="${PUSH_RETRIES:-5}"
|
||||||
|
PUSH_RETRY_DELAY="${PUSH_RETRY_DELAY:-10}"
|
||||||
|
|
||||||
#──────────────────────────────────────────────────────────────────────
|
#──────────────────────────────────────────────────────────────────────
|
||||||
# Parse args
|
# Parse args
|
||||||
#──────────────────────────────────────────────────────────────────────
|
#──────────────────────────────────────────────────────────────────────
|
||||||
@@ -98,6 +106,36 @@ run() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Push one image tag, retrying on transient registry failures.
|
||||||
|
#
|
||||||
|
# The engine images carry a ~5.6GB torch layer. Uploading it intermittently
|
||||||
|
# fails with a 502 from the reverse proxy in front of the registry, and a
|
||||||
|
# manifest PUT can then fail with a 500 because the blob commit has not yet
|
||||||
|
# registered. Both clear on a retry, so a whole release should not be lost to
|
||||||
|
# one hiccup. Tune with PUSH_RETRIES / PUSH_RETRY_DELAY.
|
||||||
|
push_image() {
|
||||||
|
local image="$1"
|
||||||
|
local attempt=1
|
||||||
|
|
||||||
|
echo " $ docker push $image"
|
||||||
|
[[ "$DRY_RUN" == true ]] && return 0
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
if docker push "$image"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( attempt >= PUSH_RETRIES )); then
|
||||||
|
echo "Error: failed to push $image after $PUSH_RETRIES attempts" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " push failed (attempt $attempt/$PUSH_RETRIES) — retrying in ${PUSH_RETRY_DELAY}s"
|
||||||
|
sleep "$PUSH_RETRY_DELAY"
|
||||||
|
attempt=$(( attempt + 1 ))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
#──────────────────────────────────────────────────────────────────────
|
#──────────────────────────────────────────────────────────────────────
|
||||||
# Determine release version
|
# Determine release version
|
||||||
#──────────────────────────────────────────────────────────────────────
|
#──────────────────────────────────────────────────────────────────────
|
||||||
@@ -155,8 +193,8 @@ CPU_IMAGE="${IMAGE_BASE}/engine:${DOCKER_TAG}-cpu"
|
|||||||
NVIDIA_LATEST="${IMAGE_BASE}/engine:latest-nvidia"
|
NVIDIA_LATEST="${IMAGE_BASE}/engine:latest-nvidia"
|
||||||
CPU_LATEST="${IMAGE_BASE}/engine:latest-cpu"
|
CPU_LATEST="${IMAGE_BASE}/engine:latest-cpu"
|
||||||
|
|
||||||
run docker build -t "$NVIDIA_IMAGE" -t "$NVIDIA_LATEST" -f "$ENGINE_DIR/Dockerfile.nvidia" "$ENGINE_DIR"
|
run docker build --provenance=false --sbom=false -t "$NVIDIA_IMAGE" -t "$NVIDIA_LATEST" -f "$ENGINE_DIR/Dockerfile.nvidia" "$ENGINE_DIR"
|
||||||
run docker build -t "$CPU_IMAGE" -t "$CPU_LATEST" -f "$ENGINE_DIR/Dockerfile.cpu" "$ENGINE_DIR"
|
run docker build --provenance=false --sbom=false -t "$CPU_IMAGE" -t "$CPU_LATEST" -f "$ENGINE_DIR/Dockerfile.cpu" "$ENGINE_DIR"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -171,7 +209,7 @@ if [[ -f "$MCP_DIR/Dockerfile" ]]; then
|
|||||||
MCP_IMAGE="${IMAGE_BASE}/mcp:${DOCKER_TAG}"
|
MCP_IMAGE="${IMAGE_BASE}/mcp:${DOCKER_TAG}"
|
||||||
MCP_LATEST="${IMAGE_BASE}/mcp:latest"
|
MCP_LATEST="${IMAGE_BASE}/mcp:latest"
|
||||||
|
|
||||||
run docker build -t "$MCP_IMAGE" -t "$MCP_LATEST" -f "$MCP_DIR/Dockerfile" "$MCP_DIR"
|
run docker build --provenance=false --sbom=false -t "$MCP_IMAGE" -t "$MCP_LATEST" -f "$MCP_DIR/Dockerfile" "$MCP_DIR"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
@@ -233,14 +271,14 @@ echo ""
|
|||||||
#──────────────────────────────────────────────────────────────────────
|
#──────────────────────────────────────────────────────────────────────
|
||||||
echo "==> Pushing Docker images to $REGISTRY"
|
echo "==> Pushing Docker images to $REGISTRY"
|
||||||
|
|
||||||
run docker push "$NVIDIA_IMAGE"
|
push_image "$NVIDIA_IMAGE"
|
||||||
run docker push "$NVIDIA_LATEST"
|
push_image "$NVIDIA_LATEST"
|
||||||
run docker push "$CPU_IMAGE"
|
push_image "$CPU_IMAGE"
|
||||||
run docker push "$CPU_LATEST"
|
push_image "$CPU_LATEST"
|
||||||
|
|
||||||
if [[ -n "${MCP_IMAGE:-}" ]]; then
|
if [[ -n "${MCP_IMAGE:-}" ]]; then
|
||||||
run docker push "$MCP_IMAGE"
|
push_image "$MCP_IMAGE"
|
||||||
run docker push "$MCP_LATEST"
|
push_image "$MCP_LATEST"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user