From 99ee00b2250f25a1111746e57656467aa3b1909c Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Sun, 1 Feb 2026 13:19:30 -0600 Subject: [PATCH] fix: add OCR image to CI/CD workflows (refs #64) - Add OCR image build/push to staging workflow - Add OCR service with image override to staging compose - Add OCR service with image override to blue-green compose - Add OCR image pull/deploy to production workflow - Include mvp-ocr-staging in health checks The OCR container is a shared service (like postgres/redis), not part of blue-green deployment. Co-Authored-By: Claude Opus 4.5 --- .gitea/workflows/production.yaml | 8 +++++++- .gitea/workflows/staging.yaml | 21 +++++++++++++++++++-- docker-compose.blue-green.yml | 6 ++++++ docker-compose.staging.yml | 7 +++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/production.yaml b/.gitea/workflows/production.yaml index 76dc966..c87866e 100644 --- a/.gitea/workflows/production.yaml +++ b/.gitea/workflows/production.yaml @@ -34,6 +34,7 @@ jobs: target_stack: ${{ steps.determine-stack.outputs.target_stack }} backend_image: ${{ steps.set-images.outputs.backend_image }} frontend_image: ${{ steps.set-images.outputs.frontend_image }} + ocr_image: ${{ steps.set-images.outputs.ocr_image }} steps: - name: Check Docker availability run: | @@ -53,6 +54,7 @@ jobs: TAG="${{ inputs.image_tag }}" echo "backend_image=$REGISTRY/egullickson/backend:$TAG" >> $GITHUB_OUTPUT echo "frontend_image=$REGISTRY/egullickson/frontend:$TAG" >> $GITHUB_OUTPUT + echo "ocr_image=$REGISTRY/egullickson/ocr:$TAG" >> $GITHUB_OUTPUT - name: Determine target stack id: determine-stack @@ -83,6 +85,7 @@ jobs: TARGET_STACK: ${{ needs.validate.outputs.target_stack }} BACKEND_IMAGE: ${{ needs.validate.outputs.backend_image }} FRONTEND_IMAGE: ${{ needs.validate.outputs.frontend_image }} + OCR_IMAGE: ${{ needs.validate.outputs.ocr_image }} steps: - name: Checkout scripts, config, and compose files uses: actions/checkout@v4 @@ -138,6 +141,7 @@ jobs: run: | docker pull $BACKEND_IMAGE docker pull $FRONTEND_IMAGE + docker pull $OCR_IMAGE - name: Record expected image IDs id: expected-images @@ -155,10 +159,12 @@ jobs: cd "$DEPLOY_PATH" export BACKEND_IMAGE=$BACKEND_IMAGE export FRONTEND_IMAGE=$FRONTEND_IMAGE + export OCR_IMAGE=$OCR_IMAGE # --force-recreate ensures containers are recreated even if image tag is same # This prevents stale container content when image digest changes + # Start shared OCR service and target stack docker compose -f $COMPOSE_FILE -f $COMPOSE_BLUE_GREEN up -d --force-recreate \ - mvp-frontend-$TARGET_STACK mvp-backend-$TARGET_STACK + mvp-ocr mvp-frontend-$TARGET_STACK mvp-backend-$TARGET_STACK - name: Wait for stack initialization run: sleep 10 diff --git a/.gitea/workflows/staging.yaml b/.gitea/workflows/staging.yaml index 0605af5..78d0e9d 100644 --- a/.gitea/workflows/staging.yaml +++ b/.gitea/workflows/staging.yaml @@ -29,6 +29,7 @@ jobs: outputs: backend_image: ${{ steps.tags.outputs.backend_image }} frontend_image: ${{ steps.tags.outputs.frontend_image }} + ocr_image: ${{ steps.tags.outputs.ocr_image }} short_sha: ${{ steps.tags.outputs.short_sha }} steps: - name: Checkout code @@ -45,6 +46,7 @@ jobs: SHORT_SHA="${SHORT_SHA:0:7}" echo "backend_image=$REGISTRY/egullickson/backend:$SHORT_SHA" >> $GITHUB_OUTPUT echo "frontend_image=$REGISTRY/egullickson/frontend:$SHORT_SHA" >> $GITHUB_OUTPUT + echo "ocr_image=$REGISTRY/egullickson/ocr:$SHORT_SHA" >> $GITHUB_OUTPUT echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT - name: Build backend image @@ -74,12 +76,24 @@ jobs: -f frontend/Dockerfile \ frontend + - name: Build OCR image + run: | + docker build \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --cache-from $REGISTRY/egullickson/ocr:latest \ + -t ${{ steps.tags.outputs.ocr_image }} \ + -t $REGISTRY/egullickson/ocr:latest \ + -f ocr/Dockerfile \ + ocr + - name: Push images run: | docker push ${{ steps.tags.outputs.backend_image }} docker push ${{ steps.tags.outputs.frontend_image }} + docker push ${{ steps.tags.outputs.ocr_image }} docker push $REGISTRY/egullickson/backend:latest docker push $REGISTRY/egullickson/frontend:latest + docker push $REGISTRY/egullickson/ocr:latest # ============================================ # DEPLOY STAGING - Deploy to staging server @@ -91,6 +105,7 @@ jobs: env: BACKEND_IMAGE: ${{ needs.build.outputs.backend_image }} FRONTEND_IMAGE: ${{ needs.build.outputs.frontend_image }} + OCR_IMAGE: ${{ needs.build.outputs.ocr_image }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -139,12 +154,14 @@ jobs: run: | docker pull $BACKEND_IMAGE docker pull $FRONTEND_IMAGE + docker pull $OCR_IMAGE - name: Deploy staging stack run: | cd "$DEPLOY_PATH" export BACKEND_IMAGE=$BACKEND_IMAGE export FRONTEND_IMAGE=$FRONTEND_IMAGE + export OCR_IMAGE=$OCR_IMAGE docker compose -f $COMPOSE_FILE -f $COMPOSE_STAGING down --timeout 30 || true docker compose -f $COMPOSE_FILE -f $COMPOSE_STAGING up -d @@ -164,7 +181,7 @@ jobs: - name: Check container status and health run: | - for service in mvp-frontend-staging mvp-backend-staging mvp-postgres-staging mvp-redis-staging; do + for service in mvp-frontend-staging mvp-backend-staging mvp-ocr-staging mvp-postgres-staging mvp-redis-staging; do status=$(docker inspect --format='{{.State.Status}}' $service 2>/dev/null || echo "not found") if [ "$status" != "running" ]; then echo "ERROR: $service is not running (status: $status)" @@ -177,7 +194,7 @@ jobs: # Wait for Docker healthchecks to complete (services with healthcheck defined) echo "" echo "Waiting for Docker healthchecks..." - for service in mvp-frontend-staging mvp-backend-staging mvp-postgres-staging mvp-redis-staging; do + for service in mvp-frontend-staging mvp-backend-staging mvp-ocr-staging mvp-postgres-staging mvp-redis-staging; do # Check if service has a healthcheck defined has_healthcheck=$(docker inspect --format='{{if .Config.Healthcheck}}true{{else}}false{{end}}' $service 2>/dev/null || echo "false") if [ "$has_healthcheck" = "true" ]; then diff --git a/docker-compose.blue-green.yml b/docker-compose.blue-green.yml index 9c8ff2d..fb5d61a 100644 --- a/docker-compose.blue-green.yml +++ b/docker-compose.blue-green.yml @@ -194,6 +194,12 @@ services: - "com.motovaultpro.stack=green" - "com.motovaultpro.service=backend" + # ======================================== + # Shared Service - OCR Processing + # ======================================== + mvp-ocr: + image: ${OCR_IMAGE:-git.motovaultpro.com/egullickson/ocr:latest} + # ======================================== # Override Traefik to add dynamic config # ======================================== diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml index 79b537e..df667b3 100644 --- a/docker-compose.staging.yml +++ b/docker-compose.staging.yml @@ -55,6 +55,13 @@ services: - "traefik.http.routers.mvp-backend-health.priority=30" - "traefik.http.services.mvp-backend.loadbalancer.server.port=3001" + # ======================================== + # OCR Service (Staging) + # ======================================== + mvp-ocr: + image: ${OCR_IMAGE:-git.motovaultpro.com/egullickson/ocr:latest} + container_name: mvp-ocr-staging + # ======================================== # PostgreSQL (Staging - Separate Database) # ========================================