# ============================================================================= # PostgreSQL 16→18 Upgrade Image for CloudNativePG pg_upgrade # ============================================================================= # This special image contains BOTH PG16 and PG18 binaries + PostGIS, required # for CloudNativePG's declarative pg_upgrade feature. # # Use this image ONLY for the upgrade process. After upgrade completes, # switch to the regular cnpg-postgis:18-3.6 image. # # Build: docker build --platform linux/arm64 -f Dockerfile.upgrade -t cnpg-postgis:upgrade-16-to-18 . # ============================================================================= # ----------------------------------------------------------------------------- # Build arguments - Pin versions for reproducible builds # ----------------------------------------------------------------------------- ARG PG_OLD=16 ARG PG_NEW=18 ARG POSTGIS_OLD=3.4.3 ARG POSTGIS_NEW=3.6.1 ARG GEOS_VERSION=3.13.0 ARG PROJ_VERSION=9.4.1 ARG GDAL_VERSION=3.10.1 # ============================================================================= # Stage 1: Build PostGIS for PG16 (old version) # ============================================================================= FROM postgres:16-bookworm AS builder-pg16 ARG POSTGIS_OLD ARG GEOS_VERSION ARG PROJ_VERSION ARG GDAL_VERSION # Install build dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential cmake ninja-build pkg-config git wget ca-certificates \ postgresql-server-dev-16 \ 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 \ libpcre2-dev autoconf automake libtool nlohmann-json3-dev libgeotiff-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build # Build GEOS 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 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-* && ldconfig # Build GDAL 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-* && ldconfig # Build PostGIS for PG16 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_OLD}.tar.gz \ && tar xzf postgis-${POSTGIS_OLD}.tar.gz \ && cd postgis-${POSTGIS_OLD} \ && LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include" \ ./configure \ --with-pgconfig=/usr/lib/postgresql/16/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-pg16 \ && cd /build && rm -rf postgis-* # ============================================================================= # Stage 2: Build PostGIS for PG18 (new version) # ============================================================================= FROM postgres:18-bookworm AS builder-pg18 ARG POSTGIS_NEW ARG GEOS_VERSION ARG PROJ_VERSION ARG GDAL_VERSION # Install build dependencies (same as PG16) RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential cmake ninja-build pkg-config git wget ca-certificates \ postgresql-server-dev-18 \ 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 \ libpcre2-dev autoconf automake libtool nlohmann-json3-dev libgeotiff-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build # Build GEOS 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 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-* && ldconfig # Build GDAL 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-* && ldconfig # Build PostGIS for PG18 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_NEW}.tar.gz \ && tar xzf postgis-${POSTGIS_NEW}.tar.gz \ && cd postgis-${POSTGIS_NEW} \ && LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include" \ ./configure \ --with-pgconfig=/usr/lib/postgresql/18/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-pg18 \ && cd /build && rm -rf postgis-* # ============================================================================= # Stage 3: Get CNPG tools # ============================================================================= FROM ghcr.io/cloudnative-pg/postgresql:18 AS cnpg-tools # ============================================================================= # Stage 4: Final multi-version runtime image # ============================================================================= FROM postgres:18-bookworm ARG PG_OLD=16 ARG PG_NEW=18 ARG POSTGIS_NEW LABEL maintainer="Keyboard Vagabond " LABEL description="PostgreSQL 16→18 upgrade image with PostGIS for CloudNativePG pg_upgrade (ARM64)" LABEL org.opencontainers.image.source="https://keyboardvagabond.com" LABEL pg.upgrade.from="16" LABEL pg.upgrade.to="18" ENV POSTGIS_MAJOR=3 ENV POSTGIS_VERSION=${POSTGIS_NEW} # Install runtime dependencies + PostgreSQL 16 binaries 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 ca-certificates curl jq \ # Python for barman-cloud python3 python3-boto3 python3-botocore \ # PostgreSQL 16 binaries (required for pg_upgrade) postgresql-16 \ && rm -rf /var/lib/apt/lists/* # Copy compiled libraries from PG18 builder (shared between both versions) COPY --from=builder-pg18 /usr/local/lib/ /usr/local/lib/ COPY --from=builder-pg18 /usr/local/share/proj/ /usr/local/share/proj/ COPY --from=builder-pg18 /usr/local/share/gdal/ /usr/local/share/gdal/ COPY --from=builder-pg18 /usr/local/bin/geos-config /usr/local/bin/ COPY --from=builder-pg18 /usr/local/bin/gdal-config /usr/local/bin/ COPY --from=builder-pg18 /usr/local/bin/proj /usr/local/bin/ COPY --from=builder-pg18 /usr/local/bin/projinfo /usr/local/bin/ # Copy PostGIS for PG16 (old version) COPY --from=builder-pg16 /postgis-install-pg16/usr/lib/postgresql/16/lib/ /usr/lib/postgresql/16/lib/ COPY --from=builder-pg16 /postgis-install-pg16/usr/share/postgresql/16/extension/ /usr/share/postgresql/16/extension/ # Copy PostGIS for PG18 (new version) COPY --from=builder-pg18 /postgis-install-pg18/usr/lib/postgresql/18/lib/ /usr/lib/postgresql/18/lib/ COPY --from=builder-pg18 /postgis-install-pg18/usr/share/postgresql/18/extension/ /usr/share/postgresql/18/extension/ # Update library cache RUN ldconfig # Copy barman-cloud tools from CNPG image 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 \ 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; \ usermod -u 26 postgres; \ 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 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 - both PG versions and PostGIS # ----------------------------------------------------------------------------- RUN set -eux; \ echo "=== PostgreSQL Versions ==="; \ /usr/lib/postgresql/16/bin/postgres --version; \ /usr/lib/postgresql/18/bin/postgres --version; \ echo "=== PostGIS Libraries ==="; \ ls -la /usr/lib/postgresql/16/lib/postgis*.so; \ ls -la /usr/lib/postgresql/18/lib/postgis*.so; \ echo "=== pg_upgrade Available ==="; \ /usr/lib/postgresql/18/bin/pg_upgrade --version; \ echo "=== Shared Libraries ==="; \ echo "GEOS: $(geos-config --version)"; \ echo "GDAL: $(gdal-config --version)"; \ id postgres USER postgres EXPOSE 5432