From 1177b29b475d3eb2026b7142d84dcdf167b7e52c Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 8 Aug 2022 13:26:28 +0200 Subject: [PATCH 1/2] Add the latest container-common-scripts Signed-off-by: Petr "Stone" Hracek --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 93fb9c19..95018da4 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 93fb9c196b26e18a8de6f0b16702bc0afa7cc744 +Subproject commit 95018da4490445cfc5d54b956ccebb0019b5c315 From 0815688e5ee4e27487ffbe0f477f4c09651717f0 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 8 Aug 2022 13:27:10 +0200 Subject: [PATCH 2/2] Add distgen generated files Signed-off-by: Petr "Stone" Hracek --- 11/README.md | 1 + 11/cccp.yml | 1 + 11/content_sets.yml | 10 + 11/root/usr/bin/container-entrypoint | 3 + 11/root/usr/bin/run-postgresql | 58 +++ 11/root/usr/bin/run-postgresql-master | 5 + 11/root/usr/bin/run-postgresql-slave | 37 ++ 11/root/usr/bin/usage | 4 + 11/root/usr/libexec/check-container | 27 + 11/root/usr/libexec/fix-permissions | 39 ++ .../container-scripts/postgresql/README.md | 331 ++++++++++++ .../container-scripts/postgresql/common.sh | 479 ++++++++++++++++++ ...ustom-postgresql-replication.conf.template | 7 + .../openshift-custom-postgresql.conf.template | 21 + .../openshift-custom-recovery.conf.template | 9 + .../container-scripts/postgresql/scl_enable | 3 + .../postgresql/start/set_passwords.sh | 23 + 11/s2i/bin/assemble | 14 + 11/s2i/bin/run | 1 + 11/s2i/bin/usage | 1 + 11/test | 1 + 12/Dockerfile.c8s | 84 +++ 12/Dockerfile.rhel7 | 94 ++++ 12/Dockerfile.rhel8 | 85 ++++ 12/README.md | 1 + 12/cccp.yml | 1 + 12/content_sets.yml | 10 + 12/root/usr/bin/container-entrypoint | 3 + 12/root/usr/bin/run-postgresql | 58 +++ 12/root/usr/bin/run-postgresql-master | 5 + 12/root/usr/bin/run-postgresql-slave | 39 ++ 12/root/usr/bin/usage | 4 + 12/root/usr/libexec/check-container | 27 + 12/root/usr/libexec/fix-permissions | 39 ++ .../container-scripts/postgresql/README.md | 331 ++++++++++++ .../container-scripts/postgresql/common.sh | 479 ++++++++++++++++++ ...ustom-postgresql-replication.conf.template | 7 + .../openshift-custom-postgresql.conf.template | 21 + .../openshift-custom-recovery.conf.template | 8 + .../container-scripts/postgresql/scl_enable | 3 + .../postgresql/start/set_passwords.sh | 23 + 12/s2i/bin/assemble | 14 + 12/s2i/bin/run | 1 + 12/s2i/bin/usage | 1 + 12/test | 1 + 13/Dockerfile.c8s | 84 +++ 13/Dockerfile.c9s | 83 +++ 13/Dockerfile.rhel7 | 94 ++++ 13/Dockerfile.rhel8 | 85 ++++ 13/Dockerfile.rhel9 | 85 ++++ 13/README.md | 1 + 13/cccp.yml | 1 + 13/content_sets.yml | 10 + 13/root/usr/bin/container-entrypoint | 3 + 13/root/usr/bin/run-postgresql | 58 +++ 13/root/usr/bin/run-postgresql-master | 5 + 13/root/usr/bin/run-postgresql-slave | 39 ++ 13/root/usr/bin/usage | 4 + 13/root/usr/libexec/check-container | 27 + 13/root/usr/libexec/fix-permissions | 39 ++ .../container-scripts/postgresql/README.md | 331 ++++++++++++ .../container-scripts/postgresql/common.sh | 479 ++++++++++++++++++ ...ustom-postgresql-replication.conf.template | 7 + .../openshift-custom-postgresql.conf.template | 21 + .../openshift-custom-recovery.conf.template | 8 + .../container-scripts/postgresql/scl_enable | 3 + .../postgresql/start/set_passwords.sh | 23 + 13/s2i/bin/assemble | 14 + 13/s2i/bin/run | 1 + 13/s2i/bin/usage | 1 + 13/test | 1 + 71 files changed, 3921 insertions(+) create mode 120000 11/README.md create mode 100644 11/cccp.yml create mode 100644 11/content_sets.yml create mode 100755 11/root/usr/bin/container-entrypoint create mode 100755 11/root/usr/bin/run-postgresql create mode 100755 11/root/usr/bin/run-postgresql-master create mode 100755 11/root/usr/bin/run-postgresql-slave create mode 100755 11/root/usr/bin/usage create mode 100755 11/root/usr/libexec/check-container create mode 100755 11/root/usr/libexec/fix-permissions create mode 100644 11/root/usr/share/container-scripts/postgresql/README.md create mode 100644 11/root/usr/share/container-scripts/postgresql/common.sh create mode 100644 11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template create mode 100644 11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template create mode 100644 11/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template create mode 100644 11/root/usr/share/container-scripts/postgresql/scl_enable create mode 100644 11/root/usr/share/container-scripts/postgresql/start/set_passwords.sh create mode 100755 11/s2i/bin/assemble create mode 120000 11/s2i/bin/run create mode 100755 11/s2i/bin/usage create mode 120000 11/test create mode 100644 12/Dockerfile.c8s create mode 100644 12/Dockerfile.rhel7 create mode 100644 12/Dockerfile.rhel8 create mode 120000 12/README.md create mode 100644 12/cccp.yml create mode 100644 12/content_sets.yml create mode 100755 12/root/usr/bin/container-entrypoint create mode 100755 12/root/usr/bin/run-postgresql create mode 100755 12/root/usr/bin/run-postgresql-master create mode 100755 12/root/usr/bin/run-postgresql-slave create mode 100755 12/root/usr/bin/usage create mode 100755 12/root/usr/libexec/check-container create mode 100755 12/root/usr/libexec/fix-permissions create mode 100644 12/root/usr/share/container-scripts/postgresql/README.md create mode 100644 12/root/usr/share/container-scripts/postgresql/common.sh create mode 100644 12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template create mode 100644 12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template create mode 100644 12/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template create mode 100644 12/root/usr/share/container-scripts/postgresql/scl_enable create mode 100644 12/root/usr/share/container-scripts/postgresql/start/set_passwords.sh create mode 100755 12/s2i/bin/assemble create mode 120000 12/s2i/bin/run create mode 100755 12/s2i/bin/usage create mode 120000 12/test create mode 100644 13/Dockerfile.c8s create mode 100644 13/Dockerfile.c9s create mode 100644 13/Dockerfile.rhel7 create mode 100644 13/Dockerfile.rhel8 create mode 100644 13/Dockerfile.rhel9 create mode 120000 13/README.md create mode 100644 13/cccp.yml create mode 100644 13/content_sets.yml create mode 100755 13/root/usr/bin/container-entrypoint create mode 100755 13/root/usr/bin/run-postgresql create mode 100755 13/root/usr/bin/run-postgresql-master create mode 100755 13/root/usr/bin/run-postgresql-slave create mode 100755 13/root/usr/bin/usage create mode 100755 13/root/usr/libexec/check-container create mode 100755 13/root/usr/libexec/fix-permissions create mode 100644 13/root/usr/share/container-scripts/postgresql/README.md create mode 100644 13/root/usr/share/container-scripts/postgresql/common.sh create mode 100644 13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template create mode 100644 13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template create mode 100644 13/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template create mode 100644 13/root/usr/share/container-scripts/postgresql/scl_enable create mode 100644 13/root/usr/share/container-scripts/postgresql/start/set_passwords.sh create mode 100755 13/s2i/bin/assemble create mode 120000 13/s2i/bin/run create mode 100755 13/s2i/bin/usage create mode 120000 13/test diff --git a/11/README.md b/11/README.md new file mode 120000 index 00000000..d359f030 --- /dev/null +++ b/11/README.md @@ -0,0 +1 @@ +root/usr/share/container-scripts/postgresql/README.md \ No newline at end of file diff --git a/11/cccp.yml b/11/cccp.yml new file mode 100644 index 00000000..d89c1915 --- /dev/null +++ b/11/cccp.yml @@ -0,0 +1 @@ +job-id: postgresql-11-centos7 diff --git a/11/content_sets.yml b/11/content_sets.yml new file mode 100644 index 00000000..432c0914 --- /dev/null +++ b/11/content_sets.yml @@ -0,0 +1,10 @@ +# This is a file defining which content sets are needed to update content in +# this image. Data provided here helps determine which images are vulnerable to +# specific CVEs. Generally you should only need to update this file when: +# 1. You start depending on new product +# 2. You are preparing new product release and your content sets will change +--- +x86_64: +- rhel-7-server-rpms +- rhel-7-server-optional-rpms +- rhel-server-rhscl-7-rpms diff --git a/11/root/usr/bin/container-entrypoint b/11/root/usr/bin/container-entrypoint new file mode 100755 index 00000000..5fc44481 --- /dev/null +++ b/11/root/usr/bin/container-entrypoint @@ -0,0 +1,3 @@ +#!/bin/bash + +exec "$@" diff --git a/11/root/usr/bin/run-postgresql b/11/root/usr/bin/run-postgresql new file mode 100755 index 00000000..2367e57e --- /dev/null +++ b/11/root/usr/bin/run-postgresql @@ -0,0 +1,58 @@ +#!/bin/bash + +export ENABLE_REPLICATION=${ENABLE_REPLICATION:-false} + +set -eu +export_vars=$(cgroup-limits) ; export $export_vars + +source "${CONTAINER_SCRIPTS_PATH}/common.sh" + +set_pgdata + +process_extending_files \ + "${APP_DATA}/src/postgresql-pre-start" \ + "${CONTAINER_SCRIPTS_PATH}/pre-start" + +check_env_vars +generate_passwd_file +generate_postgresql_config + +# Is this brand new data volume? +PG_INITIALIZED=false + +if [ ! -f "$PGDATA/postgresql.conf" ]; then + initialize_database + PG_INITIALIZED=: +else + try_pgupgrade +fi + +# Use insanely large timeout (24h) to ensure that the potential recovery has +# enough time here to happen (unless liveness probe kills us). Note that in +# case of server failure this command still exists immediately. +pg_ctl start -w --timeout 86400 -o "-h ''" + +# This is just a pedantic safety measure (the timeout above is unlikely to +# happen), but `pt_ctl -w` is not reliable prior to PostgreSQL v10 where it +# returns exit_status=0 even if the server is still starting. For more info +# see the issue#297 and +# https://www.postgresql.org/message-id/CAB7nPqSJs85wK9aknm%3D_jmS6GnH3SQBhpzKcqs8Qo2LhEg2etw%40mail.gmail.com +pg_isready + +if $PG_INITIALIZED ; then + process_extending_files \ + "${APP_DATA}/src/postgresql-init" \ + "${CONTAINER_SCRIPTS_PATH}/init" + migrate_db + create_users +fi + +process_extending_files \ + "${APP_DATA}/src/postgresql-start" \ + "${CONTAINER_SCRIPTS_PATH}/start" + +pg_ctl stop + +unset_env_vars +echo "Starting server..." +exec postgres "$@" diff --git a/11/root/usr/bin/run-postgresql-master b/11/root/usr/bin/run-postgresql-master new file mode 100755 index 00000000..79e7cc24 --- /dev/null +++ b/11/root/usr/bin/run-postgresql-master @@ -0,0 +1,5 @@ +#!/bin/bash + +export ENABLE_REPLICATION=true + +exec run-postgresql "$@" diff --git a/11/root/usr/bin/run-postgresql-slave b/11/root/usr/bin/run-postgresql-slave new file mode 100755 index 00000000..82113b76 --- /dev/null +++ b/11/root/usr/bin/run-postgresql-slave @@ -0,0 +1,37 @@ +#!/bin/bash + +export ENABLE_REPLICATION=true + +set -eu +export_vars=$(cgroup-limits) ; export $export_vars + +source "$CONTAINER_SCRIPTS_PATH"/common.sh + +set_pgdata + +function initialize_replica() { + echo "Initializing PostgreSQL slave ..." + # TODO: Validate and reuse existing data? + rm -rf $PGDATA + PGPASSWORD="${POSTGRESQL_MASTER_PASSWORD}" pg_basebackup -X fetch --no-password --pgdata ${PGDATA} --host=${MASTER_FQDN} --port=5432 -U "${POSTGRESQL_MASTER_USER}" + + # PostgreSQL recovery configuration. + generate_postgresql_recovery_config + cat >> "$PGDATA/recovery.conf" <&2 <&2 "fixing permissions on '$dir' directory" + find "$dir" -exec chown "$uid:0" {} \; + find "$dir" -exec chmod "g+r$write" {} \; + find "$dir" -type d -exec chmod g+x {} + +done diff --git a/11/root/usr/share/container-scripts/postgresql/README.md b/11/root/usr/share/container-scripts/postgresql/README.md new file mode 100644 index 00000000..e0980204 --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/README.md @@ -0,0 +1,331 @@ +PostgreSQL 11 SQL Database Server container image +=============================================== + +This container image includes PostgreSQL 11 SQL database server for OpenShift and general usage. +Users can choose between RHEL, CentOS and Fedora based images. +The RHEL images are available in the [Red Hat Container Catalog](https://access.redhat.com/containers/), +the CentOS images are available on [Quay.io](https://quay.io/organization/centos7), +and the Fedora images are available in [Quay.io](https://quay.io/organization/fedora). +The resulting image can be run using [podman](https://github.com/containers/libpod). + +Note: while the examples in this README are calling `podman`, you can replace any such calls by `docker` with the same arguments + + +Description +----------- + +This container image provides a containerized packaging of the PostgreSQL postgres daemon +and client application. The postgres server daemon accepts connections from clients +and provides access to content from PostgreSQL databases on behalf of the clients. +You can find more information on the PostgreSQL project from the project Web site +(https://www.postgresql.org/). + + +Usage +----- + +For this, we will assume that you are using the `` image, available via `postgresql:11` imagestream tag in Openshift. +If you want to set only the mandatory environment variables and not store the database +in a host directory, execute the following command: + +``` +$ podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 +``` + +This will create a container named `postgresql_database` running PostgreSQL with +database `db` and user with credentials `user:pass`. +> Note: user `postgres` is reserved for internal usage + +Port 5432 will be exposed +and mapped to the host. If you want your database to be persistent across container +executions, also add a `-v /host/db/path:/var/lib/pgsql/data` argument (see +below). This will be the PostgreSQL database cluster directory. + +The same can be achieved in an Openshift instance using templates provided by Openshift or available in [examples](https://github.com/sclorg/postgresql-container/tree/master/examples): + +``` +$ oc process -f examples/postgresql-ephemeral-template.json -p POSTGRESQL_VERSION=11 -p POSTGRESQL_USER=user -p POSTGRESQL_PASSWORD=pass -p POSTGRESQL_DATABASE=db | oc create -f - +``` + +If the database cluster directory is not initialized, the entrypoint script will +first run [`initdb`](http://www.postgresql.org/docs/11/static/app-initdb.html) +and setup necessary database users and passwords. After the database is initialized, +or if it was already present, [`postgres`](http://www.postgresql.org/docs/11/static/app-postgres.html) +is executed and will run as PID 1. You can stop the detached container by running +`podman stop postgresql_database`. + + + +Environment variables and volumes +--------------------------------- + +The image recognizes the following environment variables that you can set during +initialization by passing `-e VAR=VALUE` to the Docker run command. + +**`POSTGRESQL_USER`** + User name for PostgreSQL account to be created + +**`POSTGRESQL_PASSWORD`** + Password for the user account + +**`POSTGRESQL_DATABASE`** + Database name + +**`POSTGRESQL_ADMIN_PASSWORD`** + Password for the `postgres` admin account (optional) + + +Alternatively, the following options are related to migration scenario: + +**`POSTGRESQL_MIGRATION_REMOTE_HOST`** + Hostname/IP to migrate from + +**`POSTGRESQL_MIGRATION_ADMIN_PASSWORD`** + Password for the remote 'postgres' admin user + +**`POSTGRESQL_MIGRATION_IGNORE_ERRORS (optional, default 'no')`** + Set to 'yes' to ignore sql import errors + + +The following environment variables influence the PostgreSQL configuration file. They are all optional. + +**`POSTGRESQL_MAX_CONNECTIONS (default: 100)`** + The maximum number of client connections allowed + +**`POSTGRESQL_MAX_PREPARED_TRANSACTIONS (default: 0)`** + Sets the maximum number of transactions that can be in the "prepared" state. If you are using prepared transactions, you will probably want this to be at least as large as max_connections + +**`POSTGRESQL_SHARED_BUFFERS (default: 1/4 of memory limit or 32M)`** + Sets how much memory is dedicated to PostgreSQL to use for caching data + +**`POSTGRESQL_EFFECTIVE_CACHE_SIZE (default: 1/2 of memory limit or 128M)`** + Set to an estimate of how much memory is available for disk caching by the operating system and within the database itself + + +You can also set the following mount points by passing the `-v /host/dir:/container/dir:Z` flag to Docker. + +**`/var/lib/pgsql/data`** + PostgreSQL database cluster directory + + +**Notice: When mouting a directory from the host into the container, ensure that the mounted +directory has the appropriate permissions and that the owner and group of the directory +matches the user UID or name which is running inside the container.** + +Typically (unless you use `podman run -u` option) processes in container +run under UID 26, so -- on GNU/Linux -- you can fix the datadir permissions +for example by: + +``` +$ setfacl -m u:26:-wx /your/data/dir +$ podman run <...> -v /your/data/dir:/var/lib/pgsql/data:Z <...> +``` + + +Data migration +-------------- + +PostgreSQL container supports migration of data from remote PostgreSQL server. +You can run it like: + +``` +$ podman run -d --name postgresql_database \ + -e POSTGRESQL_MIGRATION_REMOTE_HOST=172.17.0.2 \ + -e POSTGRESQL_MIGRATION_ADMIN_PASSWORD=remoteAdminP@ssword \ + [ OPTIONAL_CONFIGURATION_VARIABLES ] + openshift/postgresql-92-centos7 +``` + +The migration is done the **dump and restore** way (running `pg_dumpall` against +remote cluster and importing the dump locally by `psql`). Because the process +is streamed (unix pipeline), there are no intermediate dump files created during +this process to not waste additional storage space. + +If some SQL commands fail during applying, the default behavior +of the migration script is to fail as well to ensure the **all** or **nothing** +result of scripted, unattended migration. In most common cases, successful +migration is expected (but not guaranteed!), given you migrate from +a previous version of PostgreSQL server container, that is created using +the same principles as this one (e.g. migration from +`openshift/postgresql-92-centos7` to `centos/postgresql-95-centos7`). +Migration from a different kind of PostgreSQL container can likely fail. + +If this **all** or **nothing** principle is inadequate for you, and you know +what you are doing, there's optional `POSTGRESQL_MIGRATION_IGNORE_ERRORS` option +which does **best effort** migration (some data might be lost, it is up to user +to review the standard error output and fix the issues manually in +post-migration time). + +Please keep in mind that the container image provides help for users' +convenience, but fully automatic migration is not guaranteed. Thus, before you +start proceeding with the database migration, get prepared to perform manual +steps in order to get all your data migrated. + +Note that you might not use variables like `POSTGRESQL_USER` in migration +scenario, all the data (including info about databases, roles or passwords are +copied from old cluster). Ensure that you use the same +`OPTIONAL_CONFIGURATION_VARIABLES` as you used for initialization of the old +PostgreSQL container. If some non-default configuration is done on remote +cluster, you might need to copy the configuration files manually, too. + +Security warning: Note that the IP communication between old and new PostgreSQL +clusters is not encrypted by default, it is up to user to configure SSL on +remote cluster or ensure security via different means. + +PostgreSQL auto-tuning +---------------------- + +When the PostgreSQL image is run with the `--memory` parameter set and if there +are no values provided for `POSTGRESQL_SHARED_BUFFERS` and +`POSTGRESQL_EFFECTIVE_CACHE_SIZE` those values are automatically calculated +based on the value provided in the `--memory` parameter. + +The values are calculated based on the +[upstream](https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server) +formulas. For the `shared_buffers` we use 1/4 of given memory and for the +`effective_cache_size` we set the value to 1/2 of the given memory. + +PostgreSQL admin account +------------------------ +The admin account `postgres` has no password set by default, only allowing local +connections. You can set it by setting the `POSTGRESQL_ADMIN_PASSWORD` environment +variable when initializing your container. This will allow you to login to the +`postgres` account remotely. Local connections will still not require a password. + + +Changing passwords +------------------ + +Since passwords are part of the image configuration, the only supported method +to change passwords for the database user (`POSTGRESQL_USER`) and `postgres` +admin user is by changing the environment variables `POSTGRESQL_PASSWORD` and +`POSTGRESQL_ADMIN_PASSWORD`, respectively. + +Changing database passwords through SQL statements or any way other than through +the environment variables aforementioned will cause a mismatch between the +values stored in the variables and the actual passwords. Whenever a database +container starts it will reset the passwords to the values stored in the +environment variables. + + +Upgrading database (by switching to newer PostgreSQL image version) +------------------------------------------------------------------- + +** Warning! Please, before you decide to do the data directory upgrade, always +ensure that you've carefully backed up all your data and that you are OK with +potential manual rollback! ** + +This image supports automatic upgrade of data directory created by +the PostgreSQL server version 10 (and _only_ this version) - provided by sclorg +image. The upgrade process is designed so that you should be able to just +switch from *image A* to *image B*, and set the `$POSTGRESQL_UPGRADE` variable +appropriately to explicitly request the database data transformation. + +The upgrade process is internally implemented via `pg_upgrade` binary, and for +that purpose the container needs to contain two versions of PostgreSQL server +(have a look at `man pg_upgrade` for more info). + +For the `pg_upgrade` process - and the new server version, we need to initialize +a brand new data directory. That's data directory is created automatically by +container tooling under /var/lib/pgsql/data, which is usually external +bind-mountpoint. The `pg_upgrade` execution is then similar to dump&restore +approach -- it starts both old and new PostgreSQL servers (within container) and +"dumps" the old datadir while and at the same time it "restores" it into new +datadir. This operation requires a lot of data files copying, so you can decide +what type of upgrade you'll do by setting `$POSTGRESQL_UPGRADE` appropriately: + +**`copy`** + The data files are copied from old datadir to new datadir. This option has low risk of data loss in case of some upgrade failure. + +**`hardlink`** + Data files are hard-linked from old to the new data directory, which brings performance optimization - but the old directory becomes unusable, even in case of failure. + + +Note that because we copy data directory, you need to make sure that you have +enough space for the copy; upgrade failure because of not enough space might +lead to data loss. + + +Extending image +---------------- + +This image can be extended in Openshift using the `Source` build strategy or via the standalone +[source-to-image](https://github.com/openshift/source-to-image) application (where available). +For this, we will assume that you are using the `` image, +available via `postgresql:11` imagestream tag in Openshift. + +For example to build customized image `new-postgresql` +with configuration from `https://github.com/sclorg/postgresql-container/tree/master/examples/extending-image` run: + +``` +$ oc new-app postgresql:11~https://github.com/sclorg/postgresql-container.git \ + --name new-postgresql \ + --context-dir examples/extending-image/ \ + -e POSTGRESQL_USER=user \ + -e POSTGRESQL_DATABASE=db \ + -e POSTGRESQL_PASSWORD=password +``` + +or via `s2i`: + +``` +$ s2i build --context-dir examples/extending-image/ https://github.com/sclorg/postgresql-container.git new-postgresql +``` + +The directory passed to Openshift should contain one or more of the +following directories: + + +##### `postgresql-pre-start/` + +Source all `*.sh` files from this directory during early start of the +container. There's no PostgreSQL daemon running on background. + + +##### `postgresql-cfg/` + +Contained configuration files (`*.conf`) will be included at the end of image +postgresql.conf file. + + +##### `postgresql-init/` + +Contained shell scripts (`*.sh`) are sourced when the database is freshly +initialized (after successful initdb run which made the data directory +non-empty). At the time of sourcing these scripts, the local PostgreSQL +server is running. For re-deployments scenarios with persistent data +directory, the scripts are not sourced (no-op). + + +##### `postgresql-start/` + +Same sematics as `postgresql-init/`, except that these scripts are +always sourced (after `postgresql-init/` scripts, if they exist). + + +---------------------------------------------- + +During the s2i build all provided files are copied into `/opt/app-root/src` +directory in the new image. Only one +file with the same name can be used for customization and user provided files +are preferred over default files in `/usr/share/container-scripts/`- +so it is possible to overwrite them. + + +Troubleshooting +--------------- +At first the postgres daemon writes its logs to the standard output, so these are available in the container log. The log can be examined by running: + + podman logs + +Then log output is redirected to logging collector process and will appear in directory "pg_log". + + +See also +-------- +Dockerfile and other sources for this container image are available on +https://github.com/sclorg/postgresql-container. +In that repository, the Dockerfile for CentOS is called Dockerfile, the Dockerfile +for RHEL7 is called Dockerfile.rhel7, the Dockerfile for RHEL8 is called Dockerfile.rhel8, +the Dockerfile for RHEL9 is called Dockerfile.rhel9, +and the Dockerfile for Fedora is called Dockerfile.fedora. diff --git a/11/root/usr/share/container-scripts/postgresql/common.sh b/11/root/usr/share/container-scripts/postgresql/common.sh new file mode 100644 index 00000000..4e1bc94a --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/common.sh @@ -0,0 +1,479 @@ +# Configuration settings. +export POSTGRESQL_MAX_CONNECTIONS=${POSTGRESQL_MAX_CONNECTIONS:-100} +export POSTGRESQL_MAX_PREPARED_TRANSACTIONS=${POSTGRESQL_MAX_PREPARED_TRANSACTIONS:-0} + +# Perform auto-tuning based on the container cgroups limits (only when the +# limits are set). +# Users can still override this by setting the POSTGRESQL_SHARED_BUFFERS +# and POSTGRESQL_EFFECTIVE_CACHE_SIZE variables. +if [[ "${NO_MEMORY_LIMIT:-}" == "true" || -z "${MEMORY_LIMIT_IN_BYTES:-}" ]]; then + export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-32MB} + export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-128MB} +else + # Use 1/4 of given memory for shared buffers + shared_buffers_computed="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/4))MB" + # Setting effective_cache_size to 1/2 of total memory would be a normal conservative setting, + effective_cache="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/2))MB" + export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-$shared_buffers_computed} + export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-$effective_cache} +fi + +export POSTGRESQL_RECOVERY_FILE=$HOME/openshift-custom-recovery.conf +export POSTGRESQL_CONFIG_FILE=$HOME/openshift-custom-postgresql.conf + +postinitdb_actions= + +# match . files when moving userdata below +shopt -s dotglob +# extglob enables the !(userdata) glob pattern below. +shopt -s extglob + +function usage() { + if [ $# == 1 ]; then + echo >&2 "error: $1" + fi + + cat >&2 </dev/null) + # FIXME: This is for debugging (docker run) + if [ -v POSTGRESQL_MASTER_IP ]; then + endpoints=${POSTGRESQL_MASTER_IP:-} + fi + if [ -z "$endpoints" ]; then + >&2 echo "Failed to resolve PostgreSQL master IP address" + exit 3 + fi + echo -n "$(echo $endpoints | cut -d ' ' -f 1)" +} + +# Converts the version in format x.y or x.y.z to a number. +version2number () +{ + local old_IFS=$IFS + local to_print= depth=${2-3} width=${3-2} sum=0 one_part + IFS='.' + set -- $1 + while test $depth -ge 1; do + depth=$(( depth - 1 )) + part=${1-0} ; shift || : + printf "%0${width}d" "$part" + done + IFS=$old_IFS +} + +# On non-intel arches, data_sync_retry = off does not work +# Upstream discussion: https://www.postgresql.org/message-id/CA+mCpegfOUph2U4ZADtQT16dfbkjjYNJL1bSTWErsazaFjQW9A@mail.gmail.com +# Upstream changes that caused this issue: +# https://github.com/postgres/postgres/commit/483520eca426fb1b428e8416d1d014ac5ad80ef4 +# https://github.com/postgres/postgres/commit/9ccdd7f66e3324d2b6d3dec282cfa9ff084083f1 +# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1779150 +# Special handle of data_sync_retry should handle only in some cases. +# These cases are: non-intel architectures, and version higher or equal 12.0, 10.7, 9.6.12 +# Return value 0 means the hack is needed. +function should_hack_data_sync_retry() { + [ "$(uname -p)" == 'x86_64' ] && return 1 + local version_number=$(version2number "$(pg_ctl -V | sed -e 's/^pg_ctl (PostgreSQL) //')") + # this matches all 12.x and versions of 10.x where we need the hack + [ "$version_number" -ge 100700 ] && return 0 + # this matches all 10.x that were not matched above + [ "$version_number" -ge 100000 ] && return 1 + # this matches all 9.x where need the hack + [ "$version_number" -ge 090612 ] && return 0 + # all rest should be older 9.x releases + return 1 +} + +# New config is generated every time a container is created. It only contains +# additional custom settings and is included from $PGDATA/postgresql.conf. +function generate_postgresql_config() { + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql.conf.template" \ + > "${POSTGRESQL_CONFIG_FILE}" + + if [ "${ENABLE_REPLICATION}" == "true" ]; then + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql-replication.conf.template" \ + >> "${POSTGRESQL_CONFIG_FILE}" + fi + + if should_hack_data_sync_retry ; then + echo "data_sync_retry = on" >>"${POSTGRESQL_CONFIG_FILE}" + fi + + ( + shopt -s nullglob + for conf in "${APP_DATA}"/src/postgresql-cfg/*.conf; do + echo include \'${conf}\' >> "${POSTGRESQL_CONFIG_FILE}" + done + ) +} + +function generate_postgresql_recovery_config() { + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-recovery.conf.template" \ + > "${POSTGRESQL_RECOVERY_FILE}" +} + +# Generate passwd file based on current uid +function generate_passwd_file() { + export USER_ID=$(id -u) + export GROUP_ID=$(id -g) + grep -v -e ^postgres -e ^$USER_ID /etc/passwd > "$HOME/passwd" + echo "postgres:x:${USER_ID}:${GROUP_ID}:PostgreSQL Server:${HOME}:/bin/bash" >> "$HOME/passwd" + export LD_PRELOAD=libnss_wrapper.so + export NSS_WRAPPER_PASSWD=${HOME}/passwd + export NSS_WRAPPER_GROUP=/etc/group +} + +initdb_wrapper () +{ + # Initialize the database cluster with utf8 support enabled by default. + # This might affect performance, see: + # http://www.postgresql.org/docs/11/static/locale.html + LANG=${LANG:-en_US.utf8} "$@" +} + +function initialize_database() { + initdb_wrapper initdb + + # PostgreSQL configuration. + cat >> "$PGDATA/postgresql.conf" <> "$PGDATA/pg_hba.conf" <&2 "\n========== \$PGDATA upgrade: %s -> %s ==========\n\n" \ + "$POSTGRESQL_PREV_VERSION" \ + "$POSTGRESQL_VERSION" + + info_msg () { printf >&2 "\n===> $*\n\n" ;} + + # pg_upgrade writes logs to cwd, so go to the persistent storage first + cd "$HOME"/data + + # disable this because of scl_source, 'set +u' just makes the code ugly + # anyways + set +u + + # we need to have the old SCL enabled, otherwise the $old_pgengine is not + # working. The scl_source script doesn't pay attention to non-zero exit + # statuses, so use 'set +e'. + set +e + source scl_source enable $old_collection + set -e + + case $POSTGRESQL_UPGRADE in + copy) # we accept this + ;; + hardlink) + optimized=: + ;; + *) + echo >&2 "Unsupported value: \$POSTGRESQL_UPGRADE=$POSTGRESQL_UPGRADE" + false + ;; + esac + + # Ensure $PGDATA_new doesn't exist yet, so we can immediately remove it if + # there's some problem. + test ! -e "$PGDATA_new" + + # initialize the database + info_msg "Initialize new data directory; we will migrate to that." + initdb_cmd=( initdb_wrapper "$new_pgengine"/initdb "$PGDATA_new" ) + eval "\${initdb_cmd[@]} ${POSTGRESQL_UPGRADE_INITDB_OPTIONS-}" || \ + { rm -rf "$PGDATA_new" ; false ; } + + upgrade_cmd=( + "$new_pgengine"/pg_upgrade + "--old-bindir=$old_pgengine" + "--new-bindir=$new_pgengine" + "--old-datadir=$PGDATA" + "--new-datadir=$PGDATA_new" + ) + + # Dangerous --link option, we loose $DATADIR if something goes wrong. + ! $optimized || upgrade_cmd+=(--link) + + # User-specififed options for pg_upgrade. + eval "upgrade_cmd+=(${POSTGRESQL_UPGRADE_PGUPGRADE_OPTIONS-})" + + # On non-intel arches the data_sync_retry set to on + sed -i -e 's/data_sync_retry/#data_sync_retry/' "${POSTGRESQL_CONFIG_FILE}" + + # the upgrade + info_msg "Starting the pg_upgrade process." + + # Once we stop support for PostgreSQL 9.4, we don't need + # REDHAT_PGUPGRADE_FROM_RHEL hack as we don't upgrade from 9.2 -- that means + # that we don't need to fiddle with unix_socket_director{y,ies} option. + REDHAT_PGUPGRADE_FROM_RHEL=1 \ + "${upgrade_cmd[@]}" || { cat $(find "$PGDATA_new"/.. -name pg_upgrade_server.log) ; rm -rf "$PGDATA_new" && false ; } + + # Move the important configuration and remove old data. This is highly + # careless, but we can't do more for this over-automatized process. + info_msg "Swap the old and new PGDATA and cleanup." + mv "$PGDATA"/*.conf "$PGDATA_new" + rm -rf "$PGDATA" + mv "$PGDATA_new" "$PGDATA" + + # Get back the option we changed above + sed -i -e 's/#data_sync_retry/data_sync_retry/' "${POSTGRESQL_CONFIG_FILE}" + + info_msg "Upgrade DONE." +) + + +# Run right after container startup, when the data volume is already initialized +# (not initialized by this container run) and thus there exists a chance that +# the data was generated by incompatible PostgreSQL major version. +try_pgupgrade () +{ + local versionfile="$PGDATA"/PG_VERSION version upgrade_available + + # This file always exists. + test -f "$versionfile" + version=$(cat "$versionfile") + + # If we don't support pg_upgrade, skip. + test -z "${POSTGRESQL_PREV_VERSION-}" && return 0 + + if test "$POSTGRESQL_VERSION" = "$version"; then + # No need to call pg_upgrade. + + # Mistakenly requests upgrade? If not, just start the DB. + test -z "${POSTGRESQL_UPGRADE-}" && return 0 + + # Make _sure_ we have this safety-belt here, otherwise our users would + # just specify '-e POSTGRESQL_UPGRADE=hardlink' permanently, even for + # re-deployment cases when upgrade is not needed. Setting such + # unfortunate default could mean that pg_upgrade might (after some user + # mistake) migrate (or even destruct, especially with --link) the old data + # directory with limited rollback options, if any. + echo >&2 + echo >&2 "== WARNING!! ==" + echo >&2 "PostgreSQL server version matches the datadir PG_VERSION." + echo >&2 "The \$POSTGRESQL_UPGRADE makes no sense and you probably" + echo >&2 "made some mistake, keeping the variable set you might" + echo >&2 "risk a data loss in future!" + echo >&2 "===============" + echo >&2 + + # Exit here, but allow _really explicit_ foot-shot. + ${POSTGRESQL_UPGRADE_FORCE-false} + return 0 + fi + + # At this point in code we know that PG_VERSION doesn't match the PostgreSQL + # server major version; this might mean that user either (a) mistakenly + # deploys from a bad image, or (b) user wants to perform upgrade. For the + # upgrade we require explicit request -- just to avoid disasters in (a)-cases. + + if test -z "${POSTGRESQL_UPGRADE-}"; then + echo >&2 "Incompatible data directory. This container image provides" + echo >&2 "PostgreSQL '$POSTGRESQL_VERSION', but data directory is of" + echo >&2 "version '$version'." + echo >&2 + echo >&2 "This image supports automatic data directory upgrade from" + echo >&2 "'$POSTGRESQL_PREV_VERSION', please _carefully_ consult image documentation" + echo >&2 "about how to use the '\$POSTGRESQL_UPGRADE' startup option." + # We could wait for postgresql startup failure (there's no risk of data dir + # corruption), but fail rather early. + false + fi + + # We support pg_upgrade process only from previous version of this container + # (upgrade to N to N+1 is possible, so e.g. 9.4 to 9.5). + if test "$POSTGRESQL_PREV_VERSION" != "$version"; then + echo >&2 "With this container image you can only upgrade from data directory" + echo >&2 "of version '$POSTGRESQL_PREV_VERSION', not '$version'." + false + fi + + run_pgupgrade +} + +# get_matched_files PATTERN DIR [DIR ...] +# --------------------------------------- +# Print all basenames for files matching PATTERN in DIRs. +get_matched_files () +{ + local pattern=$1 dir + shift + for dir; do + test -d "$dir" || continue + find -L "$dir" -maxdepth 1 -type f -name "$pattern" -printf "%f\n" + done +} + +# process_extending_files DIR [DIR ...] +# ------------------------------------- +# Source all *.sh files in DIRs in alphabetical order, but if the file exists in +# more then one DIR, source only the first occurrence (first found wins). +process_extending_files() +{ + local filename dir + while read filename ; do + for dir in "$@"; do + local file="$dir/$filename" + if test -f "$file"; then + echo "=> sourcing $file ..." + source "$file" + set -e # ensure that users don't mistakenly change this + break + fi + done + done <<<"$(get_matched_files '*.sh' "$@" | sort -u)" +} diff --git a/11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template b/11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template new file mode 100644 index 00000000..ef04eaae --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template @@ -0,0 +1,7 @@ +# required on master for replication +wal_level = hot_standby # minimal, archive, hot_standby, or logical +max_wal_senders = 6 # max number of walsender processes +wal_keep_segments = 400 # in logfile segments, 16MB each; 0 disables + +# required on replicas for replication +hot_standby = on diff --git a/11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template b/11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template new file mode 100644 index 00000000..3c2bc7f3 --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template @@ -0,0 +1,21 @@ +# +# Custom OpenShift configuration. +# +# NOTE: This file is rewritten every time the container is started! +# Changes to this file will be overwritten. +# + +# Listen on all interfaces. +listen_addresses = '*' + +# Determines the maximum number of concurrent connections to the database server. Default: 100 +max_connections = ${POSTGRESQL_MAX_CONNECTIONS} + +# Allow each connection to use a prepared transaction +max_prepared_transactions = ${POSTGRESQL_MAX_PREPARED_TRANSACTIONS} + +# Sets the amount of memory the database server uses for shared memory buffers. Default: 32MB +shared_buffers = ${POSTGRESQL_SHARED_BUFFERS} + +# Sets the planner's assumption about the effective size of the disk cache that is available to a single query +effective_cache_size = ${POSTGRESQL_EFFECTIVE_CACHE_SIZE} diff --git a/11/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template b/11/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template new file mode 100644 index 00000000..26d56693 --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template @@ -0,0 +1,9 @@ +# +# Custom OpenShift configuration. +# +# NOTE: This file is rewritten every time the container is started! +# Changes to this file will be overwritten. +# + +standby_mode = on +primary_conninfo = 'host=${MASTER_FQDN} port=5432 user=${POSTGRESQL_MASTER_USER} password=${POSTGRESQL_MASTER_PASSWORD}' diff --git a/11/root/usr/share/container-scripts/postgresql/scl_enable b/11/root/usr/share/container-scripts/postgresql/scl_enable new file mode 100644 index 00000000..1d967f9b --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/scl_enable @@ -0,0 +1,3 @@ +# This will make scl collection binaries work out of box. +unset BASH_ENV PROMPT_COMMAND ENV +source scl_source enable $ENABLED_COLLECTIONS diff --git a/11/root/usr/share/container-scripts/postgresql/start/set_passwords.sh b/11/root/usr/share/container-scripts/postgresql/start/set_passwords.sh new file mode 100644 index 00000000..60d70e36 --- /dev/null +++ b/11/root/usr/share/container-scripts/postgresql/start/set_passwords.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +_psql () { psql --set ON_ERROR_STOP=1 "$@" ; } + +if [[ ",$postinitdb_actions," = *,simple_db,* ]]; then +_psql --set=username="$POSTGRESQL_USER" \ + --set=password="$POSTGRESQL_PASSWORD" \ +<<< "ALTER USER :\"username\" WITH ENCRYPTED PASSWORD :'password';" +fi + +if [ -v POSTGRESQL_MASTER_USER ]; then +_psql --set=masteruser="$POSTGRESQL_MASTER_USER" \ + --set=masterpass="$POSTGRESQL_MASTER_PASSWORD" \ +<<'EOF' +ALTER USER :"masteruser" WITH REPLICATION; +ALTER USER :"masteruser" WITH ENCRYPTED PASSWORD :'masterpass'; +EOF +fi + +if [ -v POSTGRESQL_ADMIN_PASSWORD ]; then +_psql --set=adminpass="$POSTGRESQL_ADMIN_PASSWORD" \ +<<<"ALTER USER \"postgres\" WITH ENCRYPTED PASSWORD :'adminpass';" +fi diff --git a/11/s2i/bin/assemble b/11/s2i/bin/assemble new file mode 100755 index 00000000..6ed8f7aa --- /dev/null +++ b/11/s2i/bin/assemble @@ -0,0 +1,14 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +shopt -s dotglob +echo "---> Installing application source ..." + + +mv /tmp/src/* ./ + +# Fix source directory permissions +/usr/libexec/fix-permissions --read-only ./ diff --git a/11/s2i/bin/run b/11/s2i/bin/run new file mode 120000 index 00000000..a7f4076b --- /dev/null +++ b/11/s2i/bin/run @@ -0,0 +1 @@ +/usr/bin/run-postgresql \ No newline at end of file diff --git a/11/s2i/bin/usage b/11/s2i/bin/usage new file mode 100755 index 00000000..9f413123 --- /dev/null +++ b/11/s2i/bin/usage @@ -0,0 +1 @@ +groff -t -man -ETascii /help.1 diff --git a/11/test b/11/test new file mode 120000 index 00000000..419df4f9 --- /dev/null +++ b/11/test @@ -0,0 +1 @@ +../test \ No newline at end of file diff --git a/12/Dockerfile.c8s b/12/Dockerfile.c8s new file mode 100644 index 00000000..7251587e --- /dev/null +++ b/12/Dockerfile.c8s @@ -0,0 +1,84 @@ +FROM quay.io/sclorg/s2i-core-c8s:c8s + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=12 \ + POSTGRESQL_PREV_VERSION=10 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 12" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql12,postgresql-12" \ + io.openshift.s2i.assemble-user="26" \ + name="sclorg/postgresql-12-c8s" \ + com.redhat.component="postgresql-12-container" \ + version="1" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 sclorg/postgresql-12-c8s" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +RUN yum -y module enable postgresql:12 && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper postgresql-server postgresql-contrib" && \ + INSTALL_PKGS="$INSTALL_PKGS pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y reinstall tzdata && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS= + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/12/Dockerfile.rhel7 b/12/Dockerfile.rhel7 new file mode 100644 index 00000000..0bdbb6be --- /dev/null +++ b/12/Dockerfile.rhel7 @@ -0,0 +1,94 @@ +FROM rhscl/s2i-core-rhel7 + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=12 \ + POSTGRESQL_PREV_VERSION=10 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 12" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql12,rh-postgresql12" \ + io.openshift.s2i.assemble-user="26" \ + name="rhscl/postgresql-12-rhel7" \ + com.redhat.component="rh-postgresql12-container" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhscl/postgresql-12-rhel7" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +# rhel-7-server-ose-3.2-rpms is enabled for nss_wrapper until this pkg is +# in base RHEL +RUN yum install -y yum-utils gettext && \ + prepare-yum-repositories rhel-server-rhscl-7-rpms && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper rh-postgresql12 rh-postgresql12-postgresql-contrib rh-postgresql12-syspaths rh-postgresql10-postgresql-server" && \ + INSTALL_PKGS="$INSTALL_PKGS rh-postgresql12-pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS=rh-postgresql12 + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# When bash is started non-interactively, to run a shell script, for example it +# looks for this variable and source the content of this file. This will enable +# the SCL for all scripts without need to do 'scl enable'. +ENV BASH_ENV=${CONTAINER_SCRIPTS_PATH}/scl_enable \ + ENV=${CONTAINER_SCRIPTS_PATH}/scl_enable \ + PROMPT_COMMAND=". ${CONTAINER_SCRIPTS_PATH}/scl_enable" + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/12/Dockerfile.rhel8 b/12/Dockerfile.rhel8 new file mode 100644 index 00000000..e387a241 --- /dev/null +++ b/12/Dockerfile.rhel8 @@ -0,0 +1,85 @@ +FROM ubi8/s2i-core + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=12 \ + POSTGRESQL_PREV_VERSION=10 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 12" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql12,postgresql-12" \ + io.openshift.s2i.assemble-user="26" \ + name="rhel8/postgresql-12" \ + com.redhat.component="postgresql-12-container" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhel8/postgresql-12" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +RUN yum -y module enable postgresql:12 && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper postgresql-server postgresql-contrib" && \ + INSTALL_PKGS="$INSTALL_PKGS pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y reinstall tzdata && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS= + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/12/README.md b/12/README.md new file mode 120000 index 00000000..d359f030 --- /dev/null +++ b/12/README.md @@ -0,0 +1 @@ +root/usr/share/container-scripts/postgresql/README.md \ No newline at end of file diff --git a/12/cccp.yml b/12/cccp.yml new file mode 100644 index 00000000..23374d63 --- /dev/null +++ b/12/cccp.yml @@ -0,0 +1 @@ +job-id: postgresql-12-centos7 diff --git a/12/content_sets.yml b/12/content_sets.yml new file mode 100644 index 00000000..432c0914 --- /dev/null +++ b/12/content_sets.yml @@ -0,0 +1,10 @@ +# This is a file defining which content sets are needed to update content in +# this image. Data provided here helps determine which images are vulnerable to +# specific CVEs. Generally you should only need to update this file when: +# 1. You start depending on new product +# 2. You are preparing new product release and your content sets will change +--- +x86_64: +- rhel-7-server-rpms +- rhel-7-server-optional-rpms +- rhel-server-rhscl-7-rpms diff --git a/12/root/usr/bin/container-entrypoint b/12/root/usr/bin/container-entrypoint new file mode 100755 index 00000000..5fc44481 --- /dev/null +++ b/12/root/usr/bin/container-entrypoint @@ -0,0 +1,3 @@ +#!/bin/bash + +exec "$@" diff --git a/12/root/usr/bin/run-postgresql b/12/root/usr/bin/run-postgresql new file mode 100755 index 00000000..2367e57e --- /dev/null +++ b/12/root/usr/bin/run-postgresql @@ -0,0 +1,58 @@ +#!/bin/bash + +export ENABLE_REPLICATION=${ENABLE_REPLICATION:-false} + +set -eu +export_vars=$(cgroup-limits) ; export $export_vars + +source "${CONTAINER_SCRIPTS_PATH}/common.sh" + +set_pgdata + +process_extending_files \ + "${APP_DATA}/src/postgresql-pre-start" \ + "${CONTAINER_SCRIPTS_PATH}/pre-start" + +check_env_vars +generate_passwd_file +generate_postgresql_config + +# Is this brand new data volume? +PG_INITIALIZED=false + +if [ ! -f "$PGDATA/postgresql.conf" ]; then + initialize_database + PG_INITIALIZED=: +else + try_pgupgrade +fi + +# Use insanely large timeout (24h) to ensure that the potential recovery has +# enough time here to happen (unless liveness probe kills us). Note that in +# case of server failure this command still exists immediately. +pg_ctl start -w --timeout 86400 -o "-h ''" + +# This is just a pedantic safety measure (the timeout above is unlikely to +# happen), but `pt_ctl -w` is not reliable prior to PostgreSQL v10 where it +# returns exit_status=0 even if the server is still starting. For more info +# see the issue#297 and +# https://www.postgresql.org/message-id/CAB7nPqSJs85wK9aknm%3D_jmS6GnH3SQBhpzKcqs8Qo2LhEg2etw%40mail.gmail.com +pg_isready + +if $PG_INITIALIZED ; then + process_extending_files \ + "${APP_DATA}/src/postgresql-init" \ + "${CONTAINER_SCRIPTS_PATH}/init" + migrate_db + create_users +fi + +process_extending_files \ + "${APP_DATA}/src/postgresql-start" \ + "${CONTAINER_SCRIPTS_PATH}/start" + +pg_ctl stop + +unset_env_vars +echo "Starting server..." +exec postgres "$@" diff --git a/12/root/usr/bin/run-postgresql-master b/12/root/usr/bin/run-postgresql-master new file mode 100755 index 00000000..79e7cc24 --- /dev/null +++ b/12/root/usr/bin/run-postgresql-master @@ -0,0 +1,5 @@ +#!/bin/bash + +export ENABLE_REPLICATION=true + +exec run-postgresql "$@" diff --git a/12/root/usr/bin/run-postgresql-slave b/12/root/usr/bin/run-postgresql-slave new file mode 100755 index 00000000..586bf5d7 --- /dev/null +++ b/12/root/usr/bin/run-postgresql-slave @@ -0,0 +1,39 @@ +#!/bin/bash + +export ENABLE_REPLICATION=true + +set -eu +export_vars=$(cgroup-limits) ; export $export_vars + +source "$CONTAINER_SCRIPTS_PATH"/common.sh + +set_pgdata + +function initialize_replica() { + echo "Initializing PostgreSQL slave ..." + # TODO: Validate and reuse existing data? + rm -rf $PGDATA + PGPASSWORD="${POSTGRESQL_MASTER_PASSWORD}" pg_basebackup -X fetch --no-password --pgdata ${PGDATA} --host=${MASTER_FQDN} --port=5432 -U "${POSTGRESQL_MASTER_USER}" + + # PostgreSQL recovery configuration. + generate_postgresql_recovery_config + cat >> "$PGDATA/postgresql.auto.conf" <&2 <&2 "fixing permissions on '$dir' directory" + find "$dir" -exec chown "$uid:0" {} \; + find "$dir" -exec chmod "g+r$write" {} \; + find "$dir" -type d -exec chmod g+x {} + +done diff --git a/12/root/usr/share/container-scripts/postgresql/README.md b/12/root/usr/share/container-scripts/postgresql/README.md new file mode 100644 index 00000000..f92d9665 --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/README.md @@ -0,0 +1,331 @@ +PostgreSQL 12 SQL Database Server container image +=============================================== + +This container image includes PostgreSQL 12 SQL database server for OpenShift and general usage. +Users can choose between RHEL, CentOS and Fedora based images. +The RHEL images are available in the [Red Hat Container Catalog](https://access.redhat.com/containers/), +the CentOS images are available on [Quay.io](https://quay.io/organization/centos7), +and the Fedora images are available in [Quay.io](https://quay.io/organization/fedora). +The resulting image can be run using [podman](https://github.com/containers/libpod). + +Note: while the examples in this README are calling `podman`, you can replace any such calls by `docker` with the same arguments + + +Description +----------- + +This container image provides a containerized packaging of the PostgreSQL postgres daemon +and client application. The postgres server daemon accepts connections from clients +and provides access to content from PostgreSQL databases on behalf of the clients. +You can find more information on the PostgreSQL project from the project Web site +(https://www.postgresql.org/). + + +Usage +----- + +For this, we will assume that you are using the `rhscl/postgresql-12-rhel7` image, available via `postgresql:12` imagestream tag in Openshift. +If you want to set only the mandatory environment variables and not store the database +in a host directory, execute the following command: + +``` +$ podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhscl/postgresql-12-rhel7 +``` + +This will create a container named `postgresql_database` running PostgreSQL with +database `db` and user with credentials `user:pass`. +> Note: user `postgres` is reserved for internal usage + +Port 5432 will be exposed +and mapped to the host. If you want your database to be persistent across container +executions, also add a `-v /host/db/path:/var/lib/pgsql/data` argument (see +below). This will be the PostgreSQL database cluster directory. + +The same can be achieved in an Openshift instance using templates provided by Openshift or available in [examples](https://github.com/sclorg/postgresql-container/tree/master/examples): + +``` +$ oc process -f examples/postgresql-ephemeral-template.json -p POSTGRESQL_VERSION=12 -p POSTGRESQL_USER=user -p POSTGRESQL_PASSWORD=pass -p POSTGRESQL_DATABASE=db | oc create -f - +``` + +If the database cluster directory is not initialized, the entrypoint script will +first run [`initdb`](http://www.postgresql.org/docs/12/static/app-initdb.html) +and setup necessary database users and passwords. After the database is initialized, +or if it was already present, [`postgres`](http://www.postgresql.org/docs/12/static/app-postgres.html) +is executed and will run as PID 1. You can stop the detached container by running +`podman stop postgresql_database`. + + + +Environment variables and volumes +--------------------------------- + +The image recognizes the following environment variables that you can set during +initialization by passing `-e VAR=VALUE` to the Docker run command. + +**`POSTGRESQL_USER`** + User name for PostgreSQL account to be created + +**`POSTGRESQL_PASSWORD`** + Password for the user account + +**`POSTGRESQL_DATABASE`** + Database name + +**`POSTGRESQL_ADMIN_PASSWORD`** + Password for the `postgres` admin account (optional) + + +Alternatively, the following options are related to migration scenario: + +**`POSTGRESQL_MIGRATION_REMOTE_HOST`** + Hostname/IP to migrate from + +**`POSTGRESQL_MIGRATION_ADMIN_PASSWORD`** + Password for the remote 'postgres' admin user + +**`POSTGRESQL_MIGRATION_IGNORE_ERRORS (optional, default 'no')`** + Set to 'yes' to ignore sql import errors + + +The following environment variables influence the PostgreSQL configuration file. They are all optional. + +**`POSTGRESQL_MAX_CONNECTIONS (default: 100)`** + The maximum number of client connections allowed + +**`POSTGRESQL_MAX_PREPARED_TRANSACTIONS (default: 0)`** + Sets the maximum number of transactions that can be in the "prepared" state. If you are using prepared transactions, you will probably want this to be at least as large as max_connections + +**`POSTGRESQL_SHARED_BUFFERS (default: 1/4 of memory limit or 32M)`** + Sets how much memory is dedicated to PostgreSQL to use for caching data + +**`POSTGRESQL_EFFECTIVE_CACHE_SIZE (default: 1/2 of memory limit or 128M)`** + Set to an estimate of how much memory is available for disk caching by the operating system and within the database itself + + +You can also set the following mount points by passing the `-v /host/dir:/container/dir:Z` flag to Docker. + +**`/var/lib/pgsql/data`** + PostgreSQL database cluster directory + + +**Notice: When mouting a directory from the host into the container, ensure that the mounted +directory has the appropriate permissions and that the owner and group of the directory +matches the user UID or name which is running inside the container.** + +Typically (unless you use `podman run -u` option) processes in container +run under UID 26, so -- on GNU/Linux -- you can fix the datadir permissions +for example by: + +``` +$ setfacl -m u:26:-wx /your/data/dir +$ podman run <...> -v /your/data/dir:/var/lib/pgsql/data:Z <...> +``` + + +Data migration +-------------- + +PostgreSQL container supports migration of data from remote PostgreSQL server. +You can run it like: + +``` +$ podman run -d --name postgresql_database \ + -e POSTGRESQL_MIGRATION_REMOTE_HOST=172.17.0.2 \ + -e POSTGRESQL_MIGRATION_ADMIN_PASSWORD=remoteAdminP@ssword \ + [ OPTIONAL_CONFIGURATION_VARIABLES ] + openshift/postgresql-92-centos7 +``` + +The migration is done the **dump and restore** way (running `pg_dumpall` against +remote cluster and importing the dump locally by `psql`). Because the process +is streamed (unix pipeline), there are no intermediate dump files created during +this process to not waste additional storage space. + +If some SQL commands fail during applying, the default behavior +of the migration script is to fail as well to ensure the **all** or **nothing** +result of scripted, unattended migration. In most common cases, successful +migration is expected (but not guaranteed!), given you migrate from +a previous version of PostgreSQL server container, that is created using +the same principles as this one (e.g. migration from +`openshift/postgresql-92-centos7` to `centos/postgresql-95-centos7`). +Migration from a different kind of PostgreSQL container can likely fail. + +If this **all** or **nothing** principle is inadequate for you, and you know +what you are doing, there's optional `POSTGRESQL_MIGRATION_IGNORE_ERRORS` option +which does **best effort** migration (some data might be lost, it is up to user +to review the standard error output and fix the issues manually in +post-migration time). + +Please keep in mind that the container image provides help for users' +convenience, but fully automatic migration is not guaranteed. Thus, before you +start proceeding with the database migration, get prepared to perform manual +steps in order to get all your data migrated. + +Note that you might not use variables like `POSTGRESQL_USER` in migration +scenario, all the data (including info about databases, roles or passwords are +copied from old cluster). Ensure that you use the same +`OPTIONAL_CONFIGURATION_VARIABLES` as you used for initialization of the old +PostgreSQL container. If some non-default configuration is done on remote +cluster, you might need to copy the configuration files manually, too. + +Security warning: Note that the IP communication between old and new PostgreSQL +clusters is not encrypted by default, it is up to user to configure SSL on +remote cluster or ensure security via different means. + +PostgreSQL auto-tuning +---------------------- + +When the PostgreSQL image is run with the `--memory` parameter set and if there +are no values provided for `POSTGRESQL_SHARED_BUFFERS` and +`POSTGRESQL_EFFECTIVE_CACHE_SIZE` those values are automatically calculated +based on the value provided in the `--memory` parameter. + +The values are calculated based on the +[upstream](https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server) +formulas. For the `shared_buffers` we use 1/4 of given memory and for the +`effective_cache_size` we set the value to 1/2 of the given memory. + +PostgreSQL admin account +------------------------ +The admin account `postgres` has no password set by default, only allowing local +connections. You can set it by setting the `POSTGRESQL_ADMIN_PASSWORD` environment +variable when initializing your container. This will allow you to login to the +`postgres` account remotely. Local connections will still not require a password. + + +Changing passwords +------------------ + +Since passwords are part of the image configuration, the only supported method +to change passwords for the database user (`POSTGRESQL_USER`) and `postgres` +admin user is by changing the environment variables `POSTGRESQL_PASSWORD` and +`POSTGRESQL_ADMIN_PASSWORD`, respectively. + +Changing database passwords through SQL statements or any way other than through +the environment variables aforementioned will cause a mismatch between the +values stored in the variables and the actual passwords. Whenever a database +container starts it will reset the passwords to the values stored in the +environment variables. + + +Upgrading database (by switching to newer PostgreSQL image version) +------------------------------------------------------------------- + +** Warning! Please, before you decide to do the data directory upgrade, always +ensure that you've carefully backed up all your data and that you are OK with +potential manual rollback! ** + +This image supports automatic upgrade of data directory created by +the PostgreSQL server version 10 (and _only_ this version) - provided by sclorg +image. The upgrade process is designed so that you should be able to just +switch from *image A* to *image B*, and set the `$POSTGRESQL_UPGRADE` variable +appropriately to explicitly request the database data transformation. + +The upgrade process is internally implemented via `pg_upgrade` binary, and for +that purpose the container needs to contain two versions of PostgreSQL server +(have a look at `man pg_upgrade` for more info). + +For the `pg_upgrade` process - and the new server version, we need to initialize +a brand new data directory. That's data directory is created automatically by +container tooling under /var/lib/pgsql/data, which is usually external +bind-mountpoint. The `pg_upgrade` execution is then similar to dump&restore +approach -- it starts both old and new PostgreSQL servers (within container) and +"dumps" the old datadir while and at the same time it "restores" it into new +datadir. This operation requires a lot of data files copying, so you can decide +what type of upgrade you'll do by setting `$POSTGRESQL_UPGRADE` appropriately: + +**`copy`** + The data files are copied from old datadir to new datadir. This option has low risk of data loss in case of some upgrade failure. + +**`hardlink`** + Data files are hard-linked from old to the new data directory, which brings performance optimization - but the old directory becomes unusable, even in case of failure. + + +Note that because we copy data directory, you need to make sure that you have +enough space for the copy; upgrade failure because of not enough space might +lead to data loss. + + +Extending image +---------------- + +This image can be extended in Openshift using the `Source` build strategy or via the standalone +[source-to-image](https://github.com/openshift/source-to-image) application (where available). +For this, we will assume that you are using the `rhscl/postgresql-12-rhel7` image, +available via `postgresql:12` imagestream tag in Openshift. + +For example to build customized image `new-postgresql` +with configuration from `https://github.com/sclorg/postgresql-container/tree/master/examples/extending-image` run: + +``` +$ oc new-app postgresql:12~https://github.com/sclorg/postgresql-container.git \ + --name new-postgresql \ + --context-dir examples/extending-image/ \ + -e POSTGRESQL_USER=user \ + -e POSTGRESQL_DATABASE=db \ + -e POSTGRESQL_PASSWORD=password +``` + +or via `s2i`: + +``` +$ s2i build --context-dir examples/extending-image/ https://github.com/sclorg/postgresql-container.git rhscl/postgresql-12-rhel7 new-postgresql +``` + +The directory passed to Openshift should contain one or more of the +following directories: + + +##### `postgresql-pre-start/` + +Source all `*.sh` files from this directory during early start of the +container. There's no PostgreSQL daemon running on background. + + +##### `postgresql-cfg/` + +Contained configuration files (`*.conf`) will be included at the end of image +postgresql.conf file. + + +##### `postgresql-init/` + +Contained shell scripts (`*.sh`) are sourced when the database is freshly +initialized (after successful initdb run which made the data directory +non-empty). At the time of sourcing these scripts, the local PostgreSQL +server is running. For re-deployments scenarios with persistent data +directory, the scripts are not sourced (no-op). + + +##### `postgresql-start/` + +Same sematics as `postgresql-init/`, except that these scripts are +always sourced (after `postgresql-init/` scripts, if they exist). + + +---------------------------------------------- + +During the s2i build all provided files are copied into `/opt/app-root/src` +directory in the new image. Only one +file with the same name can be used for customization and user provided files +are preferred over default files in `/usr/share/container-scripts/`- +so it is possible to overwrite them. + + +Troubleshooting +--------------- +At first the postgres daemon writes its logs to the standard output, so these are available in the container log. The log can be examined by running: + + podman logs + +Then log output is redirected to logging collector process and will appear in directory "pg_log". + + +See also +-------- +Dockerfile and other sources for this container image are available on +https://github.com/sclorg/postgresql-container. +In that repository, the Dockerfile for CentOS is called Dockerfile, the Dockerfile +for RHEL7 is called Dockerfile.rhel7, the Dockerfile for RHEL8 is called Dockerfile.rhel8, +the Dockerfile for RHEL9 is called Dockerfile.rhel9, +and the Dockerfile for Fedora is called Dockerfile.fedora. diff --git a/12/root/usr/share/container-scripts/postgresql/common.sh b/12/root/usr/share/container-scripts/postgresql/common.sh new file mode 100644 index 00000000..4b968f5a --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/common.sh @@ -0,0 +1,479 @@ +# Configuration settings. +export POSTGRESQL_MAX_CONNECTIONS=${POSTGRESQL_MAX_CONNECTIONS:-100} +export POSTGRESQL_MAX_PREPARED_TRANSACTIONS=${POSTGRESQL_MAX_PREPARED_TRANSACTIONS:-0} + +# Perform auto-tuning based on the container cgroups limits (only when the +# limits are set). +# Users can still override this by setting the POSTGRESQL_SHARED_BUFFERS +# and POSTGRESQL_EFFECTIVE_CACHE_SIZE variables. +if [[ "${NO_MEMORY_LIMIT:-}" == "true" || -z "${MEMORY_LIMIT_IN_BYTES:-}" ]]; then + export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-32MB} + export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-128MB} +else + # Use 1/4 of given memory for shared buffers + shared_buffers_computed="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/4))MB" + # Setting effective_cache_size to 1/2 of total memory would be a normal conservative setting, + effective_cache="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/2))MB" + export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-$shared_buffers_computed} + export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-$effective_cache} +fi + +export POSTGRESQL_RECOVERY_FILE=$HOME/openshift-custom-recovery.conf +export POSTGRESQL_CONFIG_FILE=$HOME/openshift-custom-postgresql.conf + +postinitdb_actions= + +# match . files when moving userdata below +shopt -s dotglob +# extglob enables the !(userdata) glob pattern below. +shopt -s extglob + +function usage() { + if [ $# == 1 ]; then + echo >&2 "error: $1" + fi + + cat >&2 </dev/null) + # FIXME: This is for debugging (docker run) + if [ -v POSTGRESQL_MASTER_IP ]; then + endpoints=${POSTGRESQL_MASTER_IP:-} + fi + if [ -z "$endpoints" ]; then + >&2 echo "Failed to resolve PostgreSQL master IP address" + exit 3 + fi + echo -n "$(echo $endpoints | cut -d ' ' -f 1)" +} + +# Converts the version in format x.y or x.y.z to a number. +version2number () +{ + local old_IFS=$IFS + local to_print= depth=${2-3} width=${3-2} sum=0 one_part + IFS='.' + set -- $1 + while test $depth -ge 1; do + depth=$(( depth - 1 )) + part=${1-0} ; shift || : + printf "%0${width}d" "$part" + done + IFS=$old_IFS +} + +# On non-intel arches, data_sync_retry = off does not work +# Upstream discussion: https://www.postgresql.org/message-id/CA+mCpegfOUph2U4ZADtQT16dfbkjjYNJL1bSTWErsazaFjQW9A@mail.gmail.com +# Upstream changes that caused this issue: +# https://github.com/postgres/postgres/commit/483520eca426fb1b428e8416d1d014ac5ad80ef4 +# https://github.com/postgres/postgres/commit/9ccdd7f66e3324d2b6d3dec282cfa9ff084083f1 +# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1779150 +# Special handle of data_sync_retry should handle only in some cases. +# These cases are: non-intel architectures, and version higher or equal 12.0, 10.7, 9.6.12 +# Return value 0 means the hack is needed. +function should_hack_data_sync_retry() { + [ "$(uname -p)" == 'x86_64' ] && return 1 + local version_number=$(version2number "$(pg_ctl -V | sed -e 's/^pg_ctl (PostgreSQL) //')") + # this matches all 12.x and versions of 10.x where we need the hack + [ "$version_number" -ge 100700 ] && return 0 + # this matches all 10.x that were not matched above + [ "$version_number" -ge 100000 ] && return 1 + # this matches all 9.x where need the hack + [ "$version_number" -ge 090612 ] && return 0 + # all rest should be older 9.x releases + return 1 +} + +# New config is generated every time a container is created. It only contains +# additional custom settings and is included from $PGDATA/postgresql.conf. +function generate_postgresql_config() { + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql.conf.template" \ + > "${POSTGRESQL_CONFIG_FILE}" + + if [ "${ENABLE_REPLICATION}" == "true" ]; then + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql-replication.conf.template" \ + >> "${POSTGRESQL_CONFIG_FILE}" + fi + + if should_hack_data_sync_retry ; then + echo "data_sync_retry = on" >>"${POSTGRESQL_CONFIG_FILE}" + fi + + ( + shopt -s nullglob + for conf in "${APP_DATA}"/src/postgresql-cfg/*.conf; do + echo include \'${conf}\' >> "${POSTGRESQL_CONFIG_FILE}" + done + ) +} + +function generate_postgresql_recovery_config() { + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-recovery.conf.template" \ + > "${POSTGRESQL_RECOVERY_FILE}" +} + +# Generate passwd file based on current uid +function generate_passwd_file() { + export USER_ID=$(id -u) + export GROUP_ID=$(id -g) + grep -v -e ^postgres -e ^$USER_ID /etc/passwd > "$HOME/passwd" + echo "postgres:x:${USER_ID}:${GROUP_ID}:PostgreSQL Server:${HOME}:/bin/bash" >> "$HOME/passwd" + export LD_PRELOAD=libnss_wrapper.so + export NSS_WRAPPER_PASSWD=${HOME}/passwd + export NSS_WRAPPER_GROUP=/etc/group +} + +initdb_wrapper () +{ + # Initialize the database cluster with utf8 support enabled by default. + # This might affect performance, see: + # http://www.postgresql.org/docs/12/static/locale.html + LANG=${LANG:-en_US.utf8} "$@" +} + +function initialize_database() { + initdb_wrapper initdb + + # PostgreSQL configuration. + cat >> "$PGDATA/postgresql.conf" <> "$PGDATA/pg_hba.conf" <&2 "\n========== \$PGDATA upgrade: %s -> %s ==========\n\n" \ + "$POSTGRESQL_PREV_VERSION" \ + "$POSTGRESQL_VERSION" + + info_msg () { printf >&2 "\n===> $*\n\n" ;} + + # pg_upgrade writes logs to cwd, so go to the persistent storage first + cd "$HOME"/data + + # disable this because of scl_source, 'set +u' just makes the code ugly + # anyways + set +u + + # we need to have the old SCL enabled, otherwise the $old_pgengine is not + # working. The scl_source script doesn't pay attention to non-zero exit + # statuses, so use 'set +e'. + set +e + source scl_source enable $old_collection + set -e + + case $POSTGRESQL_UPGRADE in + copy) # we accept this + ;; + hardlink) + optimized=: + ;; + *) + echo >&2 "Unsupported value: \$POSTGRESQL_UPGRADE=$POSTGRESQL_UPGRADE" + false + ;; + esac + + # Ensure $PGDATA_new doesn't exist yet, so we can immediately remove it if + # there's some problem. + test ! -e "$PGDATA_new" + + # initialize the database + info_msg "Initialize new data directory; we will migrate to that." + initdb_cmd=( initdb_wrapper "$new_pgengine"/initdb "$PGDATA_new" ) + eval "\${initdb_cmd[@]} ${POSTGRESQL_UPGRADE_INITDB_OPTIONS-}" || \ + { rm -rf "$PGDATA_new" ; false ; } + + upgrade_cmd=( + "$new_pgengine"/pg_upgrade + "--old-bindir=$old_pgengine" + "--new-bindir=$new_pgengine" + "--old-datadir=$PGDATA" + "--new-datadir=$PGDATA_new" + ) + + # Dangerous --link option, we loose $DATADIR if something goes wrong. + ! $optimized || upgrade_cmd+=(--link) + + # User-specififed options for pg_upgrade. + eval "upgrade_cmd+=(${POSTGRESQL_UPGRADE_PGUPGRADE_OPTIONS-})" + + # On non-intel arches the data_sync_retry set to on + sed -i -e 's/data_sync_retry/#data_sync_retry/' "${POSTGRESQL_CONFIG_FILE}" + + # the upgrade + info_msg "Starting the pg_upgrade process." + + # Once we stop support for PostgreSQL 9.4, we don't need + # REDHAT_PGUPGRADE_FROM_RHEL hack as we don't upgrade from 9.2 -- that means + # that we don't need to fiddle with unix_socket_director{y,ies} option. + REDHAT_PGUPGRADE_FROM_RHEL=1 \ + "${upgrade_cmd[@]}" || { cat $(find "$PGDATA_new"/.. -name pg_upgrade_server.log) ; rm -rf "$PGDATA_new" && false ; } + + # Move the important configuration and remove old data. This is highly + # careless, but we can't do more for this over-automatized process. + info_msg "Swap the old and new PGDATA and cleanup." + mv "$PGDATA"/*.conf "$PGDATA_new" + rm -rf "$PGDATA" + mv "$PGDATA_new" "$PGDATA" + + # Get back the option we changed above + sed -i -e 's/#data_sync_retry/data_sync_retry/' "${POSTGRESQL_CONFIG_FILE}" + + info_msg "Upgrade DONE." +) + + +# Run right after container startup, when the data volume is already initialized +# (not initialized by this container run) and thus there exists a chance that +# the data was generated by incompatible PostgreSQL major version. +try_pgupgrade () +{ + local versionfile="$PGDATA"/PG_VERSION version upgrade_available + + # This file always exists. + test -f "$versionfile" + version=$(cat "$versionfile") + + # If we don't support pg_upgrade, skip. + test -z "${POSTGRESQL_PREV_VERSION-}" && return 0 + + if test "$POSTGRESQL_VERSION" = "$version"; then + # No need to call pg_upgrade. + + # Mistakenly requests upgrade? If not, just start the DB. + test -z "${POSTGRESQL_UPGRADE-}" && return 0 + + # Make _sure_ we have this safety-belt here, otherwise our users would + # just specify '-e POSTGRESQL_UPGRADE=hardlink' permanently, even for + # re-deployment cases when upgrade is not needed. Setting such + # unfortunate default could mean that pg_upgrade might (after some user + # mistake) migrate (or even destruct, especially with --link) the old data + # directory with limited rollback options, if any. + echo >&2 + echo >&2 "== WARNING!! ==" + echo >&2 "PostgreSQL server version matches the datadir PG_VERSION." + echo >&2 "The \$POSTGRESQL_UPGRADE makes no sense and you probably" + echo >&2 "made some mistake, keeping the variable set you might" + echo >&2 "risk a data loss in future!" + echo >&2 "===============" + echo >&2 + + # Exit here, but allow _really explicit_ foot-shot. + ${POSTGRESQL_UPGRADE_FORCE-false} + return 0 + fi + + # At this point in code we know that PG_VERSION doesn't match the PostgreSQL + # server major version; this might mean that user either (a) mistakenly + # deploys from a bad image, or (b) user wants to perform upgrade. For the + # upgrade we require explicit request -- just to avoid disasters in (a)-cases. + + if test -z "${POSTGRESQL_UPGRADE-}"; then + echo >&2 "Incompatible data directory. This container image provides" + echo >&2 "PostgreSQL '$POSTGRESQL_VERSION', but data directory is of" + echo >&2 "version '$version'." + echo >&2 + echo >&2 "This image supports automatic data directory upgrade from" + echo >&2 "'$POSTGRESQL_PREV_VERSION', please _carefully_ consult image documentation" + echo >&2 "about how to use the '\$POSTGRESQL_UPGRADE' startup option." + # We could wait for postgresql startup failure (there's no risk of data dir + # corruption), but fail rather early. + false + fi + + # We support pg_upgrade process only from previous version of this container + # (upgrade to N to N+1 is possible, so e.g. 9.4 to 9.5). + if test "$POSTGRESQL_PREV_VERSION" != "$version"; then + echo >&2 "With this container image you can only upgrade from data directory" + echo >&2 "of version '$POSTGRESQL_PREV_VERSION', not '$version'." + false + fi + + run_pgupgrade +} + +# get_matched_files PATTERN DIR [DIR ...] +# --------------------------------------- +# Print all basenames for files matching PATTERN in DIRs. +get_matched_files () +{ + local pattern=$1 dir + shift + for dir; do + test -d "$dir" || continue + find -L "$dir" -maxdepth 1 -type f -name "$pattern" -printf "%f\n" + done +} + +# process_extending_files DIR [DIR ...] +# ------------------------------------- +# Source all *.sh files in DIRs in alphabetical order, but if the file exists in +# more then one DIR, source only the first occurrence (first found wins). +process_extending_files() +{ + local filename dir + while read filename ; do + for dir in "$@"; do + local file="$dir/$filename" + if test -f "$file"; then + echo "=> sourcing $file ..." + source "$file" + set -e # ensure that users don't mistakenly change this + break + fi + done + done <<<"$(get_matched_files '*.sh' "$@" | sort -u)" +} diff --git a/12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template b/12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template new file mode 100644 index 00000000..ef04eaae --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template @@ -0,0 +1,7 @@ +# required on master for replication +wal_level = hot_standby # minimal, archive, hot_standby, or logical +max_wal_senders = 6 # max number of walsender processes +wal_keep_segments = 400 # in logfile segments, 16MB each; 0 disables + +# required on replicas for replication +hot_standby = on diff --git a/12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template b/12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template new file mode 100644 index 00000000..3c2bc7f3 --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template @@ -0,0 +1,21 @@ +# +# Custom OpenShift configuration. +# +# NOTE: This file is rewritten every time the container is started! +# Changes to this file will be overwritten. +# + +# Listen on all interfaces. +listen_addresses = '*' + +# Determines the maximum number of concurrent connections to the database server. Default: 100 +max_connections = ${POSTGRESQL_MAX_CONNECTIONS} + +# Allow each connection to use a prepared transaction +max_prepared_transactions = ${POSTGRESQL_MAX_PREPARED_TRANSACTIONS} + +# Sets the amount of memory the database server uses for shared memory buffers. Default: 32MB +shared_buffers = ${POSTGRESQL_SHARED_BUFFERS} + +# Sets the planner's assumption about the effective size of the disk cache that is available to a single query +effective_cache_size = ${POSTGRESQL_EFFECTIVE_CACHE_SIZE} diff --git a/12/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template b/12/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template new file mode 100644 index 00000000..58d8e336 --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template @@ -0,0 +1,8 @@ +# +# Custom OpenShift configuration. +# +# NOTE: This file is rewritten every time the container is started! +# Changes to this file will be overwritten. +# + +primary_conninfo = 'host=${MASTER_FQDN} port=5432 user=${POSTGRESQL_MASTER_USER} password=${POSTGRESQL_MASTER_PASSWORD}' diff --git a/12/root/usr/share/container-scripts/postgresql/scl_enable b/12/root/usr/share/container-scripts/postgresql/scl_enable new file mode 100644 index 00000000..1d967f9b --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/scl_enable @@ -0,0 +1,3 @@ +# This will make scl collection binaries work out of box. +unset BASH_ENV PROMPT_COMMAND ENV +source scl_source enable $ENABLED_COLLECTIONS diff --git a/12/root/usr/share/container-scripts/postgresql/start/set_passwords.sh b/12/root/usr/share/container-scripts/postgresql/start/set_passwords.sh new file mode 100644 index 00000000..60d70e36 --- /dev/null +++ b/12/root/usr/share/container-scripts/postgresql/start/set_passwords.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +_psql () { psql --set ON_ERROR_STOP=1 "$@" ; } + +if [[ ",$postinitdb_actions," = *,simple_db,* ]]; then +_psql --set=username="$POSTGRESQL_USER" \ + --set=password="$POSTGRESQL_PASSWORD" \ +<<< "ALTER USER :\"username\" WITH ENCRYPTED PASSWORD :'password';" +fi + +if [ -v POSTGRESQL_MASTER_USER ]; then +_psql --set=masteruser="$POSTGRESQL_MASTER_USER" \ + --set=masterpass="$POSTGRESQL_MASTER_PASSWORD" \ +<<'EOF' +ALTER USER :"masteruser" WITH REPLICATION; +ALTER USER :"masteruser" WITH ENCRYPTED PASSWORD :'masterpass'; +EOF +fi + +if [ -v POSTGRESQL_ADMIN_PASSWORD ]; then +_psql --set=adminpass="$POSTGRESQL_ADMIN_PASSWORD" \ +<<<"ALTER USER \"postgres\" WITH ENCRYPTED PASSWORD :'adminpass';" +fi diff --git a/12/s2i/bin/assemble b/12/s2i/bin/assemble new file mode 100755 index 00000000..6ed8f7aa --- /dev/null +++ b/12/s2i/bin/assemble @@ -0,0 +1,14 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +shopt -s dotglob +echo "---> Installing application source ..." + + +mv /tmp/src/* ./ + +# Fix source directory permissions +/usr/libexec/fix-permissions --read-only ./ diff --git a/12/s2i/bin/run b/12/s2i/bin/run new file mode 120000 index 00000000..a7f4076b --- /dev/null +++ b/12/s2i/bin/run @@ -0,0 +1 @@ +/usr/bin/run-postgresql \ No newline at end of file diff --git a/12/s2i/bin/usage b/12/s2i/bin/usage new file mode 100755 index 00000000..9f413123 --- /dev/null +++ b/12/s2i/bin/usage @@ -0,0 +1 @@ +groff -t -man -ETascii /help.1 diff --git a/12/test b/12/test new file mode 120000 index 00000000..419df4f9 --- /dev/null +++ b/12/test @@ -0,0 +1 @@ +../test \ No newline at end of file diff --git a/13/Dockerfile.c8s b/13/Dockerfile.c8s new file mode 100644 index 00000000..e4e526a4 --- /dev/null +++ b/13/Dockerfile.c8s @@ -0,0 +1,84 @@ +FROM quay.io/sclorg/s2i-core-c8s:c8s + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=13 \ + POSTGRESQL_PREV_VERSION=12 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 13" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql13,postgresql-13" \ + io.openshift.s2i.assemble-user="26" \ + name="sclorg/postgresql-13-c8s" \ + com.redhat.component="postgresql-13-container" \ + version="1" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 sclorg/postgresql-13-c8s" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +RUN yum -y module enable postgresql:13 && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper postgresql-server postgresql-contrib" && \ + INSTALL_PKGS="$INSTALL_PKGS pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y reinstall tzdata && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS= + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/13/Dockerfile.c9s b/13/Dockerfile.c9s new file mode 100644 index 00000000..69aa8ed2 --- /dev/null +++ b/13/Dockerfile.c9s @@ -0,0 +1,83 @@ +FROM quay.io/sclorg/s2i-core-c9s:c9s + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=13 \ + POSTGRESQL_PREV_VERSION=12 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 13" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql13,postgresql-13" \ + io.openshift.s2i.assemble-user="26" \ + name="sclorg/postgresql-13-c9s" \ + com.redhat.component="postgresql-13-container" \ + version="1" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 sclorg/postgresql-13-c9s" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +RUN { yum -y module enable postgresql:13 || :; } && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper postgresql-server postgresql-contrib" && \ + INSTALL_PKGS="$INSTALL_PKGS pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS= + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/13/Dockerfile.rhel7 b/13/Dockerfile.rhel7 new file mode 100644 index 00000000..9bbe5ff9 --- /dev/null +++ b/13/Dockerfile.rhel7 @@ -0,0 +1,94 @@ +FROM rhscl/s2i-core-rhel7 + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=13 \ + POSTGRESQL_PREV_VERSION=12 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 13" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql13,rh-postgresql13" \ + io.openshift.s2i.assemble-user="26" \ + name="rhscl/postgresql-13-rhel7" \ + com.redhat.component="rh-postgresql13-container" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhscl/postgresql-13-rhel7" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +# rhel-7-server-ose-3.2-rpms is enabled for nss_wrapper until this pkg is +# in base RHEL +RUN yum install -y yum-utils gettext && \ + prepare-yum-repositories rhel-server-rhscl-7-rpms && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper rh-postgresql13 rh-postgresql13-postgresql-contrib rh-postgresql13-syspaths rh-postgresql12-postgresql-server" && \ + INSTALL_PKGS="$INSTALL_PKGS rh-postgresql13-pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS=rh-postgresql13 + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# When bash is started non-interactively, to run a shell script, for example it +# looks for this variable and source the content of this file. This will enable +# the SCL for all scripts without need to do 'scl enable'. +ENV BASH_ENV=${CONTAINER_SCRIPTS_PATH}/scl_enable \ + ENV=${CONTAINER_SCRIPTS_PATH}/scl_enable \ + PROMPT_COMMAND=". ${CONTAINER_SCRIPTS_PATH}/scl_enable" + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/13/Dockerfile.rhel8 b/13/Dockerfile.rhel8 new file mode 100644 index 00000000..0be804fb --- /dev/null +++ b/13/Dockerfile.rhel8 @@ -0,0 +1,85 @@ +FROM ubi8/s2i-core + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=13 \ + POSTGRESQL_PREV_VERSION=12 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 13" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql13,postgresql-13" \ + io.openshift.s2i.assemble-user="26" \ + name="rhel8/postgresql-13" \ + com.redhat.component="postgresql-13-container" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhel8/postgresql-13" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +RUN yum -y module enable postgresql:13 && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper postgresql-server postgresql-contrib" && \ + INSTALL_PKGS="$INSTALL_PKGS pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y reinstall tzdata && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS= + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/13/Dockerfile.rhel9 b/13/Dockerfile.rhel9 new file mode 100644 index 00000000..23d2a439 --- /dev/null +++ b/13/Dockerfile.rhel9 @@ -0,0 +1,85 @@ +FROM ubi9/s2i-core + +# PostgreSQL image for OpenShift. +# Volumes: +# * /var/lib/pgsql/data - Database cluster for PostgreSQL +# Environment: +# * $POSTGRESQL_USER - Database user name +# * $POSTGRESQL_PASSWORD - User's password +# * $POSTGRESQL_DATABASE - Name of the database to create +# * $POSTGRESQL_ADMIN_PASSWORD (Optional) - Password for the 'postgres' +# PostgreSQL administrative account + +ENV POSTGRESQL_VERSION=13 \ + POSTGRESQL_PREV_VERSION=12 \ + HOME=/var/lib/pgsql \ + PGUSER=postgres \ + APP_DATA=/opt/app-root + +ENV SUMMARY="PostgreSQL is an advanced Object-Relational database management system" \ + DESCRIPTION="PostgreSQL is an advanced Object-Relational database management system (DBMS). \ +The image contains the client and server programs that you'll need to \ +create, run, maintain and access a PostgreSQL DBMS server." + +LABEL summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="PostgreSQL 13" \ + io.openshift.expose-services="5432:postgresql" \ + io.openshift.tags="database,postgresql,postgresql13,postgresql-13" \ + io.openshift.s2i.assemble-user="26" \ + name="rhel9/postgresql-13" \ + com.redhat.component="postgresql-13-container" \ + version="1" \ + com.redhat.license_terms="https://www.redhat.com/en/about/red-hat-end-user-license-agreements#rhel" \ + usage="podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhel9/postgresql-13" \ + maintainer="SoftwareCollections.org " + +EXPOSE 5432 + +COPY root/usr/libexec/fix-permissions /usr/libexec/fix-permissions + +# This image must forever use UID 26 for postgres user so our volumes are +# safe in the future. This should *never* change, the last test is there +# to make sure of that. +RUN { yum -y module enable postgresql:13 || :; } && \ + INSTALL_PKGS="rsync tar gettext bind-utils nss_wrapper postgresql-server postgresql-contrib" && \ + INSTALL_PKGS="$INSTALL_PKGS pgaudit" && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + yum -y reinstall tzdata && \ + yum -y clean all --enablerepo='*' && \ + localedef -f UTF-8 -i en_US en_US.UTF-8 && \ + test "$(id postgres)" = "uid=26(postgres) gid=26(postgres) groups=26(postgres)" && \ + mkdir -p /var/lib/pgsql/data && \ + /usr/libexec/fix-permissions /var/lib/pgsql /var/run/postgresql + +# Get prefix path and path to scripts rather than hard-code them in scripts +ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/postgresql \ + ENABLED_COLLECTIONS= + +COPY root / +COPY ./s2i/bin/ $STI_SCRIPTS_PATH + +# Not using VOLUME statement since it's not working in OpenShift Online: +# https://github.com/sclorg/httpd-container/issues/30 +# VOLUME ["/var/lib/pgsql/data"] + +# S2I permission fixes +# -------------------- +# 1. unless specified otherwise (or - equivalently - we are in OpenShift), s2i +# build process would be executed as 'uid=26(postgres) gid=26(postgres)'. +# Such process wouldn't be able to execute the default 'assemble' script +# correctly (it transitively executes 'fix-permissions' script). So let's +# add the 'postgres' user into 'root' group here +# +# 2. we call fix-permissions on $APP_DATA here directly (UID=0 during build +# anyways) to assure that s2i process is actually able to _read_ the +# user-specified scripting. +RUN usermod -a -G root postgres && \ + /usr/libexec/fix-permissions --read-only "$APP_DATA" + +USER 26 + +ENTRYPOINT ["container-entrypoint"] +CMD ["run-postgresql"] diff --git a/13/README.md b/13/README.md new file mode 120000 index 00000000..d359f030 --- /dev/null +++ b/13/README.md @@ -0,0 +1 @@ +root/usr/share/container-scripts/postgresql/README.md \ No newline at end of file diff --git a/13/cccp.yml b/13/cccp.yml new file mode 100644 index 00000000..2a88a7b7 --- /dev/null +++ b/13/cccp.yml @@ -0,0 +1 @@ +job-id: postgresql-13-centos7 diff --git a/13/content_sets.yml b/13/content_sets.yml new file mode 100644 index 00000000..432c0914 --- /dev/null +++ b/13/content_sets.yml @@ -0,0 +1,10 @@ +# This is a file defining which content sets are needed to update content in +# this image. Data provided here helps determine which images are vulnerable to +# specific CVEs. Generally you should only need to update this file when: +# 1. You start depending on new product +# 2. You are preparing new product release and your content sets will change +--- +x86_64: +- rhel-7-server-rpms +- rhel-7-server-optional-rpms +- rhel-server-rhscl-7-rpms diff --git a/13/root/usr/bin/container-entrypoint b/13/root/usr/bin/container-entrypoint new file mode 100755 index 00000000..5fc44481 --- /dev/null +++ b/13/root/usr/bin/container-entrypoint @@ -0,0 +1,3 @@ +#!/bin/bash + +exec "$@" diff --git a/13/root/usr/bin/run-postgresql b/13/root/usr/bin/run-postgresql new file mode 100755 index 00000000..2367e57e --- /dev/null +++ b/13/root/usr/bin/run-postgresql @@ -0,0 +1,58 @@ +#!/bin/bash + +export ENABLE_REPLICATION=${ENABLE_REPLICATION:-false} + +set -eu +export_vars=$(cgroup-limits) ; export $export_vars + +source "${CONTAINER_SCRIPTS_PATH}/common.sh" + +set_pgdata + +process_extending_files \ + "${APP_DATA}/src/postgresql-pre-start" \ + "${CONTAINER_SCRIPTS_PATH}/pre-start" + +check_env_vars +generate_passwd_file +generate_postgresql_config + +# Is this brand new data volume? +PG_INITIALIZED=false + +if [ ! -f "$PGDATA/postgresql.conf" ]; then + initialize_database + PG_INITIALIZED=: +else + try_pgupgrade +fi + +# Use insanely large timeout (24h) to ensure that the potential recovery has +# enough time here to happen (unless liveness probe kills us). Note that in +# case of server failure this command still exists immediately. +pg_ctl start -w --timeout 86400 -o "-h ''" + +# This is just a pedantic safety measure (the timeout above is unlikely to +# happen), but `pt_ctl -w` is not reliable prior to PostgreSQL v10 where it +# returns exit_status=0 even if the server is still starting. For more info +# see the issue#297 and +# https://www.postgresql.org/message-id/CAB7nPqSJs85wK9aknm%3D_jmS6GnH3SQBhpzKcqs8Qo2LhEg2etw%40mail.gmail.com +pg_isready + +if $PG_INITIALIZED ; then + process_extending_files \ + "${APP_DATA}/src/postgresql-init" \ + "${CONTAINER_SCRIPTS_PATH}/init" + migrate_db + create_users +fi + +process_extending_files \ + "${APP_DATA}/src/postgresql-start" \ + "${CONTAINER_SCRIPTS_PATH}/start" + +pg_ctl stop + +unset_env_vars +echo "Starting server..." +exec postgres "$@" diff --git a/13/root/usr/bin/run-postgresql-master b/13/root/usr/bin/run-postgresql-master new file mode 100755 index 00000000..79e7cc24 --- /dev/null +++ b/13/root/usr/bin/run-postgresql-master @@ -0,0 +1,5 @@ +#!/bin/bash + +export ENABLE_REPLICATION=true + +exec run-postgresql "$@" diff --git a/13/root/usr/bin/run-postgresql-slave b/13/root/usr/bin/run-postgresql-slave new file mode 100755 index 00000000..586bf5d7 --- /dev/null +++ b/13/root/usr/bin/run-postgresql-slave @@ -0,0 +1,39 @@ +#!/bin/bash + +export ENABLE_REPLICATION=true + +set -eu +export_vars=$(cgroup-limits) ; export $export_vars + +source "$CONTAINER_SCRIPTS_PATH"/common.sh + +set_pgdata + +function initialize_replica() { + echo "Initializing PostgreSQL slave ..." + # TODO: Validate and reuse existing data? + rm -rf $PGDATA + PGPASSWORD="${POSTGRESQL_MASTER_PASSWORD}" pg_basebackup -X fetch --no-password --pgdata ${PGDATA} --host=${MASTER_FQDN} --port=5432 -U "${POSTGRESQL_MASTER_USER}" + + # PostgreSQL recovery configuration. + generate_postgresql_recovery_config + cat >> "$PGDATA/postgresql.auto.conf" <&2 <&2 "fixing permissions on '$dir' directory" + find "$dir" -exec chown "$uid:0" {} \; + find "$dir" -exec chmod "g+r$write" {} \; + find "$dir" -type d -exec chmod g+x {} + +done diff --git a/13/root/usr/share/container-scripts/postgresql/README.md b/13/root/usr/share/container-scripts/postgresql/README.md new file mode 100644 index 00000000..fb1dbfa2 --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/README.md @@ -0,0 +1,331 @@ +PostgreSQL 13 SQL Database Server container image +=============================================== + +This container image includes PostgreSQL 13 SQL database server for OpenShift and general usage. +Users can choose between RHEL, CentOS and Fedora based images. +The RHEL images are available in the [Red Hat Container Catalog](https://access.redhat.com/containers/), +the CentOS images are available on [Quay.io](https://quay.io/organization/centos7), +and the Fedora images are available in [Quay.io](https://quay.io/organization/fedora). +The resulting image can be run using [podman](https://github.com/containers/libpod). + +Note: while the examples in this README are calling `podman`, you can replace any such calls by `docker` with the same arguments + + +Description +----------- + +This container image provides a containerized packaging of the PostgreSQL postgres daemon +and client application. The postgres server daemon accepts connections from clients +and provides access to content from PostgreSQL databases on behalf of the clients. +You can find more information on the PostgreSQL project from the project Web site +(https://www.postgresql.org/). + + +Usage +----- + +For this, we will assume that you are using the `rhscl/postgresql-13-rhel7` image, available via `postgresql:13` imagestream tag in Openshift. +If you want to set only the mandatory environment variables and not store the database +in a host directory, execute the following command: + +``` +$ podman run -d --name postgresql_database -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRESQL_DATABASE=db -p 5432:5432 rhscl/postgresql-13-rhel7 +``` + +This will create a container named `postgresql_database` running PostgreSQL with +database `db` and user with credentials `user:pass`. +> Note: user `postgres` is reserved for internal usage + +Port 5432 will be exposed +and mapped to the host. If you want your database to be persistent across container +executions, also add a `-v /host/db/path:/var/lib/pgsql/data` argument (see +below). This will be the PostgreSQL database cluster directory. + +The same can be achieved in an Openshift instance using templates provided by Openshift or available in [examples](https://github.com/sclorg/postgresql-container/tree/master/examples): + +``` +$ oc process -f examples/postgresql-ephemeral-template.json -p POSTGRESQL_VERSION=13 -p POSTGRESQL_USER=user -p POSTGRESQL_PASSWORD=pass -p POSTGRESQL_DATABASE=db | oc create -f - +``` + +If the database cluster directory is not initialized, the entrypoint script will +first run [`initdb`](http://www.postgresql.org/docs/13/static/app-initdb.html) +and setup necessary database users and passwords. After the database is initialized, +or if it was already present, [`postgres`](http://www.postgresql.org/docs/13/static/app-postgres.html) +is executed and will run as PID 1. You can stop the detached container by running +`podman stop postgresql_database`. + + + +Environment variables and volumes +--------------------------------- + +The image recognizes the following environment variables that you can set during +initialization by passing `-e VAR=VALUE` to the Docker run command. + +**`POSTGRESQL_USER`** + User name for PostgreSQL account to be created + +**`POSTGRESQL_PASSWORD`** + Password for the user account + +**`POSTGRESQL_DATABASE`** + Database name + +**`POSTGRESQL_ADMIN_PASSWORD`** + Password for the `postgres` admin account (optional) + + +Alternatively, the following options are related to migration scenario: + +**`POSTGRESQL_MIGRATION_REMOTE_HOST`** + Hostname/IP to migrate from + +**`POSTGRESQL_MIGRATION_ADMIN_PASSWORD`** + Password for the remote 'postgres' admin user + +**`POSTGRESQL_MIGRATION_IGNORE_ERRORS (optional, default 'no')`** + Set to 'yes' to ignore sql import errors + + +The following environment variables influence the PostgreSQL configuration file. They are all optional. + +**`POSTGRESQL_MAX_CONNECTIONS (default: 100)`** + The maximum number of client connections allowed + +**`POSTGRESQL_MAX_PREPARED_TRANSACTIONS (default: 0)`** + Sets the maximum number of transactions that can be in the "prepared" state. If you are using prepared transactions, you will probably want this to be at least as large as max_connections + +**`POSTGRESQL_SHARED_BUFFERS (default: 1/4 of memory limit or 32M)`** + Sets how much memory is dedicated to PostgreSQL to use for caching data + +**`POSTGRESQL_EFFECTIVE_CACHE_SIZE (default: 1/2 of memory limit or 128M)`** + Set to an estimate of how much memory is available for disk caching by the operating system and within the database itself + + +You can also set the following mount points by passing the `-v /host/dir:/container/dir:Z` flag to Docker. + +**`/var/lib/pgsql/data`** + PostgreSQL database cluster directory + + +**Notice: When mouting a directory from the host into the container, ensure that the mounted +directory has the appropriate permissions and that the owner and group of the directory +matches the user UID or name which is running inside the container.** + +Typically (unless you use `podman run -u` option) processes in container +run under UID 26, so -- on GNU/Linux -- you can fix the datadir permissions +for example by: + +``` +$ setfacl -m u:26:-wx /your/data/dir +$ podman run <...> -v /your/data/dir:/var/lib/pgsql/data:Z <...> +``` + + +Data migration +-------------- + +PostgreSQL container supports migration of data from remote PostgreSQL server. +You can run it like: + +``` +$ podman run -d --name postgresql_database \ + -e POSTGRESQL_MIGRATION_REMOTE_HOST=172.17.0.2 \ + -e POSTGRESQL_MIGRATION_ADMIN_PASSWORD=remoteAdminP@ssword \ + [ OPTIONAL_CONFIGURATION_VARIABLES ] + openshift/postgresql-92-centos7 +``` + +The migration is done the **dump and restore** way (running `pg_dumpall` against +remote cluster and importing the dump locally by `psql`). Because the process +is streamed (unix pipeline), there are no intermediate dump files created during +this process to not waste additional storage space. + +If some SQL commands fail during applying, the default behavior +of the migration script is to fail as well to ensure the **all** or **nothing** +result of scripted, unattended migration. In most common cases, successful +migration is expected (but not guaranteed!), given you migrate from +a previous version of PostgreSQL server container, that is created using +the same principles as this one (e.g. migration from +`openshift/postgresql-92-centos7` to `centos/postgresql-95-centos7`). +Migration from a different kind of PostgreSQL container can likely fail. + +If this **all** or **nothing** principle is inadequate for you, and you know +what you are doing, there's optional `POSTGRESQL_MIGRATION_IGNORE_ERRORS` option +which does **best effort** migration (some data might be lost, it is up to user +to review the standard error output and fix the issues manually in +post-migration time). + +Please keep in mind that the container image provides help for users' +convenience, but fully automatic migration is not guaranteed. Thus, before you +start proceeding with the database migration, get prepared to perform manual +steps in order to get all your data migrated. + +Note that you might not use variables like `POSTGRESQL_USER` in migration +scenario, all the data (including info about databases, roles or passwords are +copied from old cluster). Ensure that you use the same +`OPTIONAL_CONFIGURATION_VARIABLES` as you used for initialization of the old +PostgreSQL container. If some non-default configuration is done on remote +cluster, you might need to copy the configuration files manually, too. + +Security warning: Note that the IP communication between old and new PostgreSQL +clusters is not encrypted by default, it is up to user to configure SSL on +remote cluster or ensure security via different means. + +PostgreSQL auto-tuning +---------------------- + +When the PostgreSQL image is run with the `--memory` parameter set and if there +are no values provided for `POSTGRESQL_SHARED_BUFFERS` and +`POSTGRESQL_EFFECTIVE_CACHE_SIZE` those values are automatically calculated +based on the value provided in the `--memory` parameter. + +The values are calculated based on the +[upstream](https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server) +formulas. For the `shared_buffers` we use 1/4 of given memory and for the +`effective_cache_size` we set the value to 1/2 of the given memory. + +PostgreSQL admin account +------------------------ +The admin account `postgres` has no password set by default, only allowing local +connections. You can set it by setting the `POSTGRESQL_ADMIN_PASSWORD` environment +variable when initializing your container. This will allow you to login to the +`postgres` account remotely. Local connections will still not require a password. + + +Changing passwords +------------------ + +Since passwords are part of the image configuration, the only supported method +to change passwords for the database user (`POSTGRESQL_USER`) and `postgres` +admin user is by changing the environment variables `POSTGRESQL_PASSWORD` and +`POSTGRESQL_ADMIN_PASSWORD`, respectively. + +Changing database passwords through SQL statements or any way other than through +the environment variables aforementioned will cause a mismatch between the +values stored in the variables and the actual passwords. Whenever a database +container starts it will reset the passwords to the values stored in the +environment variables. + + +Upgrading database (by switching to newer PostgreSQL image version) +------------------------------------------------------------------- + +** Warning! Please, before you decide to do the data directory upgrade, always +ensure that you've carefully backed up all your data and that you are OK with +potential manual rollback! ** + +This image supports automatic upgrade of data directory created by +the PostgreSQL server version 12 (and _only_ this version) - provided by sclorg +image. The upgrade process is designed so that you should be able to just +switch from *image A* to *image B*, and set the `$POSTGRESQL_UPGRADE` variable +appropriately to explicitly request the database data transformation. + +The upgrade process is internally implemented via `pg_upgrade` binary, and for +that purpose the container needs to contain two versions of PostgreSQL server +(have a look at `man pg_upgrade` for more info). + +For the `pg_upgrade` process - and the new server version, we need to initialize +a brand new data directory. That's data directory is created automatically by +container tooling under /var/lib/pgsql/data, which is usually external +bind-mountpoint. The `pg_upgrade` execution is then similar to dump&restore +approach -- it starts both old and new PostgreSQL servers (within container) and +"dumps" the old datadir while and at the same time it "restores" it into new +datadir. This operation requires a lot of data files copying, so you can decide +what type of upgrade you'll do by setting `$POSTGRESQL_UPGRADE` appropriately: + +**`copy`** + The data files are copied from old datadir to new datadir. This option has low risk of data loss in case of some upgrade failure. + +**`hardlink`** + Data files are hard-linked from old to the new data directory, which brings performance optimization - but the old directory becomes unusable, even in case of failure. + + +Note that because we copy data directory, you need to make sure that you have +enough space for the copy; upgrade failure because of not enough space might +lead to data loss. + + +Extending image +---------------- + +This image can be extended in Openshift using the `Source` build strategy or via the standalone +[source-to-image](https://github.com/openshift/source-to-image) application (where available). +For this, we will assume that you are using the `rhscl/postgresql-13-rhel7` image, +available via `postgresql:13` imagestream tag in Openshift. + +For example to build customized image `new-postgresql` +with configuration from `https://github.com/sclorg/postgresql-container/tree/master/examples/extending-image` run: + +``` +$ oc new-app postgresql:13~https://github.com/sclorg/postgresql-container.git \ + --name new-postgresql \ + --context-dir examples/extending-image/ \ + -e POSTGRESQL_USER=user \ + -e POSTGRESQL_DATABASE=db \ + -e POSTGRESQL_PASSWORD=password +``` + +or via `s2i`: + +``` +$ s2i build --context-dir examples/extending-image/ https://github.com/sclorg/postgresql-container.git rhscl/postgresql-13-rhel7 new-postgresql +``` + +The directory passed to Openshift should contain one or more of the +following directories: + + +##### `postgresql-pre-start/` + +Source all `*.sh` files from this directory during early start of the +container. There's no PostgreSQL daemon running on background. + + +##### `postgresql-cfg/` + +Contained configuration files (`*.conf`) will be included at the end of image +postgresql.conf file. + + +##### `postgresql-init/` + +Contained shell scripts (`*.sh`) are sourced when the database is freshly +initialized (after successful initdb run which made the data directory +non-empty). At the time of sourcing these scripts, the local PostgreSQL +server is running. For re-deployments scenarios with persistent data +directory, the scripts are not sourced (no-op). + + +##### `postgresql-start/` + +Same sematics as `postgresql-init/`, except that these scripts are +always sourced (after `postgresql-init/` scripts, if they exist). + + +---------------------------------------------- + +During the s2i build all provided files are copied into `/opt/app-root/src` +directory in the new image. Only one +file with the same name can be used for customization and user provided files +are preferred over default files in `/usr/share/container-scripts/`- +so it is possible to overwrite them. + + +Troubleshooting +--------------- +At first the postgres daemon writes its logs to the standard output, so these are available in the container log. The log can be examined by running: + + podman logs + +Then log output is redirected to logging collector process and will appear in directory "pg_log". + + +See also +-------- +Dockerfile and other sources for this container image are available on +https://github.com/sclorg/postgresql-container. +In that repository, the Dockerfile for CentOS is called Dockerfile, the Dockerfile +for RHEL7 is called Dockerfile.rhel7, the Dockerfile for RHEL8 is called Dockerfile.rhel8, +the Dockerfile for RHEL9 is called Dockerfile.rhel9, +and the Dockerfile for Fedora is called Dockerfile.fedora. diff --git a/13/root/usr/share/container-scripts/postgresql/common.sh b/13/root/usr/share/container-scripts/postgresql/common.sh new file mode 100644 index 00000000..8c8b2dd6 --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/common.sh @@ -0,0 +1,479 @@ +# Configuration settings. +export POSTGRESQL_MAX_CONNECTIONS=${POSTGRESQL_MAX_CONNECTIONS:-100} +export POSTGRESQL_MAX_PREPARED_TRANSACTIONS=${POSTGRESQL_MAX_PREPARED_TRANSACTIONS:-0} + +# Perform auto-tuning based on the container cgroups limits (only when the +# limits are set). +# Users can still override this by setting the POSTGRESQL_SHARED_BUFFERS +# and POSTGRESQL_EFFECTIVE_CACHE_SIZE variables. +if [[ "${NO_MEMORY_LIMIT:-}" == "true" || -z "${MEMORY_LIMIT_IN_BYTES:-}" ]]; then + export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-32MB} + export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-128MB} +else + # Use 1/4 of given memory for shared buffers + shared_buffers_computed="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/4))MB" + # Setting effective_cache_size to 1/2 of total memory would be a normal conservative setting, + effective_cache="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/2))MB" + export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-$shared_buffers_computed} + export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-$effective_cache} +fi + +export POSTGRESQL_RECOVERY_FILE=$HOME/openshift-custom-recovery.conf +export POSTGRESQL_CONFIG_FILE=$HOME/openshift-custom-postgresql.conf + +postinitdb_actions= + +# match . files when moving userdata below +shopt -s dotglob +# extglob enables the !(userdata) glob pattern below. +shopt -s extglob + +function usage() { + if [ $# == 1 ]; then + echo >&2 "error: $1" + fi + + cat >&2 </dev/null) + # FIXME: This is for debugging (docker run) + if [ -v POSTGRESQL_MASTER_IP ]; then + endpoints=${POSTGRESQL_MASTER_IP:-} + fi + if [ -z "$endpoints" ]; then + >&2 echo "Failed to resolve PostgreSQL master IP address" + exit 3 + fi + echo -n "$(echo $endpoints | cut -d ' ' -f 1)" +} + +# Converts the version in format x.y or x.y.z to a number. +version2number () +{ + local old_IFS=$IFS + local to_print= depth=${2-3} width=${3-2} sum=0 one_part + IFS='.' + set -- $1 + while test $depth -ge 1; do + depth=$(( depth - 1 )) + part=${1-0} ; shift || : + printf "%0${width}d" "$part" + done + IFS=$old_IFS +} + +# On non-intel arches, data_sync_retry = off does not work +# Upstream discussion: https://www.postgresql.org/message-id/CA+mCpegfOUph2U4ZADtQT16dfbkjjYNJL1bSTWErsazaFjQW9A@mail.gmail.com +# Upstream changes that caused this issue: +# https://github.com/postgres/postgres/commit/483520eca426fb1b428e8416d1d014ac5ad80ef4 +# https://github.com/postgres/postgres/commit/9ccdd7f66e3324d2b6d3dec282cfa9ff084083f1 +# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1779150 +# Special handle of data_sync_retry should handle only in some cases. +# These cases are: non-intel architectures, and version higher or equal 12.0, 10.7, 9.6.12 +# Return value 0 means the hack is needed. +function should_hack_data_sync_retry() { + [ "$(uname -p)" == 'x86_64' ] && return 1 + local version_number=$(version2number "$(pg_ctl -V | sed -e 's/^pg_ctl (PostgreSQL) //')") + # this matches all 12.x and versions of 10.x where we need the hack + [ "$version_number" -ge 100700 ] && return 0 + # this matches all 10.x that were not matched above + [ "$version_number" -ge 100000 ] && return 1 + # this matches all 9.x where need the hack + [ "$version_number" -ge 090612 ] && return 0 + # all rest should be older 9.x releases + return 1 +} + +# New config is generated every time a container is created. It only contains +# additional custom settings and is included from $PGDATA/postgresql.conf. +function generate_postgresql_config() { + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql.conf.template" \ + > "${POSTGRESQL_CONFIG_FILE}" + + if [ "${ENABLE_REPLICATION}" == "true" ]; then + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql-replication.conf.template" \ + >> "${POSTGRESQL_CONFIG_FILE}" + fi + + if should_hack_data_sync_retry ; then + echo "data_sync_retry = on" >>"${POSTGRESQL_CONFIG_FILE}" + fi + + ( + shopt -s nullglob + for conf in "${APP_DATA}"/src/postgresql-cfg/*.conf; do + echo include \'${conf}\' >> "${POSTGRESQL_CONFIG_FILE}" + done + ) +} + +function generate_postgresql_recovery_config() { + envsubst \ + < "${CONTAINER_SCRIPTS_PATH}/openshift-custom-recovery.conf.template" \ + > "${POSTGRESQL_RECOVERY_FILE}" +} + +# Generate passwd file based on current uid +function generate_passwd_file() { + export USER_ID=$(id -u) + export GROUP_ID=$(id -g) + grep -v -e ^postgres -e ^$USER_ID /etc/passwd > "$HOME/passwd" + echo "postgres:x:${USER_ID}:${GROUP_ID}:PostgreSQL Server:${HOME}:/bin/bash" >> "$HOME/passwd" + export LD_PRELOAD=libnss_wrapper.so + export NSS_WRAPPER_PASSWD=${HOME}/passwd + export NSS_WRAPPER_GROUP=/etc/group +} + +initdb_wrapper () +{ + # Initialize the database cluster with utf8 support enabled by default. + # This might affect performance, see: + # http://www.postgresql.org/docs/13/static/locale.html + LANG=${LANG:-en_US.utf8} "$@" +} + +function initialize_database() { + initdb_wrapper initdb + + # PostgreSQL configuration. + cat >> "$PGDATA/postgresql.conf" <> "$PGDATA/pg_hba.conf" <&2 "\n========== \$PGDATA upgrade: %s -> %s ==========\n\n" \ + "$POSTGRESQL_PREV_VERSION" \ + "$POSTGRESQL_VERSION" + + info_msg () { printf >&2 "\n===> $*\n\n" ;} + + # pg_upgrade writes logs to cwd, so go to the persistent storage first + cd "$HOME"/data + + # disable this because of scl_source, 'set +u' just makes the code ugly + # anyways + set +u + + # we need to have the old SCL enabled, otherwise the $old_pgengine is not + # working. The scl_source script doesn't pay attention to non-zero exit + # statuses, so use 'set +e'. + set +e + source scl_source enable $old_collection + set -e + + case $POSTGRESQL_UPGRADE in + copy) # we accept this + ;; + hardlink) + optimized=: + ;; + *) + echo >&2 "Unsupported value: \$POSTGRESQL_UPGRADE=$POSTGRESQL_UPGRADE" + false + ;; + esac + + # Ensure $PGDATA_new doesn't exist yet, so we can immediately remove it if + # there's some problem. + test ! -e "$PGDATA_new" + + # initialize the database + info_msg "Initialize new data directory; we will migrate to that." + initdb_cmd=( initdb_wrapper "$new_pgengine"/initdb "$PGDATA_new" ) + eval "\${initdb_cmd[@]} ${POSTGRESQL_UPGRADE_INITDB_OPTIONS-}" || \ + { rm -rf "$PGDATA_new" ; false ; } + + upgrade_cmd=( + "$new_pgengine"/pg_upgrade + "--old-bindir=$old_pgengine" + "--new-bindir=$new_pgengine" + "--old-datadir=$PGDATA" + "--new-datadir=$PGDATA_new" + ) + + # Dangerous --link option, we loose $DATADIR if something goes wrong. + ! $optimized || upgrade_cmd+=(--link) + + # User-specififed options for pg_upgrade. + eval "upgrade_cmd+=(${POSTGRESQL_UPGRADE_PGUPGRADE_OPTIONS-})" + + # On non-intel arches the data_sync_retry set to on + sed -i -e 's/data_sync_retry/#data_sync_retry/' "${POSTGRESQL_CONFIG_FILE}" + + # the upgrade + info_msg "Starting the pg_upgrade process." + + # Once we stop support for PostgreSQL 9.4, we don't need + # REDHAT_PGUPGRADE_FROM_RHEL hack as we don't upgrade from 9.2 -- that means + # that we don't need to fiddle with unix_socket_director{y,ies} option. + REDHAT_PGUPGRADE_FROM_RHEL=1 \ + "${upgrade_cmd[@]}" || { cat $(find "$PGDATA_new"/.. -name pg_upgrade_server.log) ; rm -rf "$PGDATA_new" && false ; } + + # Move the important configuration and remove old data. This is highly + # careless, but we can't do more for this over-automatized process. + info_msg "Swap the old and new PGDATA and cleanup." + mv "$PGDATA"/*.conf "$PGDATA_new" + rm -rf "$PGDATA" + mv "$PGDATA_new" "$PGDATA" + + # Get back the option we changed above + sed -i -e 's/#data_sync_retry/data_sync_retry/' "${POSTGRESQL_CONFIG_FILE}" + + info_msg "Upgrade DONE." +) + + +# Run right after container startup, when the data volume is already initialized +# (not initialized by this container run) and thus there exists a chance that +# the data was generated by incompatible PostgreSQL major version. +try_pgupgrade () +{ + local versionfile="$PGDATA"/PG_VERSION version upgrade_available + + # This file always exists. + test -f "$versionfile" + version=$(cat "$versionfile") + + # If we don't support pg_upgrade, skip. + test -z "${POSTGRESQL_PREV_VERSION-}" && return 0 + + if test "$POSTGRESQL_VERSION" = "$version"; then + # No need to call pg_upgrade. + + # Mistakenly requests upgrade? If not, just start the DB. + test -z "${POSTGRESQL_UPGRADE-}" && return 0 + + # Make _sure_ we have this safety-belt here, otherwise our users would + # just specify '-e POSTGRESQL_UPGRADE=hardlink' permanently, even for + # re-deployment cases when upgrade is not needed. Setting such + # unfortunate default could mean that pg_upgrade might (after some user + # mistake) migrate (or even destruct, especially with --link) the old data + # directory with limited rollback options, if any. + echo >&2 + echo >&2 "== WARNING!! ==" + echo >&2 "PostgreSQL server version matches the datadir PG_VERSION." + echo >&2 "The \$POSTGRESQL_UPGRADE makes no sense and you probably" + echo >&2 "made some mistake, keeping the variable set you might" + echo >&2 "risk a data loss in future!" + echo >&2 "===============" + echo >&2 + + # Exit here, but allow _really explicit_ foot-shot. + ${POSTGRESQL_UPGRADE_FORCE-false} + return 0 + fi + + # At this point in code we know that PG_VERSION doesn't match the PostgreSQL + # server major version; this might mean that user either (a) mistakenly + # deploys from a bad image, or (b) user wants to perform upgrade. For the + # upgrade we require explicit request -- just to avoid disasters in (a)-cases. + + if test -z "${POSTGRESQL_UPGRADE-}"; then + echo >&2 "Incompatible data directory. This container image provides" + echo >&2 "PostgreSQL '$POSTGRESQL_VERSION', but data directory is of" + echo >&2 "version '$version'." + echo >&2 + echo >&2 "This image supports automatic data directory upgrade from" + echo >&2 "'$POSTGRESQL_PREV_VERSION', please _carefully_ consult image documentation" + echo >&2 "about how to use the '\$POSTGRESQL_UPGRADE' startup option." + # We could wait for postgresql startup failure (there's no risk of data dir + # corruption), but fail rather early. + false + fi + + # We support pg_upgrade process only from previous version of this container + # (upgrade to N to N+1 is possible, so e.g. 9.4 to 9.5). + if test "$POSTGRESQL_PREV_VERSION" != "$version"; then + echo >&2 "With this container image you can only upgrade from data directory" + echo >&2 "of version '$POSTGRESQL_PREV_VERSION', not '$version'." + false + fi + + run_pgupgrade +} + +# get_matched_files PATTERN DIR [DIR ...] +# --------------------------------------- +# Print all basenames for files matching PATTERN in DIRs. +get_matched_files () +{ + local pattern=$1 dir + shift + for dir; do + test -d "$dir" || continue + find -L "$dir" -maxdepth 1 -type f -name "$pattern" -printf "%f\n" + done +} + +# process_extending_files DIR [DIR ...] +# ------------------------------------- +# Source all *.sh files in DIRs in alphabetical order, but if the file exists in +# more then one DIR, source only the first occurrence (first found wins). +process_extending_files() +{ + local filename dir + while read filename ; do + for dir in "$@"; do + local file="$dir/$filename" + if test -f "$file"; then + echo "=> sourcing $file ..." + source "$file" + set -e # ensure that users don't mistakenly change this + break + fi + done + done <<<"$(get_matched_files '*.sh' "$@" | sort -u)" +} diff --git a/13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template b/13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template new file mode 100644 index 00000000..d133e511 --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql-replication.conf.template @@ -0,0 +1,7 @@ +# required on master for replication +wal_level = hot_standby # minimal, archive, hot_standby, or logical +max_wal_senders = 6 # max number of walsender processes +wal_keep_size = 6400 # number of segments (400) * size of segments (16MB each); 0 disables + +# required on replicas for replication +hot_standby = on diff --git a/13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template b/13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template new file mode 100644 index 00000000..3c2bc7f3 --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/openshift-custom-postgresql.conf.template @@ -0,0 +1,21 @@ +# +# Custom OpenShift configuration. +# +# NOTE: This file is rewritten every time the container is started! +# Changes to this file will be overwritten. +# + +# Listen on all interfaces. +listen_addresses = '*' + +# Determines the maximum number of concurrent connections to the database server. Default: 100 +max_connections = ${POSTGRESQL_MAX_CONNECTIONS} + +# Allow each connection to use a prepared transaction +max_prepared_transactions = ${POSTGRESQL_MAX_PREPARED_TRANSACTIONS} + +# Sets the amount of memory the database server uses for shared memory buffers. Default: 32MB +shared_buffers = ${POSTGRESQL_SHARED_BUFFERS} + +# Sets the planner's assumption about the effective size of the disk cache that is available to a single query +effective_cache_size = ${POSTGRESQL_EFFECTIVE_CACHE_SIZE} diff --git a/13/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template b/13/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template new file mode 100644 index 00000000..58d8e336 --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/openshift-custom-recovery.conf.template @@ -0,0 +1,8 @@ +# +# Custom OpenShift configuration. +# +# NOTE: This file is rewritten every time the container is started! +# Changes to this file will be overwritten. +# + +primary_conninfo = 'host=${MASTER_FQDN} port=5432 user=${POSTGRESQL_MASTER_USER} password=${POSTGRESQL_MASTER_PASSWORD}' diff --git a/13/root/usr/share/container-scripts/postgresql/scl_enable b/13/root/usr/share/container-scripts/postgresql/scl_enable new file mode 100644 index 00000000..1d967f9b --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/scl_enable @@ -0,0 +1,3 @@ +# This will make scl collection binaries work out of box. +unset BASH_ENV PROMPT_COMMAND ENV +source scl_source enable $ENABLED_COLLECTIONS diff --git a/13/root/usr/share/container-scripts/postgresql/start/set_passwords.sh b/13/root/usr/share/container-scripts/postgresql/start/set_passwords.sh new file mode 100644 index 00000000..60d70e36 --- /dev/null +++ b/13/root/usr/share/container-scripts/postgresql/start/set_passwords.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +_psql () { psql --set ON_ERROR_STOP=1 "$@" ; } + +if [[ ",$postinitdb_actions," = *,simple_db,* ]]; then +_psql --set=username="$POSTGRESQL_USER" \ + --set=password="$POSTGRESQL_PASSWORD" \ +<<< "ALTER USER :\"username\" WITH ENCRYPTED PASSWORD :'password';" +fi + +if [ -v POSTGRESQL_MASTER_USER ]; then +_psql --set=masteruser="$POSTGRESQL_MASTER_USER" \ + --set=masterpass="$POSTGRESQL_MASTER_PASSWORD" \ +<<'EOF' +ALTER USER :"masteruser" WITH REPLICATION; +ALTER USER :"masteruser" WITH ENCRYPTED PASSWORD :'masterpass'; +EOF +fi + +if [ -v POSTGRESQL_ADMIN_PASSWORD ]; then +_psql --set=adminpass="$POSTGRESQL_ADMIN_PASSWORD" \ +<<<"ALTER USER \"postgres\" WITH ENCRYPTED PASSWORD :'adminpass';" +fi diff --git a/13/s2i/bin/assemble b/13/s2i/bin/assemble new file mode 100755 index 00000000..6ed8f7aa --- /dev/null +++ b/13/s2i/bin/assemble @@ -0,0 +1,14 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +shopt -s dotglob +echo "---> Installing application source ..." + + +mv /tmp/src/* ./ + +# Fix source directory permissions +/usr/libexec/fix-permissions --read-only ./ diff --git a/13/s2i/bin/run b/13/s2i/bin/run new file mode 120000 index 00000000..a7f4076b --- /dev/null +++ b/13/s2i/bin/run @@ -0,0 +1 @@ +/usr/bin/run-postgresql \ No newline at end of file diff --git a/13/s2i/bin/usage b/13/s2i/bin/usage new file mode 100755 index 00000000..9f413123 --- /dev/null +++ b/13/s2i/bin/usage @@ -0,0 +1 @@ +groff -t -man -ETascii /help.1 diff --git a/13/test b/13/test new file mode 120000 index 00000000..419df4f9 --- /dev/null +++ b/13/test @@ -0,0 +1 @@ +../test \ No newline at end of file