diff --git a/production/.env.docker.production.example b/production/.env.docker.production.example index d4e33a7..b6dd441 100644 --- a/production/.env.docker.production.example +++ b/production/.env.docker.production.example @@ -5,7 +5,7 @@ PUBLIC_SITE_DOMAIN=rentaldrivego.ma PGMANAGE_DOMAIN=pgmanage.rentaldrivego.ma # Image tag -IMAGE_TAG=13d0512048d86e9fe93e9395459d04663c2b7eb0 +IMAGE_TAG=latest # Optional prebuilt image source. Set this when deploying from a private registry. APP_IMAGE=10.0.0.4/melabidi/carmanagement # APP_VERSION is accepted by helper scripts for compatibility, but IMAGE_TAG is preferred. diff --git a/production/README.md b/production/README.md index 5889037..736ef51 100644 --- a/production/README.md +++ b/production/README.md @@ -57,7 +57,7 @@ If the registry is only reachable inside a VPN container, use the shared archive IMAGE_ARCHIVE_DIR=/opt/docker-image-transfer IMAGE_ARCHIVE_REQUIRED=true APP_IMAGE=10.0.0.4/melabidi/carmanagement -IMAGE_TAG=13d0512048d86e9fe93e9395459d04663c2b7eb0 +IMAGE_TAG=latest REGISTRY_USER=melabidi ``` @@ -67,13 +67,19 @@ From the VPS, use the VPN container network to copy the image into the transfer VPN_CONTAINER="6c5dca44e1c2" ./fetch-image-through-vpn.sh ``` +Or fetch the archive and deploy in one command: + +```bash +VPN_CONTAINER="6c5dca44e1c2" ./deploy-production.sh --fetch-through-vpn +``` + Equivalent manual command: ```bash sudo mkdir -p /opt/docker-image-transfer sudo chmod 700 /opt/docker-image-transfer -IMAGE_TAG="13d0512048d86e9fe93e9395459d04663c2b7eb0" +IMAGE_TAG="latest" REGISTRY_USER="melabidi" VPN_CONTAINER="6c5dca44e1c2" @@ -95,6 +101,12 @@ docker run --rm \ Set the same `IMAGE_TAG` in `.env.docker.production`, then run the deployment. The deploy script will run `docker load -i /opt/docker-image-transfer/carmanagement-${IMAGE_TAG}.tar` before starting services. Because `IMAGE_ARCHIVE_REQUIRED=true`, the VPS will not try to pull from `10.0.0.4` directly. +If the VPS can reach the registry directly and you want to bypass archive loading, run: + +```bash +./deploy-production.sh --image-tag latest --pull-registry +``` + ## Deploy A Prebuilt Release ```bash diff --git a/production/deploy-production.sh b/production/deploy-production.sh index e6fbc01..052fb69 100755 --- a/production/deploy-production.sh +++ b/production/deploy-production.sh @@ -10,7 +10,7 @@ source "${ROOT_DIR}/scripts/docker-prod-common.sh" usage() { cat <<'EOF' Usage: - ./deploy-production.sh [--with-pgmanage] [--skip-prune] + ./deploy-production.sh [--with-pgmanage] [--skip-prune] [--image-tag ] [--fetch-through-vpn] [--pull-registry] What it does: 1. Validates .env.docker.production @@ -23,11 +23,19 @@ What it does: VPN/shared-folder image flow: Put an archive matching IMAGE_TAG in ./image-archives before running this script. Example: ./image-archives/carmanagement-latest.tar + +Options: + --image-tag Override IMAGE_TAG from .env.docker.production for this run + --fetch-through-vpn + Fetch IMAGE_TAG into IMAGE_ARCHIVE_DIR before deployment. + Requires VPN_CONTAINER and prompts for REGISTRY_TOKEN when unset. + --pull-registry Ignore IMAGE_ARCHIVE_DIR and pull directly from the registry EOF } include_pgmanage=0 skip_prune=0 +fetch_through_vpn=0 while [[ $# -gt 0 ]]; do case "$1" in @@ -39,6 +47,27 @@ while [[ $# -gt 0 ]]; do skip_prune=1 shift ;; + --image-tag) + if [[ -z "${2:-}" ]]; then + echo "--image-tag requires a tag value." >&2 + usage >&2 + exit 1 + fi + IMAGE_TAG="$2" + export IMAGE_TAG + shift 2 + ;; + --fetch-through-vpn) + fetch_through_vpn=1 + shift + ;; + --pull-registry) + IMAGE_ARCHIVE_DIR="" + IMAGE_ARCHIVE_REQUIRED=false + IMAGE_ARCHIVE_DISABLED=true + export IMAGE_ARCHIVE_DIR IMAGE_ARCHIVE_REQUIRED IMAGE_ARCHIVE_DISABLED + shift + ;; -h|--help) usage exit 0 @@ -51,6 +80,12 @@ while [[ $# -gt 0 ]]; do esac done +if [[ "${fetch_through_vpn}" -eq 1 && ("${IMAGE_ARCHIVE_DISABLED:-false}" == "true" || "${IMAGE_ARCHIVE_DISABLED:-0}" == "1") ]]; then + echo "--fetch-through-vpn and --pull-registry cannot be used together." >&2 + usage >&2 + exit 1 +fi + require_command() { local command_name="$1" @@ -60,6 +95,18 @@ require_command() { fi } +fetch_release_archive_through_vpn() { + if [[ "${fetch_through_vpn}" -ne 1 ]]; then + return 0 + fi + + echo "Fetching image archive through VPN container" + IMAGE_TAG="${IMAGE_TAG}" \ + APP_IMAGE="${APP_IMAGE:-10.0.0.4/melabidi/carmanagement}" \ + TRANSFER_DIR="${IMAGE_ARCHIVE_DIR:-/opt/docker-image-transfer}" \ + "${ROOT_DIR}/fetch-image-through-vpn.sh" "${IMAGE_TAG}" +} + normalize_archive_dir() { if [[ -z "${IMAGE_ARCHIVE_DIR:-}" ]]; then return 0 @@ -81,8 +128,16 @@ print_release_summary() { echo " Env: ${ENV_FILE}" echo " Compose project: ${PROJECT_NAME}" - if [[ -n "${IMAGE_ARCHIVE_DIR:-}" ]]; then + if [[ "${IMAGE_ARCHIVE_DISABLED:-false}" == "true" || "${IMAGE_ARCHIVE_DISABLED:-0}" == "1" ]]; then + echo " Image source: registry pull (archive loading disabled)" + elif [[ -n "${IMAGE_ARCHIVE_DIR:-}" ]]; then echo " Image archive dir: ${IMAGE_ARCHIVE_DIR}" + else + echo " Image source: registry pull" + fi + + if [[ "${IMAGE_ARCHIVE_REQUIRED:-false}" == "true" || "${IMAGE_ARCHIVE_REQUIRED:-0}" == "1" ]]; then + echo " Registry pull: disabled (IMAGE_ARCHIVE_REQUIRED=${IMAGE_ARCHIVE_REQUIRED})" fi } @@ -288,6 +343,7 @@ print_release_summary ensure_traefik_network ensure_api_uploads_volume +fetch_release_archive_through_vpn login_registry_if_configured echo "Preparing release image" diff --git a/production/scripts/docker-prod-common.sh b/production/scripts/docker-prod-common.sh index 3858ed9..0e0bd33 100755 --- a/production/scripts/docker-prod-common.sh +++ b/production/scripts/docker-prod-common.sh @@ -170,9 +170,13 @@ require_release_image() { } login_registry_if_configured() { + local archive_disabled="${IMAGE_ARCHIVE_DISABLED:-false}" + if [[ "${IMAGE_ARCHIVE_REQUIRED:-false}" == "true" || "${IMAGE_ARCHIVE_REQUIRED:-0}" == "1" ]]; then - echo "IMAGE_ARCHIVE_REQUIRED is enabled; skipping docker login." - return 0 + if [[ "${archive_disabled}" != "true" && "${archive_disabled}" != "1" ]]; then + echo "IMAGE_ARCHIVE_REQUIRED is enabled; skipping docker login." + return 0 + fi fi if [[ -n "${IMAGE_ARCHIVE_DIR:-}" && -d "${IMAGE_ARCHIVE_DIR}" ]]; then @@ -215,8 +219,10 @@ pull_prod_release_images() { if [[ "${IMAGE_ARCHIVE_REQUIRED:-false}" == "true" || "${IMAGE_ARCHIVE_REQUIRED:-0}" == "1" ]]; then echo "IMAGE_ARCHIVE_REQUIRED is enabled, but no archive for IMAGE_TAG=${IMAGE_TAG} was found in ${IMAGE_ARCHIVE_DIR:-}." >&2 - echo "The VPS cannot reach the VPN-only registry. Create a shared archive first, for example:" >&2 - echo " docker save ${APP_IMAGE:-rentaldrivego/carmanagement}:${IMAGE_TAG} -o ${IMAGE_ARCHIVE_DIR:-./image-archives}/carmanagement-${IMAGE_TAG}.tar" >&2 + echo "The VPS is configured for VPN/shared-folder image handoff. Create the archive first, for example:" >&2 + echo " VPN_CONTAINER= ./fetch-image-through-vpn.sh ${IMAGE_TAG}" >&2 + echo "Or let deploy fetch it before starting services:" >&2 + echo " VPN_CONTAINER= ./deploy-production.sh --fetch-through-vpn" >&2 exit 1 fi @@ -248,6 +254,11 @@ load_release_image_archives() { local archive local loaded=0 + if [[ "${IMAGE_ARCHIVE_DISABLED:-false}" == "true" || "${IMAGE_ARCHIVE_DISABLED:-0}" == "1" ]]; then + echo "Image archive loading is disabled; pulling from registry." + return 1 + fi + if [[ -z "${archive_dir}" ]]; then return 1 fi