Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ jobs:
retention-days: 1

release-docker-images:
name: Release Docker (${{ matrix.image_name }}${{ matrix.tag_suffix }})
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -349,10 +350,28 @@ jobs:
include:
- target: api-only
image_name: hindsight-api
tag_suffix: ""
build_args: ""
- target: api-only
image_name: hindsight-api
tag_suffix: "-slim"
build_args: |
INCLUDE_LOCAL_MODELS=false
PRELOAD_ML_MODELS=false
- target: cp-only
image_name: hindsight-control-plane
tag_suffix: ""
build_args: ""
- target: standalone
image_name: hindsight
tag_suffix: ""
build_args: ""
- target: standalone
image_name: hindsight
tag_suffix: "-slim"
build_args: |
INCLUDE_LOCAL_MODELS=false
PRELOAD_ML_MODELS=false

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -390,6 +409,9 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/${{ matrix.image_name }}
flavor: |
latest=auto
suffix=${{ matrix.tag_suffix }}
tags: |
type=semver,pattern={{version}},value=${{ steps.get_version.outputs.VERSION }}
type=semver,pattern={{major}}.{{minor}},value=${{ steps.get_version.outputs.VERSION }}
Expand All @@ -415,7 +437,7 @@ jobs:
# - name: Smoke test - verify container starts
# env:
# GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
# run: ./scripts/docker-smoke-test.sh "${{ matrix.image_name }}:test" "${{ matrix.target }}"
# run: ./docker/test-image.sh "${{ matrix.image_name }}:test" "${{ matrix.target }}"

# Build multi-platform and push to release tags
- name: Build and push release images
Expand All @@ -424,6 +446,7 @@ jobs:
context: .
file: docker/standalone/Dockerfile
target: ${{ matrix.target }}
build-args: ${{ matrix.build_args }}
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
Expand Down
45 changes: 37 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -277,16 +277,35 @@ jobs:
run: helm lint helm/hindsight

