diff --git a/.example.env b/.example.env index 37dad81..b408880 100644 --- a/.example.env +++ b/.example.env @@ -4,7 +4,7 @@ COMPOSE_PROJECT_NAME=postgis ## For build arguments DISTRO=debian -IMAGE_VERSION=bullseye +IMAGE_VERSION=bookworm IMAGE_VARIANT=slim # Set GENERATE_ALL_LOCALE to empty value or 0 to build just default LOCALE: en_US.UTF-8 GENERATE_ALL_LOCALE=1 @@ -15,5 +15,5 @@ LANGS="en_US.UTF-8,id_ID.UTF-8" POSTGRES_MAJOR_VERSION=15 POSTGIS_MAJOR_VERSION=3 -POSTGIS_MINOR_RELEASE=3 +POSTGIS_MINOR_RELEASE=4 BUILD_TIMESCALE=false \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..adee0ed --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" \ No newline at end of file diff --git a/.github/workflows/build-latest.yaml b/.github/workflows/build-latest.yaml index 02a2726..27b984c 100644 --- a/.github/workflows/build-latest.yaml +++ b/.github/workflows/build-latest.yaml @@ -9,7 +9,7 @@ on: # imageVersion: # description: Base distro image version/release # required: true -# default: bullseye +# default: bookworm # imageVariant: # description: Base image variant # required: true @@ -31,7 +31,7 @@ jobs: postgisMajorVersion: - 3 postgisMinorRelease: - - 3 + - 4 scenario: - datadir_init - streaming_replication @@ -41,7 +41,7 @@ jobs: - init_scripts include: - distro: debian - imageVersion: bullseye + imageVersion: bookworm imageVariant: slim steps: - uses: actions/checkout@v3 @@ -51,7 +51,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Build image for testing id: docker_build_testing_image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: Dockerfile @@ -93,10 +93,10 @@ jobs: postgisMajorVersion: - 3 postgisMinorRelease: - - 3 + - 4 include: - distro: debian - imageVersion: bullseye + imageVersion: bookworm imageVariant: slim steps: - uses: actions/checkout@v3 @@ -111,7 +111,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} - name: Docker meta id: docker_meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: ${{ secrets.DOCKERHUB_REPO}}/postgis tags: | @@ -121,7 +121,7 @@ jobs: - name: Build image for testing id: docker_build_testing_image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: Dockerfile diff --git a/.github/workflows/deploy-image.yaml b/.github/workflows/deploy-image.yaml index d0ee100..da6712f 100644 --- a/.github/workflows/deploy-image.yaml +++ b/.github/workflows/deploy-image.yaml @@ -9,7 +9,7 @@ on: # imageVersion: # description: Base distro image version/release # required: true -# default: bullseye +# default: bookworm # imageVariant: # description: Base image variant # required: true @@ -33,10 +33,10 @@ jobs: postgisMajorVersion: - 3 postgisMinorRelease: - - 3 + - 4 include: - distro: debian - imageVersion: bullseye + imageVersion: bookworm imageVariant: slim steps: - uses: actions/checkout@v3 @@ -61,7 +61,7 @@ jobs: - name: Build base image id: docker_build_base - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . platforms: linux/amd64,linux/arm64 @@ -87,7 +87,7 @@ jobs: - name: Build prod image id: docker_build_prod - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/Dockerfile b/Dockerfile index 8ce7962..dc89c26 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # Base stage # ############################################################################## ARG DISTRO=debian -ARG IMAGE_VERSION=bullseye +ARG IMAGE_VERSION=bookworm ARG IMAGE_VARIANT=slim FROM $DISTRO:$IMAGE_VERSION-$IMAGE_VARIANT AS postgis-base LABEL maintainer="Tim Sutton" @@ -23,13 +23,13 @@ RUN set -eux \ && apt-get update \ && apt-get -y --no-install-recommends install \ locales gnupg2 wget ca-certificates rpl pwgen software-properties-common iputils-ping \ - apt-transport-https curl gettext \ - && dpkg-divert --local --rename --add /sbin/initctl - -RUN apt-get -y update; apt-get -y install build-essential autoconf libxml2-dev zlib1g-dev netcat gdal-bin \ + apt-transport-https curl gettext pgxnclient cmake && \ + apt-get -y install build-essential autoconf libxml2-dev zlib1g-dev netcat-openbsd gdal-bin \ figlet toilet gosu; \ # verify that the binary works - gosu nobody true + gosu nobody true && \ + dpkg-divert --local --rename --add /sbin/initctl + # Generating locales takes a long time. Utilize caching by runnig it by itself # early in the build process. @@ -56,6 +56,8 @@ RUN if [ -z "${GENERATE_ALL_LOCALE}" ] || [ $GENERATE_ALL_LOCALE -eq 0 ]; \ && /usr/sbin/locale-gen RUN update-locale ${LANG} + + # Cleanup resources RUN apt-get -y --purge autoremove \ && apt-get clean \ @@ -72,7 +74,7 @@ FROM postgis-base AS postgis-prod ARG IMAGE_VERSION ARG POSTGRES_MAJOR_VERSION=15 ARG POSTGIS_MAJOR_VERSION=3 -ARG POSTGIS_MINOR_RELEASE=3 +ARG POSTGIS_MINOR_RELEASE=4 ARG TIMESCALE_VERSION=2-2.9.1 ARG BUILD_TIMESCALE=false @@ -94,18 +96,19 @@ RUN set -eux \ # We add postgis as well to prevent build errors (that we dont see on local builds) # on docker hub e.g. # The following packages have unmet dependencies: -#TODO add postgresql-${POSTGRES_MAJOR_VERSION}-cron back when it's available + RUN set -eux \ && export DEBIAN_FRONTEND=noninteractive \ && apt-get update \ && apt-get -y --no-install-recommends install postgresql-client-${POSTGRES_MAJOR_VERSION} \ postgresql-common postgresql-${POSTGRES_MAJOR_VERSION} \ postgresql-${POSTGRES_MAJOR_VERSION}-postgis-${POSTGIS_MAJOR_VERSION} \ - netcat postgresql-${POSTGRES_MAJOR_VERSION}-ogr-fdw \ + postgresql-${POSTGRES_MAJOR_VERSION}-ogr-fdw \ postgresql-${POSTGRES_MAJOR_VERSION}-postgis-${POSTGIS_MAJOR_VERSION}-scripts \ postgresql-plpython3-${POSTGRES_MAJOR_VERSION} postgresql-${POSTGRES_MAJOR_VERSION}-pgrouting \ postgresql-server-dev-${POSTGRES_MAJOR_VERSION} postgresql-${POSTGRES_MAJOR_VERSION}-cron \ - postgresql-${POSTGRES_MAJOR_VERSION}-mysql-fdw + postgresql-${POSTGRES_MAJOR_VERSION}-mysql-fdw && \ + pgxn install h3 # TODO a case insensitive match would be more robust RUN if [ "${BUILD_TIMESCALE}" = "true" ]; then \ @@ -116,9 +119,8 @@ RUN if [ "${BUILD_TIMESCALE}" = "true" ]; then \ apt-get -y --no-install-recommends install timescaledb-${TIMESCALE_VERSION}-postgresql-${POSTGRES_MAJOR_VERSION} timescaledb-tools;\ fi; -RUN echo $POSTGRES_MAJOR_VERSION >/tmp/pg_version.txt -RUN echo $POSTGIS_MAJOR_VERSION >/tmp/pg_major_version.txt -RUN echo $POSTGIS_MINOR_RELEASE >/tmp/pg_minor_version.txt +RUN echo $POSTGRES_MAJOR_VERSION >/tmp/pg_version.txt && echo $POSTGIS_MAJOR_VERSION >/tmp/pg_major_version.txt && \ + echo $POSTGIS_MINOR_RELEASE >/tmp/pg_minor_version.txt ENV \ PATH="$PATH:/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin" # Compile pointcloud extension @@ -166,4 +168,4 @@ RUN set -eux \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -RUN pip3 install -r /lib/utils/requirements.txt +RUN pip3 install -r /lib/utils/requirements.txt --break-system-packages diff --git a/README.md b/README.md index 6a30b87..a67a2c0 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,13 @@ POSTGRES_MULTIPLE_EXTENSIONS=postgis,pgrouting:3.4.0 where `pgrouting:3.4.0` The extension name is fixed with the version name with the delimiter being a colon. +**Note** In some cases, some versions of extensions might not be available for +install. To enable them you can do the following inside the container: +```bash +wget --directory-prefix /usr/share/postgresql/15/extension/ https://raw.githubusercontent.com/postgres/postgres/master/contrib/hstore/hstore--1.1--1.2.sql +``` +Then proceed to install it the normal way. + #### Shared preload libraries Some PostgreSQL extensions require shared_preload_libraries to be specified in the conf files. diff --git a/docker-compose.yml b/docker-compose.yml index 3de538d..cf526fe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ volumes: services: db: - image: kartoza/postgis:15-3.3 + image: kartoza/postgis:${POSTGRES_MAJOR_VERSION}-${POSTGIS_MAJOR_VERSION}.${POSTGIS_MINOR_RELEASE} volumes: - postgis-data:/var/lib/postgresql - dbbackups:/backups @@ -21,14 +21,14 @@ services: - POSTGRES_MULTIPLE_EXTENSIONS=postgis,hstore,postgis_topology,postgis_raster,pgrouting - RUN_AS_ROOT=true ports: - - "5432" + - "25432:5432" restart: on-failure healthcheck: test: "PGPASSWORD=docker pg_isready -h 127.0.0.1 -U docker -d gis" dbbackups: - image: kartoza/pg-backup:15-3.3 + image: kartoza/pg-backup:${POSTGRES_MAJOR_VERSION}-${POSTGIS_MAJOR_VERSION}.${POSTGIS_MINOR_RELEASE} hostname: pg-backups volumes: - dbbackups:/backups @@ -41,4 +41,4 @@ services: restart: on-failure depends_on: db: - condition: service_healthy \ No newline at end of file + condition: service_healthy diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh index f71a096..680f205 100755 --- a/scripts/docker-entrypoint.sh +++ b/scripts/docker-entrypoint.sh @@ -69,7 +69,7 @@ if [[ $# -eq 0 ]];then if [[ ${RUN_AS_ROOT} =~ [Tt][Rr][Uu][Ee] ]];then echo -e "[Entrypoint] \e[1;31m Postgres initialisation process completed .... restarting in foreground \033[0m" non_root_permission postgres postgres - su - postgres -c "$SETVARS $POSTGRES -D $DATADIR -c config_file=$CONF" + exec su - postgres -c "$SETVARS $POSTGRES -D $DATADIR -c config_file=$CONF" else echo -e "[Entrypoint] \e[1;31m Postgres initialisation process completed .... restarting in foreground with gosu \033[0m" non_root_permission "${USER_NAME}" "${DB_GROUP_NAME}" diff --git a/scripts/env-data.sh b/scripts/env-data.sh index 832dc71..7bd8841 100644 --- a/scripts/env-data.sh +++ b/scripts/env-data.sh @@ -56,6 +56,7 @@ RECOVERY_CONF="$ROOT_CONF/recovery.conf" POSTGRES="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/postgres" INITDB="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/initdb" SQLDIR="/usr/share/postgresql/${POSTGRES_MAJOR_VERSION}/contrib/postgis-${POSTGIS_MAJOR}.${POSTGIS_MINOR_RELEASE}/" +EXTDIR="/usr/share/postgresql/${POSTGRES_MAJOR_VERSION}/extension/" SETVARS="POSTGIS_ENABLE_OUTDB_RASTERS=1 POSTGIS_GDAL_ENABLED_DRIVERS=ENABLE_ALL" LOCALONLY="-c listen_addresses='127.0.0.1'" PG_BASEBACKUP="/usr/bin/pg_basebackup" @@ -553,6 +554,7 @@ function over_write_conf() { } + function extension_install() { DATABASE=$1 IFS=':' @@ -565,13 +567,30 @@ function extension_install() { psql ${DATABASE} -U ${POSTGRES_USER} -p 5432 -h localhost -c "CREATE EXTENSION IF NOT EXISTS \"${EXTENSION_NAME}\" cascade;" fi else - echo -e "\e[32m [Entrypoint] Installing extension \e[1;31m ${EXTENSION_NAME} \e[32m with version \e[1;31m ${EXTENSION_VERSION} \e[32m in the database : \e[1;31m ${DATABASE} \033[0m" if [[ ${EXTENSION_NAME} != 'pg_cron' ]]; then - psql ${DATABASE} -U ${POSTGRES_USER} -p 5432 -h localhost -c "CREATE EXTENSION IF NOT EXISTS \"${EXTENSION_NAME}\" WITH VERSION '${EXTENSION_VERSION}' cascade;" + pattern="${EXTENSION_NAME}--" + last_numbers=() + for file in "$EXTDIR"/${pattern}*; do + filename=$(basename "$file" .sql) + if [[ "$filename" == *"--"* ]]; then + last_number=$(echo "$filename" | awk -F '--' '{print $NF}') + if [[ ! " ${last_numbers[@]} " =~ " $last_number " ]]; then + last_numbers+=("$last_number") + fi + fi + done + if [[ " ${last_numbers[@]} " =~ " $EXTENSION_VERSION " ]]; then + echo -e "\e[32m [Entrypoint] Installing extension \e[1;31m ${EXTENSION_NAME} \e[32m with version \e[1;31m ${EXTENSION_VERSION} \e[32m in the database : \e[1;31m ${DATABASE} \033[0m" + psql ${DATABASE} -U ${POSTGRES_USER} -p 5432 -h localhost -c "CREATE EXTENSION IF NOT EXISTS \"${EXTENSION_NAME}\" WITH VERSION '${EXTENSION_VERSION}' cascade;" + else + echo -e "\e[32m [Entrypoint] Extension \e[1;31m ${EXTENSION_NAME} \e[32m with version \e[1;31m ${EXTENSION_VERSION} \e[32m is not available for install, available versions to install are \e[1;31m "${last_numbers[@]}" \033[0m" + fi + fi fi } + function directory_checker() { DATA_PATH=$1 if [ -d $DATA_PATH ];then @@ -600,3 +619,13 @@ function non_root_permission() { } +function role_check() { + ROLE_NAME=$1 + echo "Creating user $1" + RESULT=$(su - postgres -c "psql postgres -t -c \"SELECT 1 FROM pg_roles WHERE rolname = '$ROLE_NAME'\"") + COMMAND="ALTER" + if [ -z "$RESULT" ]; then + export COMMAND="CREATE" + fi + +} diff --git a/scripts/setup-user.sh b/scripts/setup-user.sh index 52d1c48..502fbd7 100644 --- a/scripts/setup-user.sh +++ b/scripts/setup-user.sh @@ -4,32 +4,12 @@ source /scripts/env-data.sh # This script will setup new configured user -# Note that $POSTGRES_USER and $POSTGRES_PASS below are optional parameters that can be passed -# via docker run e.g. -#docker run --name="postgis" -e POSTGRES_USER=qgis -e POSTGRES_PASS=qgis -d -v -#/var/docker-data/postgres-dat:/var/lib/postgresql -t qgis/postgis:6 - -# If you dont specify a user/password in docker run, we will generate one -# here and create a user called 'docker' to go with it. - -# Only create credentials if this is a master database -# Slave database will just mirror from master users - # Check user already exists -echo "Creating superuser $POSTGRES_USER" -RESULT=`su - postgres -c "psql postgres -t -c \"SELECT 1 FROM pg_roles WHERE rolname = '$POSTGRES_USER'\""` -COMMAND="ALTER" -if [ -z "$RESULT" ]; then - COMMAND="CREATE" -fi + +role_check $POSTGRES_USER su - postgres -c "psql postgres -c \"$COMMAND USER $POSTGRES_USER WITH SUPERUSER ENCRYPTED PASSWORD '$POSTGRES_PASS';\"" -echo "Creating replication user $REPLICATION_USER" -RESULT_REPLICATION=`su - postgres -c "psql postgres -t -c \"SELECT 1 FROM pg_roles WHERE rolname = '$REPLICATION_USER'\""` -COMMANDS="ALTER" -if [ -z "$RESULT_REPLICATION" ]; then - COMMANDS="CREATE" -fi -su - postgres -c "psql postgres -c \"$COMMANDS USER $REPLICATION_USER WITH REPLICATION ENCRYPTED PASSWORD '$REPLICATION_PASS';\"" +role_check $REPLICATION_USER +su - postgres -c "psql postgres -c \"$COMMAND USER $REPLICATION_USER WITH REPLICATION ENCRYPTED PASSWORD '$REPLICATION_PASS';\""