Fix production deployment for public site routing
Build & Push / Build & Push Docker Image (push) Failing after 3m35s
Build & Push / Build & Push Docker Image (push) Failing after 3m35s
- pass `NEXT_PUBLIC_CARPLACE_URL` into the production Docker build - keep `NEXT_PUBLIC_STOREFRONT_URL` as a backward-compatible fallback - run the production deploy script from the Gitea workflow after building - include `homepage` in production deploy, pull, and health-check service lists - allow deploy to use a release image already built locally on the VPS
This commit is contained in:
@@ -92,6 +92,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
|
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
|
||||||
NEXT_PUBLIC_HOMEPAGE_URL: ${{ secrets.NEXT_PUBLIC_HOMEPAGE_URL }}
|
NEXT_PUBLIC_HOMEPAGE_URL: ${{ secrets.NEXT_PUBLIC_HOMEPAGE_URL }}
|
||||||
|
NEXT_PUBLIC_CARPLACE_URL: ${{ secrets.NEXT_PUBLIC_CARPLACE_URL }}
|
||||||
NEXT_PUBLIC_STOREFRONT_URL: ${{ secrets.NEXT_PUBLIC_STOREFRONT_URL }}
|
NEXT_PUBLIC_STOREFRONT_URL: ${{ secrets.NEXT_PUBLIC_STOREFRONT_URL }}
|
||||||
NEXT_PUBLIC_DASHBOARD_URL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_URL }}
|
NEXT_PUBLIC_DASHBOARD_URL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_URL }}
|
||||||
NEXT_PUBLIC_ADMIN_URL: ${{ secrets.NEXT_PUBLIC_ADMIN_URL }}
|
NEXT_PUBLIC_ADMIN_URL: ${{ secrets.NEXT_PUBLIC_ADMIN_URL }}
|
||||||
@@ -113,9 +114,13 @@ jobs:
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if [ -z "$NEXT_PUBLIC_CARPLACE_URL" ] && [ -n "$NEXT_PUBLIC_STOREFRONT_URL" ]; then
|
||||||
|
NEXT_PUBLIC_CARPLACE_URL="${NEXT_PUBLIC_STOREFRONT_URL%/}/carplace"
|
||||||
|
fi
|
||||||
|
|
||||||
validate_url NEXT_PUBLIC_API_URL "$NEXT_PUBLIC_API_URL"
|
validate_url NEXT_PUBLIC_API_URL "$NEXT_PUBLIC_API_URL"
|
||||||
validate_url NEXT_PUBLIC_HOMEPAGE_URL "$NEXT_PUBLIC_HOMEPAGE_URL"
|
validate_url NEXT_PUBLIC_HOMEPAGE_URL "$NEXT_PUBLIC_HOMEPAGE_URL"
|
||||||
validate_url NEXT_PUBLIC_STOREFRONT_URL "$NEXT_PUBLIC_STOREFRONT_URL"
|
validate_url NEXT_PUBLIC_CARPLACE_URL "$NEXT_PUBLIC_CARPLACE_URL"
|
||||||
validate_url NEXT_PUBLIC_DASHBOARD_URL "$NEXT_PUBLIC_DASHBOARD_URL"
|
validate_url NEXT_PUBLIC_DASHBOARD_URL "$NEXT_PUBLIC_DASHBOARD_URL"
|
||||||
validate_url NEXT_PUBLIC_ADMIN_URL "$NEXT_PUBLIC_ADMIN_URL"
|
validate_url NEXT_PUBLIC_ADMIN_URL "$NEXT_PUBLIC_ADMIN_URL"
|
||||||
validate_url SITE_ORIGIN "$SITE_ORIGIN"
|
validate_url SITE_ORIGIN "$SITE_ORIGIN"
|
||||||
@@ -245,6 +250,7 @@ jobs:
|
|||||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
|
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
|
||||||
NEXT_PUBLIC_HOMEPAGE_URL: ${{ secrets.NEXT_PUBLIC_HOMEPAGE_URL }}
|
NEXT_PUBLIC_HOMEPAGE_URL: ${{ secrets.NEXT_PUBLIC_HOMEPAGE_URL }}
|
||||||
|
NEXT_PUBLIC_CARPLACE_URL: ${{ secrets.NEXT_PUBLIC_CARPLACE_URL }}
|
||||||
NEXT_PUBLIC_STOREFRONT_URL: ${{ secrets.NEXT_PUBLIC_STOREFRONT_URL }}
|
NEXT_PUBLIC_STOREFRONT_URL: ${{ secrets.NEXT_PUBLIC_STOREFRONT_URL }}
|
||||||
NEXT_PUBLIC_DASHBOARD_URL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_URL }}
|
NEXT_PUBLIC_DASHBOARD_URL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_URL }}
|
||||||
NEXT_PUBLIC_ADMIN_URL: ${{ secrets.NEXT_PUBLIC_ADMIN_URL }}
|
NEXT_PUBLIC_ADMIN_URL: ${{ secrets.NEXT_PUBLIC_ADMIN_URL }}
|
||||||
@@ -259,6 +265,9 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
SSH_OPTIONS="-i $HOME/.ssh/id_rsa -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=$HOME/.ssh/known_hosts"
|
SSH_OPTIONS="-i $HOME/.ssh/id_rsa -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=$HOME/.ssh/known_hosts"
|
||||||
REGISTRY_PASSWORD_B64="$(printf '%s' "$REGISTRY_PASSWORD" | base64 | tr -d '\n')"
|
REGISTRY_PASSWORD_B64="$(printf '%s' "$REGISTRY_PASSWORD" | base64 | tr -d '\n')"
|
||||||
|
if [ -z "$NEXT_PUBLIC_CARPLACE_URL" ] && [ -n "$NEXT_PUBLIC_STOREFRONT_URL" ]; then
|
||||||
|
NEXT_PUBLIC_CARPLACE_URL="${NEXT_PUBLIC_STOREFRONT_URL%/}/carplace"
|
||||||
|
fi
|
||||||
ssh $SSH_OPTIONS "${{ secrets.VPS_USER }}@$VPS_HOST" "
|
ssh $SSH_OPTIONS "${{ secrets.VPS_USER }}@$VPS_HOST" "
|
||||||
set -e
|
set -e
|
||||||
cd '$REMOTE_BUILD_DIR'
|
cd '$REMOTE_BUILD_DIR'
|
||||||
@@ -281,7 +290,7 @@ jobs:
|
|||||||
--build-arg ADMIN_INTERNAL_URL=http://admin:3002 \
|
--build-arg ADMIN_INTERNAL_URL=http://admin:3002 \
|
||||||
--build-arg NEXT_PUBLIC_API_URL='$NEXT_PUBLIC_API_URL' \
|
--build-arg NEXT_PUBLIC_API_URL='$NEXT_PUBLIC_API_URL' \
|
||||||
--build-arg NEXT_PUBLIC_HOMEPAGE_URL='$NEXT_PUBLIC_HOMEPAGE_URL' \
|
--build-arg NEXT_PUBLIC_HOMEPAGE_URL='$NEXT_PUBLIC_HOMEPAGE_URL' \
|
||||||
--build-arg NEXT_PUBLIC_STOREFRONT_URL='$NEXT_PUBLIC_STOREFRONT_URL' \
|
--build-arg NEXT_PUBLIC_CARPLACE_URL='$NEXT_PUBLIC_CARPLACE_URL' \
|
||||||
--build-arg NEXT_PUBLIC_DASHBOARD_URL='$NEXT_PUBLIC_DASHBOARD_URL' \
|
--build-arg NEXT_PUBLIC_DASHBOARD_URL='$NEXT_PUBLIC_DASHBOARD_URL' \
|
||||||
--build-arg NEXT_PUBLIC_ADMIN_URL='$NEXT_PUBLIC_ADMIN_URL' \
|
--build-arg NEXT_PUBLIC_ADMIN_URL='$NEXT_PUBLIC_ADMIN_URL' \
|
||||||
--build-arg SITE_ORIGIN='$SITE_ORIGIN' \
|
--build-arg SITE_ORIGIN='$SITE_ORIGIN' \
|
||||||
@@ -291,3 +300,39 @@ jobs:
|
|||||||
docker push '$IMAGE_LATEST'
|
docker push '$IMAGE_LATEST'
|
||||||
fi
|
fi
|
||||||
"
|
"
|
||||||
|
|
||||||
|
- name: Deploy production stack on VPS
|
||||||
|
env:
|
||||||
|
IMAGE_REPOSITORY: ${{ steps.image-meta.outputs.repository }}
|
||||||
|
IMAGE_TAG: ${{ gitea.sha }}
|
||||||
|
ENV_DOCKER_PRODUCTION_B64: ${{ secrets.ENV_DOCKER_PRODUCTION_B64 }}
|
||||||
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
REMOTE_BUILD_DIR: ${{ env.DEPLOY_ROOT }}/build-context
|
||||||
|
VPS_HOST: ${{ secrets.VPS_IP }}
|
||||||
|
run: |
|
||||||
|
VPS_HOST="${VPS_HOST:-$DEPLOY_SSH_HOST}"
|
||||||
|
if [ -z "$VPS_HOST" ]; then
|
||||||
|
echo "::error::VPS_IP secret or DEPLOY_SSH_HOST is required"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$ENV_DOCKER_PRODUCTION_B64" ]; then
|
||||||
|
echo "::error::ENV_DOCKER_PRODUCTION_B64 is required to deploy the production stack"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SSH_OPTIONS="-i $HOME/.ssh/id_rsa -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=$HOME/.ssh/known_hosts"
|
||||||
|
ENV_DOCKER_PRODUCTION_B64_CLEAN="$(printf '%s' "$ENV_DOCKER_PRODUCTION_B64" | tr -d '[:space:]')"
|
||||||
|
REGISTRY_PASSWORD_B64="$(printf '%s' "$REGISTRY_PASSWORD" | base64 | tr -d '\n')"
|
||||||
|
ssh $SSH_OPTIONS "${{ secrets.VPS_USER }}@$VPS_HOST" "
|
||||||
|
set -e
|
||||||
|
mkdir -p '$DEPLOY_ROOT'
|
||||||
|
printf '%s' '$ENV_DOCKER_PRODUCTION_B64_CLEAN' | base64 -d > '$DEPLOY_ROOT/.env.docker.production'
|
||||||
|
chmod 600 '$DEPLOY_ROOT/.env.docker.production'
|
||||||
|
cd '$REMOTE_BUILD_DIR'
|
||||||
|
export APP_IMAGE='$DEPLOY_REGISTRY_HOST/$IMAGE_REPOSITORY'
|
||||||
|
export IMAGE_TAG='$IMAGE_TAG'
|
||||||
|
export REGISTRY_HOST='$DEPLOY_REGISTRY_HOST'
|
||||||
|
export REGISTRY_USER='$REGISTRY_USERNAME'
|
||||||
|
export REGISTRY_PASSWORD=\"\$(printf '%s' '$REGISTRY_PASSWORD_B64' | base64 -d)\"
|
||||||
|
bash scripts/docker-prod-deploy.sh
|
||||||
|
"
|
||||||
|
|||||||
@@ -349,6 +349,12 @@ pull_prod_release_images() {
|
|||||||
require_release_image
|
require_release_image
|
||||||
ensure_registry_transport_configured
|
ensure_registry_transport_configured
|
||||||
|
|
||||||
|
local release_image="${APP_IMAGE:-rentaldrivego/carmanagement}:${IMAGE_TAG}"
|
||||||
|
if [[ "${IMAGE_TAG}" != "latest" ]] && docker image inspect "${release_image}" >/dev/null 2>&1; then
|
||||||
|
echo "Release image ${release_image} is already present locally; skipping docker pull."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
if load_release_image_archives; then
|
if load_release_image_archives; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -360,7 +366,7 @@ pull_prod_release_images() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
prod_compose pull migrate api carplace dashboard admin
|
prod_compose pull migrate api homepage carplace dashboard admin
|
||||||
}
|
}
|
||||||
|
|
||||||
load_release_image_archives() {
|
load_release_image_archives() {
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ echo "Running database migrations"
|
|||||||
run_prod_migrations
|
run_prod_migrations
|
||||||
|
|
||||||
echo "Starting application services"
|
echo "Starting application services"
|
||||||
prod_compose up -d api carplace dashboard admin
|
prod_compose up -d api homepage carplace dashboard admin
|
||||||
wait_for_healthy api 180
|
wait_for_healthy api 180
|
||||||
|
wait_for_healthy homepage 180
|
||||||
wait_for_healthy carplace 180
|
wait_for_healthy carplace 180
|
||||||
wait_for_healthy dashboard 180
|
wait_for_healthy dashboard 180
|
||||||
wait_for_healthy admin 180
|
wait_for_healthy admin 180
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ echo "Applying migrations"
|
|||||||
prod_compose run --rm migrate
|
prod_compose run --rm migrate
|
||||||
|
|
||||||
echo "Starting application services"
|
echo "Starting application services"
|
||||||
app_services=(api carplace dashboard admin)
|
app_services=(api homepage carplace dashboard admin)
|
||||||
|
|
||||||
if [[ "${INCLUDE_PGMANAGE}" == "1" ]]; then
|
if [[ "${INCLUDE_PGMANAGE}" == "1" ]]; then
|
||||||
prod_compose --profile private-tools up -d "${app_services[@]}" pgmanage
|
prod_compose --profile private-tools up -d "${app_services[@]}" pgmanage
|
||||||
@@ -98,6 +98,7 @@ else
|
|||||||
prod_compose up -d "${app_services[@]}"
|
prod_compose up -d "${app_services[@]}"
|
||||||
fi
|
fi
|
||||||
wait_for_healthy api 180
|
wait_for_healthy api 180
|
||||||
|
wait_for_healthy homepage 180
|
||||||
wait_for_healthy carplace 180
|
wait_for_healthy carplace 180
|
||||||
wait_for_healthy dashboard 180
|
wait_for_healthy dashboard 180
|
||||||
wait_for_healthy admin 180
|
wait_for_healthy admin 180
|
||||||
|
|||||||
Reference in New Issue
Block a user