2025-12-24 14:35:17 +01:00
#!/bin/bash
2026-01-14 22:33:45 +02:00
set -euo pipefail
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
# =============================================================================
# Build script for ARM64 PostgreSQL 18 + PostGIS 3.6 image for CloudNativePG
# This builds PostGIS from source since ARM64 packages aren't available yet
# =============================================================================
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
# Configuration
REGISTRY = "registry.keyboardvagabond.com/library"
2025-12-24 14:35:17 +01:00
IMAGE_NAME = "cnpg-postgis"
2026-01-14 22:33:45 +02:00
PG_VERSION = "18"
POSTGIS_VERSION = "3.6"
TAG = " ${ PG_VERSION } - ${ POSTGIS_VERSION } "
2025-12-24 14:35:17 +01:00
FULL_IMAGE = " ${ REGISTRY } / ${ IMAGE_NAME } : ${ TAG } "
LOCAL_IMAGE = " ${ IMAGE_NAME } : ${ TAG } "
2026-01-14 22:33:45 +02:00
# Colors for output
RED = '\033[0;31m'
GREEN = '\033[0;32m'
YELLOW = '\033[1;33m'
BLUE = '\033[0;34m'
NC = '\033[0m' # No Color
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
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 ""
# =============================================================================
2025-12-24 14:35:17 +01:00
# Build the image
2026-01-14 22:33:45 +02:00
# =============================================================================
log_step "Starting Docker build..."
BUILD_START = $( date +%s)
2025-12-24 14:35:17 +01:00
docker build \
--platform linux/arm64 \
2026-01-14 22:33:45 +02:00
--progress= plain \
2025-12-24 14:35:17 +01:00
-t " ${ FULL_IMAGE } " \
2026-01-14 22:33:45 +02:00
-t " ${ LOCAL_IMAGE } " \
2025-12-24 14:35:17 +01:00
.
2026-01-14 22:33:45 +02:00
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 "
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
# =============================================================================
# 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
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
# 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" ) "
'
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
# 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"
'
2025-12-24 14:35:17 +01:00
2026-01-14 22:33:45 +02:00
# 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 "=============================================="
2025-12-24 14:35:17 +01:00
echo ""
2026-01-14 22:33:45 +02:00
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:"
2025-12-24 14:35:17 +01:00
echo " docker push ${ FULL_IMAGE } "
echo ""
2026-01-14 22:33:45 +02:00
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)"