From 89b8803654c29dd70c2d7d65125f1acd9d10ef9e Mon Sep 17 00:00:00 2001 From: "emmanuel.duchastenier@bonitasoft.com" Date: Mon, 30 Sep 2024 10:41:15 +0200 Subject: [PATCH] chore(postgres): add support to Postgres 16.x (#17) Relates to https://bonitasoft.atlassian.net/browse/PROD-365 --- README.md | 2 +- postgres/16/0_init-databases.sql | 24 ++++++ postgres/16/1_update-postgresql-conf.sh | 4 + postgres/16/2_restore_dump.sh | 36 ++++++++ postgres/16/Dockerfile | 27 ++++++ postgres/16/README.md | 110 ++++++++++++++++++++++++ postgres/16/healthcheck.sh | 30 +++++++ 7 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 postgres/16/0_init-databases.sql create mode 100644 postgres/16/1_update-postgresql-conf.sh create mode 100644 postgres/16/2_restore_dump.sh create mode 100644 postgres/16/Dockerfile create mode 100644 postgres/16/README.md create mode 100755 postgres/16/healthcheck.sh diff --git a/README.md b/README.md index 5b4af71..1b7fc65 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Run Docker command depending on the DB vendor and related version: docker build -t bonitasoft/bonita-: . ``` -For instance with PostgreSQL: `docker build -t bonitasoft/bonita-postgres:15.4 .` +For instance with PostgreSQL: `docker build -t bonitasoft/bonita-postgres:16.4 .` ## Publish images on Docker Hub diff --git a/postgres/16/0_init-databases.sql b/postgres/16/0_init-databases.sql new file mode 100644 index 0000000..f51c2df --- /dev/null +++ b/postgres/16/0_init-databases.sql @@ -0,0 +1,24 @@ +CREATE ROLE bonita LOGIN PASSWORD 'bpm'; + +CREATE DATABASE bonita + WITH OWNER = bonita + ENCODING = 'UTF8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + +GRANT CONNECT, TEMPORARY ON DATABASE bonita TO public; + +GRANT ALL ON DATABASE bonita TO bonita; + + +CREATE ROLE business_data LOGIN PASSWORD 'bpm'; + +CREATE DATABASE business_data + WITH OWNER = business_data + ENCODING = 'UTF8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + +GRANT CONNECT, TEMPORARY ON DATABASE business_data TO public; + +GRANT ALL ON DATABASE business_data TO business_data; \ No newline at end of file diff --git a/postgres/16/1_update-postgresql-conf.sh b/postgres/16/1_update-postgresql-conf.sh new file mode 100644 index 0000000..f6f4262 --- /dev/null +++ b/postgres/16/1_update-postgresql-conf.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# set max_prepared_transactions to 100 +sed -i "s/^.*max_prepared_transactions\s*=\s*\(.*\)$/max_prepared_transactions = 100/" "$PGDATA"/postgresql.conf diff --git a/postgres/16/2_restore_dump.sh b/postgres/16/2_restore_dump.sh new file mode 100644 index 0000000..7314193 --- /dev/null +++ b/postgres/16/2_restore_dump.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e +## +## Restore dumps from volume /opt/bonita/dump +## dumps should have name bonita.dump and business_data.dump +## dump using: pg_dump -h localhost -p 5432 -Ubonita bonita> bonita.dump + +if [ -f /var/lib/postgresql/restore.lastExecution ]; then + echo "Restore already executed: skipping dump restoration." +else + touch /var/lib/postgresql/restore.inProgress + # plain text dump + if [ -f /opt/bonita/dump/bonita.dump ]; then + pg_restore -d bonita -U bonita /var/lib/postgresql/restore.lastExecution + fi + if [ -f /opt/bonita/dump/business_data.dump ]; then + psql -d business_data -U business_data /var/lib/postgresql/restore.lastExecution + fi + # compressed backup done using + # pg_dump with -l option to generate the list file + if [ -f /opt/bonita/dump/bonita.list ]; then + echo "Restore bonita" + pg_restore -d bonita -U bonita -Fc -L /opt/bonita/dump/bonita.list /opt/bonita/dump/bonita.pgdump + psql -d bonita -U bonita -c "VACUUM ANALYZE" + date >/var/lib/postgresql/restore.lastExecution + fi + if [ -f /opt/bonita/dump/business_data.list ]; then + echo "Restore business_data" + pg_restore -d business_data -U business_data -Fc -L /opt/bonita/dump/business_data.list /opt/bonita/dump/business_data.pgdump + psql -d business_data -U business_data -c "VACUUM ANALYZE" + date >/var/lib/postgresql/restore.lastExecution + fi + rm -vf /var/lib/postgresql/restore.inProgress +fi diff --git a/postgres/16/Dockerfile b/postgres/16/Dockerfile new file mode 100644 index 0000000..3dc8661 --- /dev/null +++ b/postgres/16/Dockerfile @@ -0,0 +1,27 @@ +FROM postgres:16.4-alpine + +# OCI annotations to image +LABEL org.opencontainers.image.authors="Bonita R&D Engine Team" \ + org.opencontainers.image.title="Bonita Postgres Database" \ + org.opencontainers.image.description="Pre-configured Postgres database image to work with Bonita" \ + org.opencontainers.image.documentation="https://github.com/Bonitasoft-Community/bonita-database-docker" \ + org.opencontainers.image.source="https://github.com/Bonitasoft-Community/bonita-database-docker" \ + org.opencontainers.image.vendor="Bonitasoft" \ + org.opencontainers.image.url="https://www.bonitasoft.com/" \ + org.opencontainers.image.licenses="GPL-2.0" \ + org.opencontainers.image.version="16.4" + +ENV POSTGRES_PASSWORD=change-me + +# allow to bind volume for database backup/restore +VOLUME /opt/bonita/sql + +# restore dump on startup if dumpfile is present +VOLUME /opt/bonita/dump + +COPY 0_init-databases.sql /docker-entrypoint-initdb.d/0_init-databases.sql +COPY 1_update-postgresql-conf.sh /docker-entrypoint-initdb.d/1_update-postgresql-conf.sh +COPY 2_restore_dump.sh /docker-entrypoint-initdb.d/2_restore_dump.sh +COPY --chmod=755 healthcheck.sh /usr/local/bin/healthcheck.sh + +HEALTHCHECK --interval=5s --retries=120 CMD ["/usr/local/bin/healthcheck.sh"] diff --git a/postgres/16/README.md b/postgres/16/README.md new file mode 100644 index 0000000..272cdbc --- /dev/null +++ b/postgres/16/README.md @@ -0,0 +1,110 @@ +# Pre-configured Postgres database image to work with Bonita + +This image is based on the [official Postgres image](https://hub.docker.com/_/postgres). + +## Additions + +### Configuration + +The property `max_prepared_transactions` is required by Bonita and is set to `100`. + +### Databases + +This image is configured with the two databases required by Bonita: + +* `bonita` (connection user `bonita`, password `bpm`) +* `business_data` (connection user `business_data`, password `bpm`) + +## How to use this image + +- Default way: + +```shell +docker run -d --name bonita-postgres -p 5432:5432 bonitasoft/bonita-postgres:16.4 +``` + +- Recommended way, to have datafiles out of container by binding a volume to **/var/lib/postgresql/data**: + +```shell +docker run -d \ + --name bonita-postgres \ + -p 5432:5432 \ + -v /my/postgres/datadir:/var/lib/postgresql/data \ + bonitasoft/bonita-postgres:16.4 +``` + +- With local volume for backup/restore and script exchange: + +```shell +docker run -d \ + --name bonita-postgres \ + -p 5432:5432 \ + -v /my/postgres/datadir:/var/lib/postgresql/data \ + -v /my/sql/folder:/opt/bonita/sql \ + bonitasoft/bonita-postgres:16.4 +``` + +## Container shell access + +```shell +docker exec -it bonita-postgres bash +``` + +## Viewing Postgres logs + +```shell +docker logs bonita-postgres +``` + +## How to restore dump + +It will restore dumps present in the volume `/opt/bonita/dump` + +For plain text sql form, dumps must be named `bonita.dump` and `business_data.dump` + +Create those dump using: + +```shell +pg_dump -h localhost -p 5432 -Ubonita bonita > /opt/bonita/dump/bonita.dump +pg_dump -h localhost -p 5432 -Ubusiness_data business_data > /opt/bonita/dump/business_data.dump +``` + +For compressed format, dumps must be named `bonita.pgdump` and `business_data.pgdump`. This format is used with a .list +file that allow to whitelist items to restore: + +```shell +# --quote-all-identifiers : ensure no issues with bonita columns name that use a PostgreSQL reserved word +# --encoding=utf8 : required +# -F c : use PostgreSQL compress format +pg_dump -h localhost -p 5432 -U bonita --quote-all-identifiers --encoding=utf8 -F c bonita > /opt/bonita/dump/bonita.pgdump + +# prepare white-list file for pg_restore +# this will read backup file and generate a TOC (Table Of Content) stored in a white list file +# then edit this file to comment with a `;` items you don't want to restore +pg_restore -l /opt/bonita/dump/bonita.pgdump > /opt/bonita/dump/bonita.list + +# same for BDM +pg_dump -h localhost -p 5432 -U business_data --quote-all-identifiers --encoding=utf8 -F c business_data > /opt/bonita/dump/business_data.pgdump +pg_restore -l /opt/bonita/dump/business_data.pgdump > /opt/bonita/dump/business_data.list +``` + +Then run the docker using volume `-v /my/postgres/dump:/opt/bonita/dump` + + Note: if container already exists, it must be removed, using `docker rm `, unless restore will not be applied + +### Restore dump from file not using default 'bonita' schema + +* Create a container with: + * Extra parameter `-e POSTGRES_PASSWORD=mysecretpassword`, in order to be able to access the tables with a known + user (`postgres`) and password + * Extra volume mapping parameter with the dump file, to access it easily from within the container. For example: + ```shell + docker run -d --name postgres-from-dump -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -v /my/postgres/dump:/opt/bonita/dump bonitasoft/bonita-postgres:16.4 + ``` +* Access the new container through `docker exec -it postgres-from-dump` +* Run `psql -U postgres bonita < ./my_dump_file.sql` + +## How to use this image with Bonita + +Please refer to [Bonitasoft official documentation](https://documentation.bonitasoft.com/bonita/latest/runtime/bonita-docker-installation) +for examples on how to run this image using a Bonita Docker image. diff --git a/postgres/16/healthcheck.sh b/postgres/16/healthcheck.sh new file mode 100755 index 0000000..5a2b9cf --- /dev/null +++ b/postgres/16/healthcheck.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# inspired by https://github.com/docker-library/healthcheck +set -eo pipefail + +# check if restore is in progress (see 2_restore_dump.sh) +if [ -f /var/lib/postgresql/restore.inProgress ]; then + echo "Database restore in progress. Not yet healthy." + exit 1 +fi + +host="$(hostname -i || echo '127.0.0.1')" +user="bonita" +db="bonita" +export PGPASSWORD="bpm" + +args=( + # force postgres to not use the local unix socket (test "external" connectivity) + --host "$host" + --username "$user" + --dbname "$db" + --quiet --no-align --tuples-only +) + +if select="$(echo 'SELECT 1' | psql "${args[@]}")" && [ "$select" = '1' ]; then + # host is healthy + exit 0 +fi + +# host is not healthy +exit 1