feat: build and install gdal and proj from source

pull/138/head
Nils Bühner 2025-01-21 18:59:05 +01:00
parent 5839d401f7
commit 8181cf5231
3 changed files with 201 additions and 26 deletions

View File

@ -1,18 +1,174 @@
FROM tomcat:9.0.98-jdk17-temurin-jammy@sha256:4cce4376204e1b73ec6864988d6a7da3f7648fd5209442323fabaa00fbe6c335 ARG BUILDER_BASE_IMAGE=eclipse-temurin:17-jdk-jammy
ARG GEOSERVER_BASE_IMAGE=tomcat:9.0.98-jdk17-temurin-jammy@sha256:4cce4376204e1b73ec6864988d6a7da3f7648fd5209442323fabaa00fbe6c335
ARG GS_VERSION=2.26.2
ARG BUILD_GDAL=false
ARG PROJ_VERSION=9.5.1
ARG GDAL_VERSION=3.10.1
ARG INSTALL_PREFIX=/usr/local
# This is a multi stage build.
# The gdal_builder image/stage can be enabled by using
# `--build-arg BUILD_GDAL=true`. The gdal_builder is derived
# from the osgeo/gdal Dockerfile (small ubuntu) and simplified
# version activating the JAVA features on top.
# It builds gdal from sources, which is necessary to get
# working gdal JAVA Bindings, e.g. for the geoserver gdal extension.
# see https://trac.osgeo.org/osgeolive/ticket/2288
#
# NOTE: the build process can take up to 15 mins on average hardware!
FROM $BUILDER_BASE_IMAGE AS gdal_builder
ARG BUILD_GDAL
ARG PROJ_VERSION
ARG GDAL_VERSION
ARG INSTALL_PREFIX
ENV HOME="/root"
USER root
# Setup build env for PROJ and GDAL
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
# we need these dirs at least empty for the later COPY...
mkdir -p /build_projgrids/usr/ \
mkdir -p /build${INSTALL_PREFIX}/share/proj/ \
mkdir -p /build${INSTALL_PREFIX}/include/\
mkdir -p /build${INSTALL_PREFIX}/bin/ \
mkdir -p /build${INSTALL_PREFIX}/lib/ \
mkdir -p /build/usr/share/bash-completion/ \
mkdir -p /build/usr/share/gdal/ \
mkdir -p /build/usr/include/ \
mkdir -p /build_gdal_python/usr/ \
mkdir -p /build_gdal_version_changing/usr/ \
&& if test "${BUILD_GDAL}" = "true"; then \
apt-get update -y \
&& apt-get upgrade -y \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --fix-missing --no-install-recommends \
# PROJ build dependencies
build-essential ca-certificates \
git make ninja-build cmake wget unzip libtool automake \
zlib1g-dev libsqlite3-dev pkg-config sqlite3 libcurl4-openssl-dev \
libtiff-dev patchelf rsync \
# GDAL build dependencies
python3-dev python3-numpy python3-setuptools \
libjpeg-dev libgeos-dev \
libexpat-dev libxerces-c-dev \
libwebp-dev libpng-dev \
libdeflate-dev \
libzstd-dev bash zip curl \
libpq-dev libssl-dev libopenjp2-7-dev \
libspatialite-dev \
libmuparser-dev \
autoconf automake sqlite3 bash-completion swig ant bison; \
fi
# Build PROJ
RUN --mount=type=cache,id=gs-proj,target=$HOME/.cache \
if test "${BUILD_GDAL}" = "true"; then \
export GCC_ARCH="$(uname -m)" \
&& mkdir -p /build_projgrids/${INSTALL_PREFIX}/share/proj \
&& curl -LO -fsS http://download.osgeo.org/proj/proj-datumgrid-latest.zip \
&& unzip -q -j -u -o proj-datumgrid-latest.zip -d /build_projgrids/${INSTALL_PREFIX}/share/proj \
&& rm -f *.zip \
&& mkdir proj \
&& wget -q https://github.com/OSGeo/PROJ/archive/${PROJ_VERSION}.tar.gz -O - \
| tar xz -C proj --strip-components=1 \
&& export PROJ_DB_CACHE_PARAM="" \
&& cd proj \
&& CFLAGS='-DPROJ_RENAME_SYMBOLS -O2' CXXFLAGS='-DPROJ_RENAME_SYMBOLS -DPROJ_INTERNAL_CPP_NAMESPACE -O2' \
cmake . \
-G Ninja \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
-DBUILD_TESTING=OFF \
$PROJ_DB_CACHE_PARAM \
&& ninja \
&& DESTDIR="/build" ninja install \
&& cd .. \
&& rm -rf proj \
&& PROJ_SO=$(readlink -f /build${INSTALL_PREFIX}/lib/libproj.so | awk 'BEGIN {FS="libproj.so."} {print $2}') \
&& PROJ_SO_FIRST=$(echo $PROJ_SO | awk 'BEGIN {FS="."} {print $1}') \
&& mv /build${INSTALL_PREFIX}/lib/libproj.so.${PROJ_SO} /build${INSTALL_PREFIX}/lib/libinternalproj.so.${PROJ_SO} \
&& ln -s libinternalproj.so.${PROJ_SO} /build${INSTALL_PREFIX}/lib/libinternalproj.so.${PROJ_SO_FIRST} \
&& ln -s libinternalproj.so.${PROJ_SO} /build${INSTALL_PREFIX}/lib/libinternalproj.so \
&& rm /build${INSTALL_PREFIX}/lib/libproj.* \
&& ${GCC_ARCH}-linux-gnu-strip -s /build${INSTALL_PREFIX}/lib/libinternalproj.so.${PROJ_SO} \
&& for i in /build${INSTALL_PREFIX}/bin/*; do ${GCC_ARCH}-linux-gnu-strip -s $i 2>/dev/null || /bin/true; done \
&& patchelf --set-soname libinternalproj.so.${PROJ_SO_FIRST} /build${INSTALL_PREFIX}/lib/libinternalproj.so.${PROJ_SO} \
&& for i in /build${INSTALL_PREFIX}/bin/*; do patchelf --replace-needed libproj.so.${PROJ_SO_FIRST} libinternalproj.so.${PROJ_SO_FIRST} $i; done \
fi
# Build GDAL
RUN --mount=type=cache,id=gs-gdal,target=$HOME/.cache \
if test "${BUILD_GDAL}" = "true"; then \
export GCC_ARCH="$(uname -m)" \
&& if test "${GDAL_VERSION}" = "master"; then \
export GDAL_VERSION=$(curl -Ls https://api.github.com/repos/OSGeo/gdal/commits/HEAD -H "Accept: application/vnd.github.VERSION.sha"); \
export GDAL_RELEASE_DATE=$(date "+%Y%m%d"); \
fi \
&& if test "${GCC_ARCH}" = "x86_64"; then \
export GDAL_CMAKE_EXTRA_OPTS="-DENABLE_IPO=ON"; \
else \
export GDAL_CMAKE_EXTRA_OPTS=""; \
fi \
&& mkdir gdal \
&& wget -q https://github.com/OSGeo/gdal/archive/v${GDAL_VERSION}.tar.gz -O - \
| tar xz -C gdal --strip-components=1 \
&& cd gdal \
&& mkdir build \
&& cd build \
&& CFLAGS='-DPROJ_RENAME_SYMBOLS -O2' CXXFLAGS='-DPROJ_RENAME_SYMBOLS -DPROJ_INTERNAL_CPP_NAMESPACE -O2 -Wno-psabi' \
cmake .. \
-G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DGDAL_FIND_PACKAGE_PROJ_MODE=MODULE \
-DPROJ_INCLUDE_DIR="/build${INSTALL_PREFIX-/usr/local}/include" \
-DPROJ_LIBRARY="/build${INSTALL_PREFIX-/usr/local}/lib/libinternalproj.so" \
-DGDAL_USE_TIFF_INTERNAL=ON \
-DGDAL_USE_GEOTIFF_INTERNAL=ON ${GDAL_CMAKE_EXTRA_OPTS} \
-DBUILD_TESTING=OFF \
-DBUILD_JAVA_BINDINGS=ON \
-DGDAL_JAVA_INSTALL_DIR=${INSTALL_PREFIX-/usr/local}/lib \
-DGDAL_JAVA_JNI_INSTALL_DIR=${INSTALL_PREFIX-/usr/local}/lib \
&& ninja \
&& DESTDIR="/build" ninja install \
&& cd .. \
&& cd .. \
&& rm -rf gdal \
&& mkdir -p /build_gdal_python/usr/lib \
&& mkdir -p /build_gdal_python/usr/bin \
&& mkdir -p /build_gdal_version_changing/usr/include \
&& mv /build/usr/lib/python* /build_gdal_python/usr/lib \
&& mv /build/usr/lib /build_gdal_version_changing/usr \
&& mv /build/usr/include/gdal_version.h /build_gdal_version_changing/usr/include \
&& mv /build/usr/bin/*.py /build_gdal_python/usr/bin \
&& mv /build/usr/bin /build_gdal_version_changing/usr \
&& for i in /build_gdal_version_changing/usr/lib/${GCC_ARCH}-linux-gnu/*; do ${GCC_ARCH}-linux-gnu-strip -s $i 2>/dev/null || /bin/true; done \
&& for i in /build_gdal_python/usr/lib/python3/dist-packages/osgeo/*.so; do ${GCC_ARCH}-linux-gnu-strip -s $i 2>/dev/null || /bin/true; done \
&& for i in /build_gdal_version_changing/usr/bin/*; do ${GCC_ARCH}-linux-gnu-strip -s $i 2>/dev/null || /bin/true; done \
fi
# final GeoServer image
FROM $GEOSERVER_BASE_IMAGE AS geoserver
LABEL vendor="osgeo.org" LABEL vendor="osgeo.org"
# Build arguments # Build arguments
ARG ADDITIONAL_FONTS_PATH=./additional_fonts/ ARG ADDITIONAL_FONTS_PATH=./additional_fonts/
ARG ADDITIONAL_LIBS_PATH=./additional_libs/ ARG ADDITIONAL_LIBS_PATH=./additional_libs/
ARG BUILD_GDAL
ARG COMMUNITY_PLUGIN_URL='' ARG COMMUNITY_PLUGIN_URL=''
ARG CORS_ALLOWED_HEADERS=Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers ARG CORS_ALLOWED_HEADERS=Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers
ARG CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS ARG CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS
ARG CORS_ALLOWED_ORIGINS=* ARG CORS_ALLOWED_ORIGINS=*
ARG CORS_ALLOW_CREDENTIALS=false ARG CORS_ALLOW_CREDENTIALS=false
ARG CORS_ENABLED=false ARG CORS_ENABLED=false
ARG GS_VERSION
ARG GS_BUILD=release ARG GS_BUILD=release
ARG GS_DATA_PATH=./geoserver_data/ ARG GS_DATA_PATH=./geoserver_data/
ARG GS_VERSION=2.26.2 ARG INSTALL_PREFIX
ARG STABLE_PLUGIN_URL=https://downloads.sourceforge.net/project/geoserver/GeoServer/${GS_VERSION}/extensions ARG STABLE_PLUGIN_URL=https://downloads.sourceforge.net/project/geoserver/GeoServer/${GS_VERSION}/extensions
ARG WAR_ZIP_URL=https://downloads.sourceforge.net/project/geoserver/GeoServer/${GS_VERSION}/geoserver-${GS_VERSION}-war.zip ARG WAR_ZIP_URL=https://downloads.sourceforge.net/project/geoserver/GeoServer/${GS_VERSION}/geoserver-${GS_VERSION}-war.zip
@ -35,6 +191,7 @@ ENV GEOSERVER_DATA_DIR=/opt/geoserver_data/
ENV GEOSERVER_LIB_DIR=$CATALINA_HOME/webapps/geoserver/WEB-INF/lib/ ENV GEOSERVER_LIB_DIR=$CATALINA_HOME/webapps/geoserver/WEB-INF/lib/
ENV SET_GEOSERVER_REQUIRE_FILE=true ENV SET_GEOSERVER_REQUIRE_FILE=true
ENV GEOSERVER_VERSION=$GS_VERSION ENV GEOSERVER_VERSION=$GS_VERSION
ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
ENV HEALTHCHECK_URL='' ENV HEALTHCHECK_URL=''
ENV INSTALL_EXTENSIONS=false ENV INSTALL_EXTENSIONS=false
ENV POSTGRES_JNDI_ENABLED=false ENV POSTGRES_JNDI_ENABLED=false
@ -49,16 +206,6 @@ ENV STABLE_PLUGIN_URL=$STABLE_PLUGIN_URL
ENV WAR_ZIP_URL=$WAR_ZIP_URL ENV WAR_ZIP_URL=$WAR_ZIP_URL
ENV WEBAPP_CONTEXT=geoserver ENV WEBAPP_CONTEXT=geoserver
# ENV JDK_JAVA_OPTIONS=--add-exports=java.desktop/sun.awt.image=ALL-UNNAMED \
# --add-opens=java.base/java.lang=ALL-UNNAMED \
# --add-opens=java.base/java.util=ALL-UNNAMED \
# --add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
# --add-opens=java.base/java.text=ALL-UNNAMED \
# --add-opens=java.desktop/java.awt.font=ALL-UNNAMED \
# --add-opens=java.desktop/sun.awt.image=ALL-UNNAMED \
# --add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED \
# --add-opens=java.desktop/sun.java2d.pipe=ALL-UNNAMED
# see https://docs.geoserver.org/stable/en/user/production/container.html # see https://docs.geoserver.org/stable/en/user/production/container.html
ENV CATALINA_OPTS="\$EXTRA_JAVA_OPTS \ ENV CATALINA_OPTS="\$EXTRA_JAVA_OPTS \
--add-exports=java.desktop/sun.awt.image=ALL-UNNAMED \ --add-exports=java.desktop/sun.awt.image=ALL-UNNAMED \
@ -84,12 +231,44 @@ WORKDIR /tmp
# Install dependencies # Install dependencies
RUN set -eux \ RUN set -eux \
&& export DEBIAN_FRONTEND=noninteractive \ && export DEBIAN_FRONTEND=noninteractive \
&& apt-get update \ && apt-get update -y \
&& apt-get install -y --no-install-recommends openssl unzip curl locales gettext gosu \ && apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
# Basic dependencies
openssl curl unzip locales gettext gosu \
&& if test "${BUILD_GDAL}" = "true"; then \
# PROJ dependencies
apt-get install -y --no-install-recommends libsqlite3-0 libtiff5 libcurl4 ca-certificates \
# GDAL dependencies
bash-completion python3-numpy libpython3.11 libjpeg-turbo8 libgeos3.10.2 libgeos-c1v5 \
libexpat1 libxerces-c3.2 libwebp7 libpng16-16 libdeflate0 libzstd1 bash libpq5 libssl3 \
libopenjp2-7 libspatialite7 libmuparser2v5 python3-pil python-is-python3; \
fi \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/cache/apt/* \ && rm -rf /var/cache/apt/* \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# install gdal (and proj)
# the source directories are empty in case of
# BUILD_GDAL=false
COPY --from=gdal_builder /build_projgrids/usr/ /usr/
COPY --from=gdal_builder /build${INSTALL_PREFIX}/share/proj/ ${INSTALL_PREFIX}/share/proj/
COPY --from=gdal_builder /build${INSTALL_PREFIX}/include/ ${INSTALL_PREFIX}/include/
COPY --from=gdal_builder /build${INSTALL_PREFIX}/bin/ ${INSTALL_PREFIX}/bin/
COPY --from=gdal_builder /build${INSTALL_PREFIX}/lib/ ${INSTALL_PREFIX}/lib/
COPY --from=gdal_builder /build/usr/share/bash-completion/ /usr/share/bash-completion/
COPY --from=gdal_builder /build/usr/share/gdal/ /usr/share/gdal/
COPY --from=gdal_builder /build/usr/include/ /usr/include/
COPY --from=gdal_builder /build_gdal_python/usr/ /usr/
COPY --from=gdal_builder /build_gdal_version_changing/usr/ /usr/
RUN if test "${BUILD_GDAL}" = "true"; then \
ldconfig; \
echo "source /usr/share/bash-completion/bash_completion" >> /root/.bashrc; \
fi
# Download geoserver # Download geoserver
RUN set -eux \ RUN set -eux \
&& echo "Downloading GeoServer ${GS_VERSION} ${GS_BUILD}" \ && echo "Downloading GeoServer ${GS_VERSION} ${GS_BUILD}" \
@ -143,14 +322,6 @@ RUN apt purge -y \
RUN chmod +x /opt/*.sh && sed -i 's/\r$//' /opt/startup.sh RUN chmod +x /opt/*.sh && sed -i 's/\r$//' /opt/startup.sh
# # Create a non-privileged tomcat user
# ARG USER_GID=999
# ARG USER_UID=999
# RUN addgroup --gid ${USER_GID} tomcat && \
# adduser --system -u ${USER_UID} --gid ${USER_GID} --no-create-home tomcat && \
# chown -R tomcat:tomcat /opt && \
# chown tomcat:tomcat $GEOSERVER_DATA_DIR
ENTRYPOINT ["bash", "/opt/startup.sh"] ENTRYPOINT ["bash", "/opt/startup.sh"]
WORKDIR /opt WORKDIR /opt

View File

@ -4,7 +4,7 @@ This Dockerfile can be used to create images for all geoserver versions since 2.
* Based on the official [`tomcat` docker image](https://hub.docker.com/_/tomcat), in particular: * Based on the official [`tomcat` docker image](https://hub.docker.com/_/tomcat), in particular:
* Tomcat 9 * Tomcat 9
* JDK11 (eclipse temurin) * JDK17 (eclipse temurin)
* Ubuntu Jammy (22.04 LTS) * Ubuntu Jammy (22.04 LTS)
* GeoServer installation is configurable and supports * GeoServer installation is configurable and supports
* Dynamic installation of extensions * Dynamic installation of extensions
@ -13,6 +13,7 @@ This Dockerfile can be used to create images for all geoserver versions since 2.
* Additional libraries * Additional libraries
* PostgreSQL JNDI * PostgreSQL JNDI
* HTTPS * HTTPS
* GDAL with Java Bindings
This README.md file covers use of official docker image, additional [build](BUILD.md) and [release](RELEASE.md) instructions are available. This README.md file covers use of official docker image, additional [build](BUILD.md) and [release](RELEASE.md) instructions are available.

View File

@ -63,7 +63,7 @@ if [[ $1 == *build* ]]; then
echo " nightly build from https://build.geoserver.org/geoserver/$BRANCH" echo " nightly build from https://build.geoserver.org/geoserver/$BRANCH"
echo echo
if [[ "$BRANCH" == "main" ]]; then if [[ "$BRANCH" == "main" ]]; then
echo "docker build --build-arg GS_VERSION=$VERSION --build-arg GS_BUILD=$BUILD -t $TAG ." echo "docker build --build-arg GS_VERSION=$VERSION --build-arg GS_BUILD=$BUILD --build-arg BUILD_GDAL=true -t $TAG ."
# todo: --no-cache-filter download,install # todo: --no-cache-filter download,install
docker build \ docker build \
--build-arg WAR_ZIP_URL=https://build.geoserver.org/geoserver/main/geoserver-main-latest-war.zip \ --build-arg WAR_ZIP_URL=https://build.geoserver.org/geoserver/main/geoserver-main-latest-war.zip \
@ -71,22 +71,25 @@ if [[ $1 == *build* ]]; then
--build-arg COMMUNITY_PLUGIN_URL=https://build.geoserver.org/geoserver/main/community-latest \ --build-arg COMMUNITY_PLUGIN_URL=https://build.geoserver.org/geoserver/main/community-latest \
--build-arg GS_VERSION=$VERSION \ --build-arg GS_VERSION=$VERSION \
--build-arg GS_BUILD=$BUILD \ --build-arg GS_BUILD=$BUILD \
--build-arg BUILD_GDAL=true \
-t $TAG . -t $TAG .
else else
echo "docker build --build-arg GS_VERSION=$VERSION --build-arg GS_BUILD=$BUILD -t $TAG ." echo "docker build --build-arg GS_VERSION=$VERSION --build-arg GS_BUILD=$BUILD --build-arg BUILD_GDAL=true -t $TAG ."
docker build \ docker build \
--build-arg WAR_ZIP_URL=https://build.geoserver.org/geoserver/$BRANCH/geoserver-$BRANCH-latest-war.zip \ --build-arg WAR_ZIP_URL=https://build.geoserver.org/geoserver/$BRANCH/geoserver-$BRANCH-latest-war.zip \
--build-arg STABLE_PLUGIN_URL=https://build.geoserver.org/geoserver/$BRANCH/ext-latest \ --build-arg STABLE_PLUGIN_URL=https://build.geoserver.org/geoserver/$BRANCH/ext-latest \
--build-arg COMMUNITY_PLUGIN_URL=https://build.geoserver.org/geoserver/$BRANCH/community-latest \ --build-arg COMMUNITY_PLUGIN_URL=https://build.geoserver.org/geoserver/$BRANCH/community-latest \
--build-arg GS_VERSION=$VERSION \ --build-arg GS_VERSION=$VERSION \
--build-arg GS_BUILD=$BUILD \ --build-arg GS_BUILD=$BUILD \
--build-arg BUILD_GDAL=true \
-t $TAG . -t $TAG .
fi fi
else else
echo "docker build --build-arg GS_VERSION=$VERSION --build-arg GS_BUILD=$BUILD -t $TAG ." echo "docker build --build-arg GS_VERSION=$VERSION --build-arg GS_BUILD=$BUILD --build-arg BUILD_GDAL=true -t $TAG ."
docker build \ docker build \
--build-arg GS_VERSION=$VERSION \ --build-arg GS_VERSION=$VERSION \
--build-arg GS_BUILD=$BUILD \ --build-arg GS_BUILD=$BUILD \
--build-arg BUILD_GDAL=true \
-t $TAG . -t $TAG .
fi fi
fi fi