#!/bin/bash set -euo pipefail # ============================================================================= # Build script for ARM64 PostgreSQL 18 + PostGIS 3.6 image for CloudNativePG # This builds PostGIS from source since ARM64 packages aren't available yet # ============================================================================= # Configuration REGISTRY="registry.keyboardvagabond.com/library" IMAGE_NAME="cnpg-postgis" PG_VERSION="18" POSTGIS_VERSION="3.6" TAG="${PG_VERSION}-${POSTGIS_VERSION}" 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' # No Color 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" } # Change to script directory cd "$(dirname "$0")" echo "" echo "==============================================" echo " PostgreSQL ${PG_VERSION} + PostGIS ${POSTGIS_VERSION} ARM64 Build" echo "==============================================" echo "" log_info "Building from source (this will take 15-30 minutes)" log_info "Target: ${FULL_IMAGE}" echo "" # ============================================================================= # Build the image # ============================================================================= log_step "Starting Docker build..." BUILD_START=$(date +%s) docker build \ --platform linux/arm64 \ --progress=plain \ -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 image # ============================================================================= echo "" log_step "Running tests..." # Test 1: PostgreSQL version log_info "Test 1: Checking PostgreSQL version..." PG_VER=$(docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" postgres --version) echo " ${PG_VER}" # Test 2: User ID check (CNPG requires UID 26) log_info "Test 2: 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 3: Library check log_info "Test 3: Checking compiled 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 4: PostGIS extension files log_info "Test 4: Checking PostGIS extension files..." docker run --rm --platform linux/arm64 "${LOCAL_IMAGE}" bash -c ' ls /usr/lib/postgresql/18/lib/postgis*.so 2>/dev/null && echo " ✓ PostGIS shared libraries present" || echo " ✗ PostGIS libraries missing" ls /usr/share/postgresql/18/extension/postgis*.control 2>/dev/null && echo " ✓ PostGIS extension control files present" || echo " ✗ Extension control files missing" ' # Test 5: Full PostGIS functionality test log_info "Test 5: Testing PostGIS functionality..." docker run --rm --platform linux/arm64 \ -e POSTGRES_PASSWORD=testpassword \ "${LOCAL_IMAGE}" \ bash -c ' set -e # Initialize database initdb -D /tmp/pgdata -U postgres >/dev/null 2>&1 # Start PostgreSQL pg_ctl -D /tmp/pgdata -o "-c listen_addresses='\'\''" start -w >/dev/null 2>&1 # Create extensions psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS postgis;" >/dev/null 2>&1 psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS postgis_topology;" >/dev/null 2>&1 psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;" >/dev/null 2>&1 psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS postgis_tiger_geocoder;" >/dev/null 2>&1 # Get version POSTGIS_VER=$(psql -U postgres -t -c "SELECT postgis_full_version();" 2>/dev/null | head -1 | xargs) echo " PostGIS: ${POSTGIS_VER:0:80}..." # Test spatial query psql -U postgres -c "SELECT ST_AsText(ST_Point(0,0));" >/dev/null 2>&1 echo " ✓ Spatial queries working" # Stop PostgreSQL pg_ctl -D /tmp/pgdata stop >/dev/null 2>&1 ' && echo " ✓ All PostGIS extensions functional" || log_warn "PostGIS test had issues (check manually)" # 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 "Build and tests 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 test interactively:" echo " docker run -it --rm -e POSTGRES_PASSWORD=test ${LOCAL_IMAGE} bash" echo "" echo "To test with docker-compose:" echo " docker-compose -f docker-compose.test.yaml up -d" echo " docker-compose -f docker-compose.test.yaml exec postgres psql -U postgres" echo "" echo "To push to Harbor registry:" echo " docker push ${FULL_IMAGE}" echo "" echo "To update CNPG cluster, change imageName in cluster-shared.yaml to:" echo " imageName: ${FULL_IMAGE}" echo "" log_warn "NOTE: PG18 uses /var/lib/postgresql as data dir (not /var/lib/postgresql/data)"