From 5698b27693817bc46de3c83e5c348782973dda6c Mon Sep 17 00:00:00 2001 From: Igor Yanchenko Date: Tue, 20 Oct 2020 13:56:25 +0300 Subject: [PATCH 1/5] 'Initialization scripts' like in https://hub.docker.com/_/postgres implemented --- docs/configuration.md | 23 +++++++++++ postgres-appliance/scripts/post_init.sh | 53 +++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index 95601355c..1ea2088f5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -82,3 +82,26 @@ using KMS. ### KMS Encryption Key Which key to use to encrypt the passwords in the template. By using KMS encryption we avoid storing the passwords in plain text anywhere. They will only be available to the EC2 instances running Spilo. + +### Initialization scripts + +If you would like to do additional initialization in an image derived from this one, add one or more `*.sql`, `*.sql.gz`, or `*.sh` scripts under `/docker-entrypoint-initdb.d` (creating the directory if necessary). After the entrypoint calls `initdb` to create the default `postgres` user and database, it will run any `*.sql` files, run any executable `*.sh` scripts, and source any non-executable `*.sh` scripts found in that directory to do further initialization before starting the service. + +**Warning**: scripts in `/docker-entrypoint-initdb.d` are only run if you start the container with a data directory that is empty; any pre-existing database will be left untouched on container startup. One common problem is that if one of your `/docker-entrypoint-initdb.d` scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts. + +For example, to add an additional user and database, add the following to `/docker-entrypoint-initdb.d/init-user-db.sh`: + +```bash +#!/bin/bash +set -e + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL + CREATE USER docker; + CREATE DATABASE docker; + GRANT ALL PRIVILEGES ON DATABASE docker TO docker; +EOSQL +``` + +These initialization files will be executed in sorted name order as defined by the current locale, which defaults to `en_US.utf8`. Any `*.sql` files will be executed by `POSTGRES_USER`, which defaults to the `postgres` superuser. It is recommended that any `psql` commands that are run inside of a `*.sh` script be executed as `POSTGRES_USER` by using the `--username "$POSTGRES_USER"` flag. This user will be able to connect without a password due to the presence of `trust` authentication for Unix socket connections made inside the container. + +Additionally, as of [docker-library/postgres#253](https://github.com/docker-library/postgres/pull/253), these initialization scripts are run as the `postgres` user (or as the "semi-arbitrary user" specified with the `--user` flag to `docker run`; see the section titled "Arbitrary `--user` Notes" for more details). Also, as of [docker-library/postgres#440](https://github.com/docker-library/postgres/pull/440), the temporary daemon started for these initialization scripts listens only on the Unix socket, so any `psql` usage should drop the hostname portion (see [docker-library/postgres#474 (comment)](https://github.com/docker-library/postgres/issues/474#issuecomment-416914741) for example). diff --git a/postgres-appliance/scripts/post_init.sh b/postgres-appliance/scripts/post_init.sh index 9aaeef0d3..c0381c96a 100755 --- a/postgres-appliance/scripts/post_init.sh +++ b/postgres-appliance/scripts/post_init.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -Eeo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1 @@ -160,3 +161,55 @@ GRANT EXECUTE ON FUNCTION public.pg_stat_statements_reset($RESET_ARGS) TO admin; cat metric_helpers.sql done < <(psql -d "$2" -tAc 'select pg_catalog.quote_ident(datname) from pg_catalog.pg_database where datallowconn') ) | PGOPTIONS="-c synchronous_commit=local" psql -Xd "$2" + + +#The folloving code is taken from https://github.com/docker-library/postgres/blob/master/docker-entrypoint.sh + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions and permissions +docker_process_init_files() { + echo + local f + for f; do + case "$f" in + *.sh) + # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 + # https://github.com/docker-library/postgres/pull/452 + if [ -x "$f" ]; then + echo "$0: running $f" + "$f" + else + echo "$0: sourcing $f" + . "$f" + fi + ;; + *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;; + *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) echo "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *) echo "$0: ignoring $f" ;; + esac + echo + done +} + +# Execute sql script, passed via stdin (or -f flag of pqsl) +# usage: docker_process_sql [psql-cli-args] +# ie: docker_process_sql --dbname=mydb <<<'INSERT ...' +# ie: docker_process_sql -f my-file.sql +# ie: docker_process_sql /dev/null + +docker_process_init_files /docker-entrypoint-initdb.d/* From e7f9f598675b7a50da22be4cf72d66200bb91e8e Mon Sep 17 00:00:00 2001 From: Igor Yanchenko Date: Tue, 20 Oct 2020 14:20:16 +0300 Subject: [PATCH 2/5] syntax fixes --- postgres-appliance/scripts/post_init.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/postgres-appliance/scripts/post_init.sh b/postgres-appliance/scripts/post_init.sh index c0381c96a..4d4cbea73 100755 --- a/postgres-appliance/scripts/post_init.sh +++ b/postgres-appliance/scripts/post_init.sh @@ -181,7 +181,8 @@ docker_process_init_files() { "$f" else echo "$0: sourcing $f" - . "$f" + # shellcheck disable=SC1090 + source "$f" fi ;; *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;; @@ -199,7 +200,7 @@ docker_process_init_files() { # ie: docker_process_sql -f my-file.sql # ie: docker_process_sql Date: Tue, 20 Oct 2020 15:58:29 +0300 Subject: [PATCH 3/5] make sure /docker-entrypoint-initdb.d/ exists --- postgres-appliance/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/postgres-appliance/Dockerfile b/postgres-appliance/Dockerfile index 4627e6b3a..8a315767b 100644 --- a/postgres-appliance/Dockerfile +++ b/postgres-appliance/Dockerfile @@ -467,6 +467,7 @@ ENV WALE_ENV_DIR=$RW_DIR/etc/wal-e.d/env \ ENV PGDATA=$PGROOT/data \ PGLOG=$PGROOT/pg_log +WORKDIR /docker-entrypoint-initdb.d WORKDIR $PGHOME COPY motd /etc/ From 816c109e013b31df61eda00c18a77429468760ef Mon Sep 17 00:00:00 2001 From: Igor Yanchenko Date: Fri, 8 Jan 2021 11:36:06 +0200 Subject: [PATCH 4/5] review fixes --- postgres-appliance/Dockerfile | 1 - postgres-appliance/scripts/post_init.sh | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/postgres-appliance/Dockerfile b/postgres-appliance/Dockerfile index 8a315767b..4627e6b3a 100644 --- a/postgres-appliance/Dockerfile +++ b/postgres-appliance/Dockerfile @@ -467,7 +467,6 @@ ENV WALE_ENV_DIR=$RW_DIR/etc/wal-e.d/env \ ENV PGDATA=$PGROOT/data \ PGLOG=$PGROOT/pg_log -WORKDIR /docker-entrypoint-initdb.d WORKDIR $PGHOME COPY motd /etc/ diff --git a/postgres-appliance/scripts/post_init.sh b/postgres-appliance/scripts/post_init.sh index 4d4cbea73..220be18ba 100755 --- a/postgres-appliance/scripts/post_init.sh +++ b/postgres-appliance/scripts/post_init.sh @@ -1,9 +1,10 @@ #!/bin/bash -set -Eeo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1 +export POSTGRES_USER="$1" +export POSTGRES_DB="$2" -PGVER=$(psql -d "$2" -XtAc "SELECT pg_catalog.current_setting('server_version_num')::int/10000") +PGVER=$(psql -d "$POSTGRES_DB" -XtAc "SELECT pg_catalog.current_setting('server_version_num')::int/10000") if [ "$PGVER" -ge 12 ]; then RESET_ARGS="oid, oid, bigint"; fi (echo "DO \$\$ @@ -18,11 +19,11 @@ END;\$\$; DO \$\$ BEGIN - PERFORM * FROM pg_catalog.pg_authid WHERE rolname = '$1'; + PERFORM * FROM pg_catalog.pg_authid WHERE rolname = '$POSTGRES_USER'; IF FOUND THEN - ALTER ROLE $1 WITH NOCREATEDB NOLOGIN NOCREATEROLE NOSUPERUSER NOREPLICATION INHERIT; + ALTER ROLE $POSTGRES_USER WITH NOCREATEDB NOLOGIN NOCREATEROLE NOSUPERUSER NOREPLICATION INHERIT; ELSE - CREATE ROLE $1; + CREATE ROLE $POSTGRES_USER; END IF; END;\$\$; @@ -150,7 +151,7 @@ while IFS= read -r db_name; do echo "SELECT public.postgis_extensions_upgrade();" fi fi - sed "s/:HUMAN_ROLE/$1/" create_user_functions.sql + sed "s/:HUMAN_ROLE/$POSTGRES_USER/" create_user_functions.sql echo "CREATE EXTENSION IF NOT EXISTS pg_stat_statements SCHEMA public; CREATE EXTENSION IF NOT EXISTS pg_stat_kcache SCHEMA public; CREATE EXTENSION IF NOT EXISTS set_user SCHEMA public; @@ -159,8 +160,8 @@ GRANT EXECUTE ON FUNCTION public.set_user(text) TO admin; GRANT EXECUTE ON FUNCTION public.pg_stat_statements_reset($RESET_ARGS) TO admin;" if [ "x$ENABLE_PG_MON" = "xtrue" ] && [ "$PGVER" -ge 11 ]; then echo "CREATE EXTENSION IF NOT EXISTS pg_mon SCHEMA public;"; fi cat metric_helpers.sql -done < <(psql -d "$2" -tAc 'select pg_catalog.quote_ident(datname) from pg_catalog.pg_database where datallowconn') -) | PGOPTIONS="-c synchronous_commit=local" psql -Xd "$2" +done < <(psql -d "$POSTGRES_DB" -tAc 'select pg_catalog.quote_ident(datname) from pg_catalog.pg_database where datallowconn') +) | PGOPTIONS="-c synchronous_commit=local" psql -Xd "$POSTGRES_DB" #The folloving code is taken from https://github.com/docker-library/postgres/blob/master/docker-entrypoint.sh @@ -200,10 +201,7 @@ docker_process_init_files() { # ie: docker_process_sql -f my-file.sql # ie: docker_process_sql Date: Mon, 11 Jan 2021 14:18:43 +0200 Subject: [PATCH 5/5] documentation clean up --- docs/configuration.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 1ea2088f5..7731b9c14 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -103,5 +103,3 @@ EOSQL ``` These initialization files will be executed in sorted name order as defined by the current locale, which defaults to `en_US.utf8`. Any `*.sql` files will be executed by `POSTGRES_USER`, which defaults to the `postgres` superuser. It is recommended that any `psql` commands that are run inside of a `*.sh` script be executed as `POSTGRES_USER` by using the `--username "$POSTGRES_USER"` flag. This user will be able to connect without a password due to the presence of `trust` authentication for Unix socket connections made inside the container. - -Additionally, as of [docker-library/postgres#253](https://github.com/docker-library/postgres/pull/253), these initialization scripts are run as the `postgres` user (or as the "semi-arbitrary user" specified with the `--user` flag to `docker run`; see the section titled "Arbitrary `--user` Notes" for more details). Also, as of [docker-library/postgres#440](https://github.com/docker-library/postgres/pull/440), the temporary daemon started for these initialization scripts listens only on the Unix socket, so any `psql` usage should drop the hostname portion (see [docker-library/postgres#474 (comment)](https://github.com/docker-library/postgres/issues/474#issuecomment-416914741) for example).