#!/bin/bash set -euo pipefail # ============================================================================= # Build script for PostgreSQL 16→18 Upgrade Image with PostGIS # This image is used ONLY for the pg_upgrade process via CloudNativePG # ============================================================================= # Configuration REGISTRY="registry.keyboardvagabond.com/library" IMAGE_NAME="cnpg-postgis" TAG="upgrade-16-to-18" FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${TAG}" LOCAL_IMAGE="${IMAGE_NAME}:${TAG}" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "${BLUE}[STEP]${NC} $1"; } cd "$(dirname "$0")" echo "" echo "========================================================" echo " PostgreSQL 16→18 Upgrade Image Build (ARM64)" echo "========================================================" echo "" log_info "This builds a special image with BOTH PG16 and PG18 binaries" log_info "Required for CloudNativePG declarative pg_upgrade" log_warn "Build time: ~30-45 minutes (builds PostGIS twice)" log_info "Target: ${FULL_IMAGE}" echo "" # ============================================================================= # Build the upgrade image # ============================================================================= log_step "Starting Docker build with Dockerfile.upgrade..." BUILD_START=$(date +%s) docker build \ --platform linux/arm64 \ --progress=plain \ -f Dockerfile.upgrade \ -t "${FULL_IMAGE}" \ -t "${LOCAL_IMAGE}" \ . BUILD_END=$(date +%s) BUILD_TIME=$((BUILD_END - BUILD_START)) BUILD_MINS=$((BUILD_TIME / 60)) BUILD_SECS=$((BUILD_TIME % 60)) log_info "Build completed in ${BUILD_MINS}m ${BUILD_SECS}s" # ============================================================================= # Test the upgrade image # ============================================================================= echo "" log_step "Running verification tests..." # Test 1: Both PostgreSQL versions present log_info "Test 1: Checking PostgreSQL versions..." docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" bash -c ' echo " PG16: $(/usr/lib/postgresql/16/bin/postgres --version)" echo " PG18: $(/usr/lib/postgresql/18/bin/postgres --version)" ' # Test 2: pg_upgrade available log_info "Test 2: Checking pg_upgrade..." docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" bash -c ' /usr/lib/postgresql/18/bin/pg_upgrade --version && echo " ✓ pg_upgrade available" ' # Test 3: User ID check log_info "Test 3: Checking postgres user ID (should be 26)..." POSTGRES_UID=$(docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" id -u postgres) if [ "$POSTGRES_UID" = "26" ]; then echo " ✓ postgres UID is 26 (CNPG compatible)" else log_error "postgres UID is ${POSTGRES_UID}, expected 26" exit 1 fi # Test 4: PostGIS for both versions log_info "Test 4: Checking PostGIS libraries..." docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" bash -c ' echo " PG16 PostGIS:" ls /usr/lib/postgresql/16/lib/postgis*.so 2>/dev/null | xargs -I{} basename {} | sed "s/^/ /" echo " PG18 PostGIS:" ls /usr/lib/postgresql/18/lib/postgis*.so 2>/dev/null | xargs -I{} basename {} | sed "s/^/ /" ' # Test 5: Shared libraries log_info "Test 5: Checking shared libraries..." docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" bash -c ' echo " GEOS: $(geos-config --version 2>/dev/null || echo "not found")" echo " GDAL: $(gdal-config --version 2>/dev/null || echo "not found")" echo " PROJ: $(projinfo 2>&1 | head -1 || echo "installed")" ' # Test 6: Barman tools log_info "Test 6: Checking barman-cloud tools..." docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" \ bash -c 'ls /usr/local/bin/barman* >/dev/null 2>&1 && echo " ✓ barman-cloud tools available" || echo " ✗ barman-cloud tools not found"' # ============================================================================= # Summary # ============================================================================= echo "" echo "========================================================" log_info "Upgrade image build completed!" echo "========================================================" echo "" echo "Images built:" echo " Local: ${LOCAL_IMAGE}" echo " Harbor: ${FULL_IMAGE}" echo "" echo "Build time: ${BUILD_MINS}m ${BUILD_SECS}s" echo "" echo "To push to Harbor registry:" echo " docker push ${FULL_IMAGE}" echo "" echo "IMPORTANT: This image is for pg_upgrade ONLY!" echo "After upgrade completes, switch to: ${REGISTRY}/${IMAGE_NAME}:18-3.6" echo "" log_warn "Next steps:" echo " 1. Push image: docker push ${FULL_IMAGE}" echo " 2. Take Longhorn snapshot of postgres-shared volumes" echo " 3. Update cluster-shared.yaml imageName to: ${FULL_IMAGE}" echo " 4. Apply and monitor the upgrade" echo " 5. After success, switch to regular 18-3.6 image" echo ""