build-docker-images:
name: Build Docker (${{ matrix.name }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: api-only
name: api
variant: full
build_args: ""
- target: api-only
name: api-slim
variant: slim
build_args: |
INCLUDE_LOCAL_MODELS=false
PRELOAD_ML_MODELS=false
- target: cp-only
name: control-plane
variant: full
build_args: ""
- target: standalone
name: standalone
variant: full
build_args: ""
- target: standalone
name: standalone-slim
variant: slim
build_args: |
INCLUDE_LOCAL_MODELS=false
PRELOAD_ML_MODELS=false

steps:
- uses: actions/checkout@v4
Expand All @@ -305,20 +324,30 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build ${{ matrix.name }} image
- name: Build ${{ matrix.name }} image (${{ matrix.variant }})
uses: docker/build-push-action@v6
with:
context: .
file: docker/standalone/Dockerfile
target: ${{ matrix.target }}
build-args: ${{ matrix.build_args }}
push: false
load: false

# TODO: Re-enable smoke test when disk space issue is resolved
# - name: Smoke test - verify container starts
# env:
# GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
# run: ./scripts/docker-smoke-test.sh "hindsight-${{ matrix.name }}:test" "${{ matrix.target }}"
load: ${{ matrix.variant == 'slim' }}
tags: hindsight-${{ matrix.name }}:test
cache-from: type=gha,scope=${{ matrix.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.name }}

# Only test slim variants to save disk space (they're much smaller)
# Slim variants require external embedding providers
- name: Smoke test - verify container starts
if: matrix.variant == 'slim'
env:
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
HINDSIGHT_API_EMBEDDINGS_PROVIDER: openai
HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
HINDSIGHT_API_RERANKER_PROVIDER: cohere
HINDSIGHT_API_COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
run: ./docker/test-image.sh "hindsight-${{ matrix.name }}:test" "${{ matrix.target }}"

test-api:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \

You can modify the LLM provider by setting `HINDSIGHT_API_LLM_PROVIDER`. Valid options are `openai`, `anthropic`, `gemini`, `groq`, `ollama`, and `lmstudio`. The documentation provides more details on [supported models](https://hindsight.vectorize.io/developer/models).

API: http://localhost:8888
API: http://localhost:8888
UI: http://localhost:9999

Install client:
Expand Down
135 changes: 135 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Docker Testing

Scripts for testing Hindsight Docker images locally and in CI.

## Scripts

### `test-image.sh`

General-purpose Docker image test script. Starts a container and verifies it becomes healthy.

**Usage:**
```bash
./docker/test-image.sh <image> [target]
```

**Arguments:**
- `image` - Docker image to test (e.g., `hindsight:test`, `ghcr.io/vectorize-io/hindsight:latest`)
- `target` - Optional: `cp-only` for control plane, `api-only` for API, or `standalone` (default)

**Environment Variables:**
- `GROQ_API_KEY` - Required for API/standalone images
- `HINDSIGHT_API_LLM_PROVIDER` - LLM provider (default: `groq`)
- `HINDSIGHT_API_LLM_MODEL` - LLM model (default: `llama-3.3-70b-versatile`)
- `HINDSIGHT_API_EMBEDDINGS_PROVIDER` - Embeddings provider (for slim images)
- `HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY` - OpenAI API key for embeddings
- `HINDSIGHT_API_RERANKER_PROVIDER` - Reranker provider (for slim images)
- `HINDSIGHT_API_COHERE_API_KEY` - Cohere API key for reranking
- `SMOKE_TEST_TIMEOUT` - Timeout in seconds (default: 120)

**Examples:**

Test a full image (with local ML models):
```bash
export GROQ_API_KEY=gsk_xxx
./docker/test-image.sh hindsight:test
```

Test a slim image (with external providers):
```bash
export GROQ_API_KEY=gsk_xxx
export HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai
export HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=sk-xxx
export HINDSIGHT_API_RERANKER_PROVIDER=cohere
export HINDSIGHT_API_COHERE_API_KEY=xxx
./docker/test-image.sh hindsight-slim:test
```

### `test-slim-local.sh`

Convenience wrapper for testing slim images locally. Automatically configures external providers.

**Usage:**
```bash
# Set API keys
export GROQ_API_KEY=gsk_xxx
export OPENAI_API_KEY=sk-xxx
export COHERE_API_KEY=xxx

# Run test
./docker/test-slim-local.sh [image]
```

**Or inline:**
```bash
GROQ_API_KEY=gsk_xxx \
OPENAI_API_KEY=sk-xxx \
COHERE_API_KEY=xxx \
./docker/test-slim-local.sh hindsight-slim:test
```

This script:
- ✅ Validates API keys are set
- ✅ Configures OpenAI embeddings automatically
- ✅ Configures Cohere reranking automatically
- ✅ Calls `test-image.sh` with the right configuration

## Building and Testing Locally

### Build a slim image

```bash
docker build \
--build-arg INCLUDE_LOCAL_MODELS=false \
--build-arg PRELOAD_ML_MODELS=false \
--target standalone \
-t hindsight-slim:test \
-f docker/standalone/Dockerfile \
.
```

### Test the slim image

```bash
# With API keys
export GROQ_API_KEY=gsk_xxx
export OPENAI_API_KEY=sk-xxx
export COHERE_API_KEY=xxx

# Run test
./docker/test-slim-local.sh hindsight-slim:test
```

## Expected Output

**Successful test:**
```
Starting smoke test for: hindsight-slim:test
Target: standalone
Health endpoint: http://localhost:8888/health
Timeout: 120s

Starting container...
Waiting for health endpoint at http://localhost:8888/health...
Still waiting... (10s)
Still waiting... (20s)

Container is healthy after 25s

=== Health Response ===
{
"status": "healthy",
"database": "connected"
}

Smoke test PASSED
```

## CI Integration

These scripts are used in CI to validate Docker images on every PR:

- `.github/workflows/test.yml` - Runs `test-image.sh` for slim variants with OpenAI/Cohere
- `.github/workflows/release.yml` - Can optionally run smoke tests during release

See the workflows for the exact configuration.
64 changes: 48 additions & 16 deletions scripts/docker-smoke-test.sh → docker/test-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,40 @@
# Can be run locally or in CI pipelines.
#
# Usage:
# ./scripts/docker-smoke-test.sh <image> [target]
# ./docker/test-image.sh <image> [target]
#
# Arguments:
# image - Docker image to test (e.g., hindsight-api:test, ghcr.io/vectorize-io/hindsight:latest)
# target - Optional: 'cp-only' for control plane, otherwise assumes API image (default: api)
#
# Environment variables:
# GROQ_API_KEY - Required for API/standalone images (LLM verification)
# HINDSIGHT_API_LLM_PROVIDER - LLM provider (default: groq)
# HINDSIGHT_API_LLM_MODEL - LLM model (default: llama-3.3-70b-versatile)
# SMOKE_TEST_TIMEOUT - Timeout in seconds (default: 120)
# SMOKE_TEST_CONTAINER_NAME - Container name (default: hindsight-smoke-test)
# GROQ_API_KEY - Required for API/standalone images (LLM verification)
# HINDSIGHT_API_LLM_PROVIDER - LLM provider (default: groq)
# HINDSIGHT_API_LLM_MODEL - LLM model (default: llama-3.3-70b-versatile)
# HINDSIGHT_API_EMBEDDINGS_PROVIDER - Embeddings provider (optional, for slim images: openai, cohere, tei)
# HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY - OpenAI API key for embeddings (optional)
# HINDSIGHT_API_RERANKER_PROVIDER - Reranker provider (optional, for slim images: cohere, tei)
# HINDSIGHT_API_COHERE_API_KEY - Cohere API key for reranking (optional)
# SMOKE_TEST_TIMEOUT - Timeout in seconds (default: 120)
# SMOKE_TEST_CONTAINER_NAME - Container name (default: hindsight-smoke-test)
#
# Examples:
# # Test a locally built image
# ./scripts/docker-smoke-test.sh hindsight-api:test
# # Test a locally built full image
# ./docker/test-image.sh hindsight-api:test
#
# # Test a released image
# ./scripts/docker-smoke-test.sh ghcr.io/vectorize-io/hindsight:latest
# ./docker/test-image.sh ghcr.io/vectorize-io/hindsight:latest
#
# # Test control plane image
# ./scripts/docker-smoke-test.sh hindsight-control-plane:test cp-only
# ./docker/test-image.sh hindsight-control-plane:test cp-only
#
# # Test slim image with external providers
# export GROQ_API_KEY=gsk_xxx
# export HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai
# export HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=sk-xxx
# export HINDSIGHT_API_RERANKER_PROVIDER=cohere
# export HINDSIGHT_API_COHERE_API_KEY=xxx
# ./docker/test-image.sh hindsight-slim:test
#
# Exit codes:
# 0 - Success (container healthy)
Expand Down Expand Up @@ -108,12 +120,32 @@ if [ "$TARGET" = "cp-only" ]; then
-p "${HEALTH_PORT}:${HEALTH_PORT}" \
"$IMAGE"
else
docker run -d --name "$CONTAINER_NAME" \
-e HINDSIGHT_API_LLM_PROVIDER="$LLM_PROVIDER" \
-e HINDSIGHT_API_LLM_API_KEY="${GROQ_API_KEY}" \
-e HINDSIGHT_API_LLM_MODEL="$LLM_MODEL" \
-p "${HEALTH_PORT}:${HEALTH_PORT}" \
"$IMAGE"
# Build docker run command with required and optional env vars
DOCKER_CMD="docker run -d --name $CONTAINER_NAME"
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_LLM_PROVIDER=$LLM_PROVIDER"
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_LLM_API_KEY=${GROQ_API_KEY}"
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_LLM_MODEL=$LLM_MODEL"

# Add optional embeddings provider config
if [ -n "${HINDSIGHT_API_EMBEDDINGS_PROVIDER:-}" ]; then
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_EMBEDDINGS_PROVIDER=${HINDSIGHT_API_EMBEDDINGS_PROVIDER}"
fi
if [ -n "${HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY:-}" ]; then
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=${HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY}"
fi

# Add optional reranker provider config
if [ -n "${HINDSIGHT_API_RERANKER_PROVIDER:-}" ]; then
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_RERANKER_PROVIDER=${HINDSIGHT_API_RERANKER_PROVIDER}"
fi
if [ -n "${HINDSIGHT_API_COHERE_API_KEY:-}" ]; then
DOCKER_CMD="$DOCKER_CMD -e HINDSIGHT_API_COHERE_API_KEY=${HINDSIGHT_API_COHERE_API_KEY}"
fi

DOCKER_CMD="$DOCKER_CMD -p ${HEALTH_PORT}:${HEALTH_PORT}"
DOCKER_CMD="$DOCKER_CMD $IMAGE"

eval $DOCKER_CMD
fi

# Wait for health endpoint
Expand Down
Loading
Loading