name: Deploy Backend to Production # Manual production deploy — pulls pre-built backend image from the registry on: workflow_dispatch: inputs: image_tag: description: "Docker image tag to deploy (commit SHA or version tag, e.g. v1.0.0)" required: true type: string env: BACKEND_IMAGE: git.koppkb.com/kopkb/qms-be DEPLOY_DIR: /home/arrahn/Project/qms jobs: deploy: runs-on: host steps: - name: Checkout repository uses: actions/checkout@v4 with: ref: ${{ inputs.image_tag }} - name: Login to Docker registry run: | echo "${{ secrets.REGISTRY_PASSWORD }}" | \ docker login git.koppkb.com \ -u "${{ secrets.REGISTRY_USERNAME }}" \ --password-stdin - name: Verify backend image exists in registry run: | set -e IMAGE_TAG="${{ inputs.image_tag }}" IMAGE="${BACKEND_IMAGE}:${IMAGE_TAG}" echo "Checking if image exists: ${IMAGE}" if ! docker manifest inspect "${IMAGE}" > /dev/null 2>&1; then echo "ERROR: Image ${IMAGE} does not exist in registry!" exit 1 fi echo "✓ ${IMAGE} found" - name: Pull backend image run: | set -e IMAGE_TAG="${{ inputs.image_tag }}" docker pull "${BACKEND_IMAGE}:${IMAGE_TAG}" echo "✓ Image pulled successfully" - name: Sync compose file and deploy run: | set -e IMAGE_TAG="${{ inputs.image_tag }}" mkdir -p "${DEPLOY_DIR}" cp be/prod-compose.yml "${DEPLOY_DIR}/docker-compose.yml" cd "${DEPLOY_DIR}" if [ ! -f .env ]; then echo "ERROR: ${DEPLOY_DIR}/.env is missing on the server" echo "Create it from be/.env.example (or be/.env.production) before deploying." exit 1 fi export IMAGE_TAG export BACKEND_IMAGE docker compose -f docker-compose.yml pull backend docker compose -f docker-compose.yml up -d --remove-orphans echo "✓ Deployed IMAGE_TAG=${IMAGE_TAG}" - name: Verify deployment run: | set -e cd "${DEPLOY_DIR}" echo "Waiting for services to start..." sleep 15 for SERVICE in mysql backend; do STATUS=$(docker compose -f docker-compose.yml ps --status running --format '{{.Name}}' "$SERVICE" 2>/dev/null || true) if [ -z "$STATUS" ]; then echo "ERROR: ${SERVICE} is not running" docker compose -f docker-compose.yml ps docker compose -f docker-compose.yml logs --tail=50 "$SERVICE" || true exit 1 fi echo "✓ ${SERVICE} is running (${STATUS})" done BACKEND_HOST_PORT=$(grep -E '^BACKEND_HOST_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"' || true) BACKEND_HOST_PORT=${BACKEND_HOST_PORT:-8080} # No actuator yet — treat any HTTP response as "server is up" for i in 1 2 3 4 5 6 7 8; do CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:${BACKEND_HOST_PORT}/" || echo "000") if [ "${CODE}" != "000" ]; then echo "✓ Backend is responding on port ${BACKEND_HOST_PORT} (HTTP ${CODE})" exit 0 fi echo "Waiting for backend... attempt ${i}/8" sleep 5 done echo "ERROR: Backend is not responding on port ${BACKEND_HOST_PORT}" docker compose -f docker-compose.yml logs --tail=50 backend || true exit 1