name: Deploy to Production # Manual production deploy — pulls pre-built images 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 default: "latest" type: string env: BACKEND_IMAGE: git.koppkb.com/kopkb/my-kopkb-be FRONTEND_IMAGE: git.koppkb.com/kopkb/my-kopkb-fe DEPLOY_DIR: /home/arrahn/Project 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 images exist in registry run: | set -e IMAGE_TAG="${{ inputs.image_tag }}" for IMAGE in "${BACKEND_IMAGE}:${IMAGE_TAG}" "${FRONTEND_IMAGE}:${IMAGE_TAG}"; do 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" done - name: Pull Docker images run: | set -e IMAGE_TAG="${{ inputs.image_tag }}" docker pull "${BACKEND_IMAGE}:${IMAGE_TAG}" docker pull "${FRONTEND_IMAGE}:${IMAGE_TAG}" echo "✓ Images pulled successfully" - name: Sync compose file and deploy run: | set -e IMAGE_TAG="${{ inputs.image_tag }}" mkdir -p "${DEPLOY_DIR}" cp be/docker/production/docker-compose.production.yml "${DEPLOY_DIR}/docker-compose.yml" # nginx config is mounted from repo checkout path on each deploy NGINX_CONF="$(pwd)/be/docker/production/nginx/nginx.conf" if [ ! -f "${NGINX_CONF}" ]; then echo "ERROR: nginx config not found at ${NGINX_CONF}" exit 1 fi cd "${DEPLOY_DIR}" if [ ! -f .env.production ]; then echo "ERROR: ${DEPLOY_DIR}/.env.production is missing on the server" exit 1 fi # Optional compose-level env (REDIS_PASSWORD, API_PORT, FE_PORT, etc.) if [ -f .env ]; then set -a # shellcheck disable=SC1091 source .env set +a fi export IMAGE_TAG export NGINX_CONF docker compose -f docker-compose.yml pull backend frontend docker compose -f docker-compose.yml up -d --remove-orphans echo "✓ Deployed IMAGE_TAG=${IMAGE_TAG}" - name: Verify deployment run: | set -e echo "Waiting for services to start..." sleep 15 cd "${DEPLOY_DIR}" for SERVICE in backend frontend; 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 BE_CONTAINER=$(docker compose -f docker-compose.yml ps -q backend) if docker exec "$BE_CONTAINER" test -f /var/www/.env; then echo "✓ Backend .env file exists" else echo "WARNING: Backend .env file not found" fi if docker exec "$BE_CONTAINER" curl -sf http://localhost/health > /dev/null; then echo "✓ Backend health check passed" else echo "WARNING: Backend health check failed" fi FE_CONTAINER=$(docker compose -f docker-compose.yml ps -q frontend) if docker exec "$FE_CONTAINER" wget -q --spider http://localhost/; then echo "✓ Frontend health check passed" else echo "WARNING: Frontend health check failed" fi