# ============================================================================= # PostgreSQL 18 + PostGIS 3.6 for CloudNativePG (ARM64 build from source) # ============================================================================= # This Dockerfile builds PostGIS from source for ARM64 architecture since # the official postgis/postgis images don't have ARM64 support for PG18 yet. # # Build: docker build --platform linux/arm64 -t cnpg-postgis:18-3.6 . # Test: docker run --rm -e POSTGRES_PASSWORD=test cnpg-postgis:18-3.6 postgres --version # ============================================================================= # ----------------------------------------------------------------------------- # Build arguments - Pin versions for reproducible builds # ----------------------------------------------------------------------------- ARG PG_MAJOR=18 ARG POSTGIS_VERSION=3.6.1 ARG GEOS_VERSION=3.13.0 # PROJ 9.4.1 is more stable for building; 9.5.x has additional deps ARG PROJ_VERSION=9.4.1 ARG GDAL_VERSION=3.10.1 ARG SFCGAL_VERSION=2.0.0 # ============================================================================= # Stage 1: Build PostGIS and dependencies from source # ============================================================================= FROM postgres:${PG_MAJOR}-bookworm AS builder ARG PG_MAJOR ARG POSTGIS_VERSION ARG GEOS_VERSION ARG PROJ_VERSION ARG GDAL_VERSION # Install build dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ # Build tools build-essential \ cmake \ ninja-build \ pkg-config \ git \ wget \ ca-certificates \ # PostgreSQL development postgresql-server-dev-${PG_MAJOR} \ # Required libraries libxml2-dev \ libjson-c-dev \ libprotobuf-c-dev \ protobuf-c-compiler \ libsqlite3-dev \ sqlite3 \ libtiff-dev \ libcurl4-openssl-dev \ libssl-dev \ zlib1g-dev \ liblzma-dev \ libzstd-dev \ libpng-dev \ libjpeg-dev \ libwebp-dev \ # Additional dependencies libpcre2-dev \ autoconf \ automake \ libtool \ # PROJ additional requirements nlohmann-json3-dev \ libgeotiff-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build # ----------------------------------------------------------------------------- # Build GEOS (Geometry Engine) # ----------------------------------------------------------------------------- RUN wget -q https://download.osgeo.org/geos/geos-${GEOS_VERSION}.tar.bz2 \ && tar xjf geos-${GEOS_VERSION}.tar.bz2 \ && cd geos-${GEOS_VERSION} \ && mkdir build && cd build \ && cmake .. \ -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local \ -DBUILD_TESTING=OFF \ && ninja \ && ninja install \ && cd /build && rm -rf geos-* # ----------------------------------------------------------------------------- # Build PROJ (Cartographic Projections) # ----------------------------------------------------------------------------- RUN wget -q https://download.osgeo.org/proj/proj-${PROJ_VERSION}.tar.gz \ && tar xzf proj-${PROJ_VERSION}.tar.gz \ && cd proj-${PROJ_VERSION} \ && mkdir build && cd build \ && cmake .. \ -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local \ -DBUILD_TESTING=OFF \ -DENABLE_CURL=ON \ -DENABLE_TIFF=ON \ && ninja \ && ninja install \ && cd /build && rm -rf proj-* # Update library cache after PROJ install RUN ldconfig # ----------------------------------------------------------------------------- # Build GDAL (Geospatial Data Abstraction Library) # ----------------------------------------------------------------------------- RUN wget -q https://github.com/OSGeo/gdal/releases/download/v${GDAL_VERSION}/gdal-${GDAL_VERSION}.tar.gz \ && tar xzf gdal-${GDAL_VERSION}.tar.gz \ && cd gdal-${GDAL_VERSION} \ && mkdir build && cd build \ && cmake .. \ -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local \ -DBUILD_TESTING=OFF \ -DBUILD_APPS=OFF \ -DGDAL_BUILD_OPTIONAL_DRIVERS=OFF \ -DOGR_BUILD_OPTIONAL_DRIVERS=OFF \ -DGDAL_USE_GEOS=ON \ -DGDAL_USE_PROJ=ON \ -DGDAL_USE_TIFF=ON \ -DGDAL_USE_GEOTIFF=ON \ -DGDAL_USE_PNG=ON \ -DGDAL_USE_JPEG=ON \ -DGDAL_USE_WEBP=ON \ -DGDAL_USE_CURL=ON \ -DGDAL_USE_SQLITE3=ON \ -DGDAL_USE_POSTGRESQL=ON \ && ninja \ && ninja install \ && cd /build && rm -rf gdal-* # Update library cache after GDAL install RUN ldconfig # ----------------------------------------------------------------------------- # Build PostGIS # ----------------------------------------------------------------------------- # Set library paths so configure can find GDAL, GEOS, PROJ ENV LD_LIBRARY_PATH=/usr/local/lib ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig RUN wget -q https://download.osgeo.org/postgis/source/postgis-${POSTGIS_VERSION}.tar.gz \ && tar xzf postgis-${POSTGIS_VERSION}.tar.gz \ && cd postgis-${POSTGIS_VERSION} \ && LDFLAGS="-L/usr/local/lib" \ CPPFLAGS="-I/usr/local/include" \ ./configure \ --with-pgconfig=/usr/lib/postgresql/${PG_MAJOR}/bin/pg_config \ --with-geosconfig=/usr/local/bin/geos-config \ --with-projdir=/usr/local \ --with-gdalconfig=/usr/local/bin/gdal-config \ --with-protobufdir=/usr \ --without-sfcgal \ && make -j$(nproc) \ && make install DESTDIR=/postgis-install \ && cd /build && rm -rf postgis-* # ============================================================================= # Stage 2: Get CNPG tools (barman-cloud for backup/restore) # ============================================================================= FROM ghcr.io/cloudnative-pg/postgresql:${PG_MAJOR} AS cnpg-tools # ============================================================================= # Stage 3: Final runtime image # ============================================================================= FROM postgres:${PG_MAJOR}-bookworm ARG PG_MAJOR ARG POSTGIS_VERSION LABEL maintainer="Keyboard Vagabond " LABEL description="PostgreSQL ${PG_MAJOR} with PostGIS ${POSTGIS_VERSION} for CloudNativePG (ARM64)" LABEL org.opencontainers.image.source="https://keyboardvagabond.com" ENV POSTGIS_MAJOR=3 ENV POSTGIS_VERSION=${POSTGIS_VERSION} # Install runtime dependencies only (no build tools) RUN apt-get update && apt-get install -y --no-install-recommends \ # Runtime libraries for GEOS/PROJ/GDAL/PostGIS libxml2 \ libjson-c5 \ libprotobuf-c1 \ libsqlite3-0 \ libtiff6 \ libcurl4 \ libssl3 \ zlib1g \ liblzma5 \ libzstd1 \ libpng16-16 \ libjpeg62-turbo \ libwebp7 \ libpcre2-8-0 \ # Additional utilities ca-certificates \ curl \ jq \ # Python for barman-cloud python3 \ python3-boto3 \ python3-botocore \ && rm -rf /var/lib/apt/lists/* # Copy compiled libraries from builder COPY --from=builder /usr/local/lib/ /usr/local/lib/ COPY --from=builder /usr/local/share/proj/ /usr/local/share/proj/ COPY --from=builder /usr/local/share/gdal/ /usr/local/share/gdal/ COPY --from=builder /usr/local/bin/geos-config /usr/local/bin/ COPY --from=builder /usr/local/bin/gdal-config /usr/local/bin/ COPY --from=builder /usr/local/bin/proj /usr/local/bin/ COPY --from=builder /usr/local/bin/projinfo /usr/local/bin/ # Copy PostGIS installation (modern PostGIS uses extension dir, not contrib) COPY --from=builder /postgis-install/usr/lib/postgresql/${PG_MAJOR}/lib/ /usr/lib/postgresql/${PG_MAJOR}/lib/ COPY --from=builder /postgis-install/usr/share/postgresql/${PG_MAJOR}/extension/ /usr/share/postgresql/${PG_MAJOR}/extension/ # Update library cache RUN ldconfig # Copy barman-cloud tools from CNPG image (they're in /usr/local/bin/) COPY --from=cnpg-tools /usr/local/bin/barman* /usr/local/bin/ # ----------------------------------------------------------------------------- # Fix user ID for CloudNativePG compatibility (requires UID 26) # ----------------------------------------------------------------------------- RUN set -eux; \ CURRENT_UID=$(id -u postgres); \ if [ "$CURRENT_UID" != "26" ]; then \ # Check if UID 26 is already in use if getent passwd 26 >/dev/null 2>&1; then \ EXISTING_USER=$(getent passwd 26 | cut -d: -f1); \ usermod -u 9999 "$EXISTING_USER" 2>/dev/null || true; \ fi; \ # Change postgres user to UID 26 usermod -u 26 postgres; \ # Fix ownership of postgres directories find /var/lib/postgresql -user $CURRENT_UID -exec chown -h 26 {} \; 2>/dev/null || true; \ find /var/run/postgresql -user $CURRENT_UID -exec chown -h 26 {} \; 2>/dev/null || true; \ chown -R postgres:postgres /var/lib/postgresql /var/run/postgresql 2>/dev/null || true; \ fi # Copy initialization and update scripts RUN mkdir -p /docker-entrypoint-initdb.d COPY ./initdb-postgis.sh /docker-entrypoint-initdb.d/10_postgis.sh COPY ./update-postgis.sh /usr/local/bin/ RUN chmod +x /docker-entrypoint-initdb.d/10_postgis.sh /usr/local/bin/update-postgis.sh # ----------------------------------------------------------------------------- # Verify installation # ----------------------------------------------------------------------------- RUN set -eux; \ postgres --version; \ echo "GEOS: $(geos-config --version)"; \ echo "PROJ: $(projinfo 2>&1 | head -1 || echo 'installed')"; \ echo "GDAL: $(gdal-config --version)"; \ id postgres; \ ls -la /usr/lib/postgresql/${PG_MAJOR}/lib/postgis*.so || true # Switch to postgres user USER postgres EXPOSE 5432