diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6fa8f400..cae4785c 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -38,7 +38,7 @@ jobs: packages: write strategy: matrix: - image: [extproc, llm-katan] + image: [extproc, llm-katan, dashboard] # Multi-architecture build strategy: # - AMD64: Native build on ubuntu-latest (fast) # - ARM64: Cross-compilation on ubuntu-latest (faster than emulation) @@ -97,6 +97,32 @@ jobs: ${{ runner.os }}-pip-${{ matrix.arch }}- ${{ runner.os }}-pip- + # Node.js and Go caching for dashboard builds + - name: Cache Node.js dependencies (dashboard) + if: matrix.image == 'dashboard' + uses: actions/cache@v4 + with: + path: | + ~/.npm + dashboard/frontend/node_modules + key: ${{ runner.os }}-node-${{ matrix.arch }}-${{ hashFiles('dashboard/frontend/package.json', 'dashboard/frontend/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.arch }}- + ${{ runner.os }}-node- + + - name: Cache Go dependencies (dashboard) + if: matrix.image == 'dashboard' + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + dashboard/backend/go.sum + key: ${{ runner.os }}-go-${{ matrix.arch }}-${{ hashFiles('dashboard/backend/go.mod', 'dashboard/backend/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ matrix.arch }}- + ${{ runner.os }}-go- + - name: Generate date tag for nightly builds id: date if: inputs.is_nightly == true @@ -124,6 +150,10 @@ jobs: echo "context=./e2e-tests/llm-katan" >> $GITHUB_OUTPUT echo "dockerfile=./e2e-tests/llm-katan/Dockerfile" >> $GITHUB_OUTPUT echo "platform=linux/${{ matrix.arch }}" >> $GITHUB_OUTPUT + elif [ "${{ matrix.image }}" = "dashboard" ]; then + echo "context=." >> $GITHUB_OUTPUT + echo "dockerfile=./dashboard/backend/Dockerfile" >> $GITHUB_OUTPUT + echo "platform=linux/${{ matrix.arch }}" >> $GITHUB_OUTPUT fi - name: Generate tags @@ -183,7 +213,7 @@ jobs: if: github.event_name != 'pull_request' strategy: matrix: - image: [extproc, llm-katan] + image: [extproc, llm-katan, dashboard] steps: - name: Log in to GitHub Container Registry diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index e339afb3..7e792b62 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -94,3 +94,44 @@ jobs: ghcr.io/${{ env.REPOSITORY_OWNER_LOWER }}/semantic-router/llm-katan:${{ steps.extract_tag.outputs.tag }} ghcr.io/${{ env.REPOSITORY_OWNER_LOWER }}/semantic-router/llm-katan:v${{ steps.version.outputs.version }} ghcr.io/${{ env.REPOSITORY_OWNER_LOWER }}/semantic-router/llm-katan:latest + + build_and_push_dashboard: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Extract tag name + id: extract_tag + run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + + - name: Set lowercase repository owner + run: echo "REPOSITORY_OWNER_LOWER=$(echo $GITHUB_REPOSITORY_OWNER | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push dashboard Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./dashboard/backend/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ghcr.io/${{ env.REPOSITORY_OWNER_LOWER }}/semantic-router/dashboard:${{ steps.extract_tag.outputs.tag }} + ghcr.io/${{ env.REPOSITORY_OWNER_LOWER }}/semantic-router/dashboard:latest diff --git a/dashboard/README.md b/dashboard/README.md index 46c05fe4..2cda6c54 100644 --- a/dashboard/README.md +++ b/dashboard/README.md @@ -271,10 +271,12 @@ docker logs -f semantic-router-dashboard - A **3-stage multi-stage build** is defined in `dashboard/backend/Dockerfile`: 1. **Node.js stage**: Builds the React frontend with Vite (`npm run build` → `dist/`) - 2. **Go builder stage**: Compiles the backend binary + 2. **Go builder stage**: Compiles the backend binary with multi-architecture support 3. **Alpine runtime stage**: Combines backend + frontend dist in minimal image - An independent Go module `dashboard/backend/go.mod` isolates backend dependencies. - Frontend production build (`dist/`) is packaged into the image at `/app/frontend`. +- **Multi-architecture support**: The Dockerfile supports both AMD64 and ARM64 architectures. +- **Pre-built images**: Available at `ghcr.io/vllm-project/semantic-router/dashboard` with tags for releases and latest. ### Grafana Embedding Support diff --git a/dashboard/backend/Dockerfile b/dashboard/backend/Dockerfile index f0741cb4..e8bf4127 100644 --- a/dashboard/backend/Dockerfile +++ b/dashboard/backend/Dockerfile @@ -16,6 +16,10 @@ WORKDIR /app ENV GOPROXY=https://goproxy.cn,direct ENV GOSUMDB=sum.golang.google.cn +# Accept build arguments for target architecture +ARG TARGETARCH +ARG TARGETOS=linux + # Copy go.mod and go.sum first for better caching COPY dashboard/backend/go.mod dashboard/backend/go.sum /app/dashboard/backend/ WORKDIR /app/dashboard/backend @@ -23,7 +27,7 @@ RUN go mod download # Copy source code and build COPY dashboard/backend/ /app/dashboard/backend/ -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /app/dashboard-backend main.go +RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags="-w -s" -o /app/dashboard-backend main.go # Stage 3: Final runtime image FROM alpine:3.19 diff --git a/dashboard/deploy/kubernetes/deployment.yaml b/dashboard/deploy/kubernetes/deployment.yaml index 435b0828..608284af 100644 --- a/dashboard/deploy/kubernetes/deployment.yaml +++ b/dashboard/deploy/kubernetes/deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: dashboard - image: semantic-router-dashboard:latest + image: ghcr.io/vllm-project/semantic-router/dashboard:latest imagePullPolicy: IfNotPresent args: ["-port=8700", "-static=/app/frontend"] env: diff --git a/deploy/docker-compose/docker-compose.yml b/deploy/docker-compose/docker-compose.yml index 185660bd..24302b04 100644 --- a/deploy/docker-compose/docker-compose.yml +++ b/deploy/docker-compose/docker-compose.yml @@ -166,10 +166,11 @@ services: # Semantic Router Dashboard dashboard: + # Use pre-built image from GHCR, fallback to local build for development + image: ${DASHBOARD_IMAGE:-ghcr.io/vllm-project/semantic-router/dashboard:latest} build: context: ../../ dockerfile: dashboard/backend/Dockerfile - image: semantic-router-dashboard:dev container_name: semantic-router-dashboard command: ["/app/dashboard-backend", "-port=8700", "-static=/app/frontend", "-config=/app/config/config.yaml"] environment: diff --git a/tools/make/docker.mk b/tools/make/docker.mk index e698097f..f28a49ee 100644 --- a/tools/make/docker.mk +++ b/tools/make/docker.mk @@ -13,7 +13,7 @@ export COMPOSE_FILE ?= deploy/docker-compose/docker-compose.yml export COMPOSE_PROJECT_NAME ?= semantic-router # Build all Docker images -docker-build-all: docker-build-extproc docker-build-llm-katan docker-build-precommit +docker-build-all: docker-build-extproc docker-build-llm-katan docker-build-dashboard docker-build-precommit @$(LOG_TARGET) @echo "All Docker images built successfully" @@ -29,6 +29,12 @@ docker-build-llm-katan: @echo "Building llm-katan Docker image..." @$(CONTAINER_RUNTIME) build -f e2e-tests/llm-katan/Dockerfile -t $(DOCKER_REGISTRY)/llm-katan:$(DOCKER_TAG) e2e-tests/llm-katan/ +# Build dashboard Docker image +docker-build-dashboard: + @$(LOG_TARGET) + @echo "Building dashboard Docker image..." + @$(CONTAINER_RUNTIME) build -f dashboard/backend/Dockerfile -t $(DOCKER_REGISTRY)/dashboard:$(DOCKER_TAG) . + # Build precommit Docker image docker-build-precommit: @$(LOG_TARGET) @@ -126,6 +132,7 @@ docker-help: @echo " docker-build-all - Build all Docker images" @echo " docker-build-extproc - Build extproc Docker image" @echo " docker-build-llm-katan - Build llm-katan Docker image" + @echo " docker-build-dashboard - Build dashboard Docker image" @echo " docker-build-precommit - Build precommit Docker image" @echo " docker-test-llm-katan - Test llm-katan Docker image" @echo " docker-run-llm-katan - Run llm-katan Docker image locally"