stages: - build - publish - deploy variables: REGISTRY: registry.gitlab.com/$CI_PROJECT_PATH # ══════════════════════════════════════════════════════════ # BUILD # ══════════════════════════════════════════════════════════ build-rag: stage: build image: eclipse-temurin:25-jdk-alpine cache: key: "${CI_COMMIT_REF_SLUG}-rag" paths: - rag-service/.m2/repository script: - cd rag-service - chmod +x mvnw - ./mvnw package -DskipTests -B -Dmaven.repo.local=.m2/repository artifacts: paths: - rag-service/target/*.jar expire_in: 1h rules: - if: $CI_COMMIT_BRANCH == "main" changes: - rag-service/**/* build-gateway: stage: build image: eclipse-temurin:25-jdk-alpine cache: key: "${CI_COMMIT_REF_SLUG}-gateway" paths: - gateway-service/.m2/repository script: - cd gateway-service - apk add --no-cache maven - mvn package -DskipTests -B -Dmaven.repo.local=.m2/repository artifacts: paths: - gateway-service/target/*.jar expire_in: 1h rules: - if: $CI_COMMIT_BRANCH == "main" changes: - gateway-service/**/* build-analytics: stage: build image: eclipse-temurin:25-jdk-alpine cache: key: "${CI_COMMIT_REF_SLUG}-analytics" paths: - analytics-service/.m2/repository script: - cd analytics-service - apk add --no-cache maven - mvn package -DskipTests -B -Dmaven.repo.local=.m2/repository artifacts: paths: - analytics-service/target/*.jar expire_in: 1h rules: - if: $CI_COMMIT_BRANCH == "main" changes: - analytics-service/**/* build-rag-view: stage: build image: node:22-alpine cache: key: "${CI_COMMIT_REF_SLUG}-rag-view" paths: - rag-view/node_modules script: - cd rag-view - npm ci - npm run build artifacts: paths: - rag-view/dist expire_in: 1h rules: - if: $CI_COMMIT_BRANCH == "main" changes: - rag-view/**/* build-analytics-view: stage: build image: node:22-alpine cache: key: "${CI_COMMIT_REF_SLUG}-analytics-view" paths: - analytics-view/node_modules script: - cd analytics-view - npm ci - npm run build artifacts: paths: - analytics-view/dist expire_in: 1h rules: - if: $CI_COMMIT_BRANCH == "main" changes: - analytics-view/**/* build-auth-view: stage: build image: node:22-alpine cache: key: "${CI_COMMIT_REF_SLUG}-auth-view" paths: - auth-view/node_modules script: - cd auth-view - npm ci - npm run build artifacts: paths: - auth-view/dist expire_in: 1h rules: - if: $CI_COMMIT_BRANCH == "main" changes: - auth-view/**/* # ══════════════════════════════════════════════════════════ # PUBLISH DOCKER IMAGES # ══════════════════════════════════════════════════════════ publish-rag: stage: publish image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "" before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - docker build -t $REGISTRY/rag-service:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/rag-service:latest -f rag-service/docker/Dockerfile rag-service/ - docker push $REGISTRY/rag-service:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/rag-service:latest needs: [build-rag] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - rag-service/**/* publish-gateway: stage: publish image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "" before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - docker build -t $REGISTRY/gateway-service:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/gateway-service:latest -f gateway-service/docker/Dockerfile gateway-service/ - docker push $REGISTRY/gateway-service:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/gateway-service:latest needs: [build-gateway] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - gateway-service/**/* publish-analytics: stage: publish image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "" before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - docker build -t $REGISTRY/analytics-service:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/analytics-service:latest -f analytics-service/docker/Dockerfile analytics-service/ - docker push $REGISTRY/analytics-service:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/analytics-service:latest needs: [build-analytics] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - analytics-service/**/* publish-rag-view: stage: publish image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "" before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - docker build --build-arg VITE_GUEST_EMAIL=$VITE_GUEST_EMAIL --build-arg VITE_GUEST_PASSWORD=$VITE_GUEST_PASSWORD -t $REGISTRY/rag-view:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/rag-view:latest -f rag-view/docker/Dockerfile rag-view/ - docker push $REGISTRY/rag-view:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/rag-view:latest needs: [build-rag-view] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - rag-view/**/* publish-analytics-view: stage: publish image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "" before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - docker build -t $REGISTRY/analytics-view:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/analytics-view:latest -f analytics-view/docker/Dockerfile analytics-view/ - docker push $REGISTRY/analytics-view:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/analytics-view:latest needs: [build-analytics-view] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - analytics-view/**/* publish-auth-view: stage: publish image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "" before_script: - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin script: - docker build -t $REGISTRY/auth-view:${CI_COMMIT_SHORT_SHA} -t $REGISTRY/auth-view:latest -f auth-view/docker/Dockerfile auth-view/ - docker push $REGISTRY/auth-view:${CI_COMMIT_SHORT_SHA} - docker push $REGISTRY/auth-view:latest needs: [build-auth-view] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - auth-view/**/* # ══════════════════════════════════════════════════════════ # DEPLOY TO VPS # ══════════════════════════════════════════════════════════ .deploy_template: &deploy_setup stage: deploy image: alpine:3.20 before_script: - apk add --no-cache openssh-client - mkdir -p ~/.ssh - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keyscan -H $VPS_HOST >> ~/.ssh/known_hosts environment: name: production url: https://balexvic.com deploy-rag: <<: *deploy_setup needs: [publish-rag] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - rag-service/**/* script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull rag-service docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d rag-service docker image prune -af ENDSSH deploy-gateway: <<: *deploy_setup needs: [publish-gateway] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - gateway-service/**/* script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull gateway-service docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d gateway-service docker image prune -af ENDSSH deploy-analytics: <<: *deploy_setup needs: [publish-analytics] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - analytics-service/**/* script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull analytics-service docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d analytics-service docker image prune -af ENDSSH deploy-rag-view: <<: *deploy_setup needs: [publish-rag-view] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - rag-view/**/* script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull rag-view docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d rag-view docker image prune -af ENDSSH deploy-analytics-view: <<: *deploy_setup needs: [publish-analytics-view] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - analytics-view/**/* script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull analytics-view docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d analytics-view docker image prune -af ENDSSH deploy-auth-view: <<: *deploy_setup needs: [publish-auth-view] rules: - if: $CI_COMMIT_BRANCH == "main" changes: - auth-view/**/* script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull auth-view docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d auth-view docker image prune -af ENDSSH # Deploy all services at once (manual trigger) deploy-all: <<: *deploy_setup rules: - if: $CI_COMMIT_BRANCH == "main" when: manual allow_failure: true needs: [] script: - | ssh $VPS_USER@$VPS_HOST << ENDSSH set -e echo "$CI_REGISTRY_PASSWORD" | docker login registry.gitlab.com -u "$CI_REGISTRY_USER" --password-stdin cd /opt/services export CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA} docker compose -f docker-compose.yml -f docker-compose.prod.yml pull docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d docker image prune -af ENDSSH