-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Update postgres #6989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Update postgres #6989
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Changes: - docker-library/postgres@5beb1d4: Update to 9.4.25-1.pgdg90+1 - docker-library/postgres@a0ec4f5: Update to 9.5.20 - docker-library/postgres@6dfdc0e: Update to 11.6 - docker-library/postgres@2addeda: Update to 11.6-1.pgdg90+1 - docker-library/postgres@f13fbe5: Update to 9.6.16-1.pgdg90+1 - docker-library/postgres@f2596e6: Update to 10.11-1.pgdg90+1 - docker-library/postgres@c1e547b: Update to 10.11 - docker-library/postgres@cac7a60: Update to 9.6.16 - docker-library/postgres@1d43a9d: Update to 12.1 - docker-library/postgres@06a831c: Update to 9.5.20-1.pgdg90+1 - docker-library/postgres@138e959: Update to 9.4.25 - docker-library/postgres@4a82eb9: Update to 12.1-1.pgdg100+1 - docker-library/postgres@0c29c35: Merge pull request docker-library/postgres#496 from infosiftr/functionalization - docker-library/postgres@8fada98: Fixes from tianon's review - docker-library/postgres@7c84645: Apply update.sh for new entrypoint - docker-library/postgres@d1cc089: Improve _is_sourced check - docker-library/postgres@6e85168: Resync function interfaces with MySQL, improve comments - docker-library/postgres@2e70e71: Apply function name changes as discussed in docker-library/mysql#471 - docker-library/postgres@49fb876: Namespace functions for less conflict when sourced - docker-library/postgres@48f2ad1: Functionalize the entrypoint to allow outside sourcing for extreme customizing of startup
Diff:diff --git a/_bashbrew-list b/_bashbrew-list
index e2a30c3..da21e29 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -2,27 +2,27 @@ postgres:9
postgres:9-alpine
postgres:9.4
postgres:9.4-alpine
-postgres:9.4.24
-postgres:9.4.24-alpine
+postgres:9.4.25
+postgres:9.4.25-alpine
postgres:9.5
postgres:9.5-alpine
-postgres:9.5.19
-postgres:9.5.19-alpine
+postgres:9.5.20
+postgres:9.5.20-alpine
postgres:9.6
postgres:9.6-alpine
-postgres:9.6.15
-postgres:9.6.15-alpine
+postgres:9.6.16
+postgres:9.6.16-alpine
postgres:10
postgres:10-alpine
-postgres:10.10
-postgres:10.10-alpine
+postgres:10.11
+postgres:10.11-alpine
postgres:11
postgres:11-alpine
-postgres:11.5
-postgres:11.5-alpine
+postgres:11.6
+postgres:11.6-alpine
postgres:12
postgres:12-alpine
-postgres:12.0
-postgres:12.0-alpine
+postgres:12.1
+postgres:12.1-alpine
postgres:alpine
postgres:latest
diff --git a/postgres_10-alpine/Dockerfile b/postgres_10-alpine/Dockerfile
index 659669e..76c5c5f 100644
--- a/postgres_10-alpine/Dockerfile
+++ b/postgres_10-alpine/Dockerfile
@@ -22,8 +22,8 @@ ENV LANG en_US.utf8
RUN mkdir /docker-entrypoint-initdb.d
ENV PG_MAJOR 10
-ENV PG_VERSION 10.10
-ENV PG_SHA256 ad4f9b8575f98ed6091bf9bb2cb16f0e52795a5f66546c1f499ca5c69b21f253
+ENV PG_VERSION 10.11
+ENV PG_SHA256 0d5d14ff6b075655f4421038fbde3a5d7b418c26a249a187a4175600d7aecc09
RUN set -ex \
\
diff --git a/postgres_10-alpine/docker-entrypoint.sh b/postgres_10-alpine/docker-entrypoint.sh
index 6dce8a1..857389d 100755
--- a/postgres_10-alpine/docker-entrypoint.sh
+++ b/postgres_10-alpine/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_WALDIR" ]; then
mkdir -p "$POSTGRES_INITDB_WALDIR"
- chown -R postgres "$POSTGRES_INITDB_WALDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_WALDIR"
fi
- exec su-exec postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_WALDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
+ set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec su-exec postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_10/Dockerfile b/postgres_10/Dockerfile
index 8dfafd0..0e559f3 100644
--- a/postgres_10/Dockerfile
+++ b/postgres_10/Dockerfile
@@ -71,7 +71,7 @@ RUN set -ex; \
apt-key list
ENV PG_MAJOR 10
-ENV PG_VERSION 10.10-1.pgdg90+1
+ENV PG_VERSION 10.11-1.pgdg90+1
RUN set -ex; \
\
diff --git a/postgres_10/docker-entrypoint.sh b/postgres_10/docker-entrypoint.sh
index 93ee4fb..02cb8e5 100755
--- a/postgres_10/docker-entrypoint.sh
+++ b/postgres_10/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_WALDIR" ]; then
mkdir -p "$POSTGRES_INITDB_WALDIR"
- chown -R postgres "$POSTGRES_INITDB_WALDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_WALDIR"
fi
- exec gosu postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_WALDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
+ set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec gosu postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_11-alpine/Dockerfile b/postgres_11-alpine/Dockerfile
index fe9d090..2bf84e9 100644
--- a/postgres_11-alpine/Dockerfile
+++ b/postgres_11-alpine/Dockerfile
@@ -22,8 +22,8 @@ ENV LANG en_US.utf8
RUN mkdir /docker-entrypoint-initdb.d
ENV PG_MAJOR 11
-ENV PG_VERSION 11.5
-ENV PG_SHA256 7fdf23060bfc715144cbf2696cf05b0fa284ad3eb21f0c378591c6bca99ad180
+ENV PG_VERSION 11.6
+ENV PG_SHA256 49924f7ff92965fdb20c86e0696f2dc9f8553e1563124ead7beedf8910c13170
RUN set -ex \
\
diff --git a/postgres_11-alpine/docker-entrypoint.sh b/postgres_11-alpine/docker-entrypoint.sh
index 6dce8a1..857389d 100755
--- a/postgres_11-alpine/docker-entrypoint.sh
+++ b/postgres_11-alpine/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_WALDIR" ]; then
mkdir -p "$POSTGRES_INITDB_WALDIR"
- chown -R postgres "$POSTGRES_INITDB_WALDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_WALDIR"
fi
- exec su-exec postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_WALDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
+ set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec su-exec postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_11/Dockerfile b/postgres_11/Dockerfile
index 4eebd2c..29af439 100644
--- a/postgres_11/Dockerfile
+++ b/postgres_11/Dockerfile
@@ -71,7 +71,7 @@ RUN set -ex; \
apt-key list
ENV PG_MAJOR 11
-ENV PG_VERSION 11.5-3.pgdg90+1
+ENV PG_VERSION 11.6-1.pgdg90+1
RUN set -ex; \
\
diff --git a/postgres_11/docker-entrypoint.sh b/postgres_11/docker-entrypoint.sh
index 93ee4fb..02cb8e5 100755
--- a/postgres_11/docker-entrypoint.sh
+++ b/postgres_11/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_WALDIR" ]; then
mkdir -p "$POSTGRES_INITDB_WALDIR"
- chown -R postgres "$POSTGRES_INITDB_WALDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_WALDIR"
fi
- exec gosu postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_WALDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
+ set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec gosu postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_9-alpine/Dockerfile b/postgres_9-alpine/Dockerfile
index df1dd63..e349927 100644
--- a/postgres_9-alpine/Dockerfile
+++ b/postgres_9-alpine/Dockerfile
@@ -22,8 +22,8 @@ ENV LANG en_US.utf8
RUN mkdir /docker-entrypoint-initdb.d
ENV PG_MAJOR 9.6
-ENV PG_VERSION 9.6.15
-ENV PG_SHA256 3cd9fe9af247167f863030842c1a57f58bdf3e5d50a94997d34a802b6032170a
+ENV PG_VERSION 9.6.16
+ENV PG_SHA256 5c6cba9cc0df70ba2b128c4a87d0babfce7c0e2b888f70a9c8485745f66b22e7
RUN set -ex \
\
diff --git a/postgres_9-alpine/docker-entrypoint.sh b/postgres_9-alpine/docker-entrypoint.sh
index 8f9cfcc..45bb6e1 100755
--- a/postgres_9-alpine/docker-entrypoint.sh
+++ b/postgres_9-alpine/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
mkdir -p "$POSTGRES_INITDB_XLOGDIR"
- chown -R postgres "$POSTGRES_INITDB_XLOGDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_XLOGDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_XLOGDIR"
fi
- exec su-exec postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --xlogdir $POSTGRES_INITDB_XLOGDIR"
+ set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec su-exec postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_9.4-alpine/Dockerfile b/postgres_9.4-alpine/Dockerfile
index e2d5467..97c7a48 100644
--- a/postgres_9.4-alpine/Dockerfile
+++ b/postgres_9.4-alpine/Dockerfile
@@ -22,8 +22,8 @@ ENV LANG en_US.utf8
RUN mkdir /docker-entrypoint-initdb.d
ENV PG_MAJOR 9.4
-ENV PG_VERSION 9.4.24
-ENV PG_SHA256 52253d67dd46a7463a9d7c5e82bf959931fa4c11ec56293150210fa82a0f9429
+ENV PG_VERSION 9.4.25
+ENV PG_SHA256 cb98afaef4748de76c13202c14198e3e4717adde49fd9c90fdc81da877520928
RUN set -ex \
\
diff --git a/postgres_9.4-alpine/docker-entrypoint.sh b/postgres_9.4-alpine/docker-entrypoint.sh
index 8f9cfcc..45bb6e1 100755
--- a/postgres_9.4-alpine/docker-entrypoint.sh
+++ b/postgres_9.4-alpine/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
mkdir -p "$POSTGRES_INITDB_XLOGDIR"
- chown -R postgres "$POSTGRES_INITDB_XLOGDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_XLOGDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_XLOGDIR"
fi
- exec su-exec postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --xlogdir $POSTGRES_INITDB_XLOGDIR"
+ set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec su-exec postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_9.4/Dockerfile b/postgres_9.4/Dockerfile
index 82b1f57..f31ff3e 100644
--- a/postgres_9.4/Dockerfile
+++ b/postgres_9.4/Dockerfile
@@ -71,7 +71,7 @@ RUN set -ex; \
apt-key list
ENV PG_MAJOR 9.4
-ENV PG_VERSION 9.4.24-1.pgdg90+1
+ENV PG_VERSION 9.4.25-1.pgdg90+1
RUN set -ex; \
\
diff --git a/postgres_9.4/docker-entrypoint.sh b/postgres_9.4/docker-entrypoint.sh
index 3f984a1..17b0a68 100755
--- a/postgres_9.4/docker-entrypoint.sh
+++ b/postgres_9.4/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
mkdir -p "$POSTGRES_INITDB_XLOGDIR"
- chown -R postgres "$POSTGRES_INITDB_XLOGDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_XLOGDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_XLOGDIR"
fi
- exec gosu postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --xlogdir $POSTGRES_INITDB_XLOGDIR"
+ set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec gosu postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_9.5-alpine/Dockerfile b/postgres_9.5-alpine/Dockerfile
index e1577b6..7cfaaad 100644
--- a/postgres_9.5-alpine/Dockerfile
+++ b/postgres_9.5-alpine/Dockerfile
@@ -22,8 +22,8 @@ ENV LANG en_US.utf8
RUN mkdir /docker-entrypoint-initdb.d
ENV PG_MAJOR 9.5
-ENV PG_VERSION 9.5.19
-ENV PG_SHA256 960caa26612bca8a3791d1c0bdc5c6d24b3d15841becb617470424edbc5e1bb3
+ENV PG_VERSION 9.5.20
+ENV PG_SHA256 925751b375cf975bebbe79753fbcb5fe85d7a62abe516d4c56861a6b877dde0d
RUN set -ex \
\
diff --git a/postgres_9.5-alpine/docker-entrypoint.sh b/postgres_9.5-alpine/docker-entrypoint.sh
index 8f9cfcc..45bb6e1 100755
--- a/postgres_9.5-alpine/docker-entrypoint.sh
+++ b/postgres_9.5-alpine/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
mkdir -p "$POSTGRES_INITDB_XLOGDIR"
- chown -R postgres "$POSTGRES_INITDB_XLOGDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_XLOGDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_XLOGDIR"
fi
- exec su-exec postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --xlogdir $POSTGRES_INITDB_XLOGDIR"
+ set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec su-exec postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_9.5/Dockerfile b/postgres_9.5/Dockerfile
index 53a2976..8645cb4 100644
--- a/postgres_9.5/Dockerfile
+++ b/postgres_9.5/Dockerfile
@@ -71,7 +71,7 @@ RUN set -ex; \
apt-key list
ENV PG_MAJOR 9.5
-ENV PG_VERSION 9.5.19-1.pgdg90+1
+ENV PG_VERSION 9.5.20-1.pgdg90+1
RUN set -ex; \
\
diff --git a/postgres_9.5/docker-entrypoint.sh b/postgres_9.5/docker-entrypoint.sh
index 3f984a1..17b0a68 100755
--- a/postgres_9.5/docker-entrypoint.sh
+++ b/postgres_9.5/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
mkdir -p "$POSTGRES_INITDB_XLOGDIR"
- chown -R postgres "$POSTGRES_INITDB_XLOGDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_XLOGDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_XLOGDIR"
fi
- exec gosu postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --xlogdir $POSTGRES_INITDB_XLOGDIR"
+ set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec gosu postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_9/Dockerfile b/postgres_9/Dockerfile
index 205b0b1..32bcf4e 100644
--- a/postgres_9/Dockerfile
+++ b/postgres_9/Dockerfile
@@ -71,7 +71,7 @@ RUN set -ex; \
apt-key list
ENV PG_MAJOR 9.6
-ENV PG_VERSION 9.6.15-1.pgdg90+1
+ENV PG_VERSION 9.6.16-1.pgdg90+1
RUN set -ex; \
\
diff --git a/postgres_9/docker-entrypoint.sh b/postgres_9/docker-entrypoint.sh
index 3f984a1..17b0a68 100755
--- a/postgres_9/docker-entrypoint.sh
+++ b/postgres_9/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
mkdir -p "$POSTGRES_INITDB_XLOGDIR"
- chown -R postgres "$POSTGRES_INITDB_XLOGDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_XLOGDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_XLOGDIR"
fi
- exec gosu postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_XLOGDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --xlogdir $POSTGRES_INITDB_XLOGDIR"
+ set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec gosu postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_alpine/Dockerfile b/postgres_alpine/Dockerfile
index ae7bd94..f611082 100644
--- a/postgres_alpine/Dockerfile
+++ b/postgres_alpine/Dockerfile
@@ -22,8 +22,8 @@ ENV LANG en_US.utf8
RUN mkdir /docker-entrypoint-initdb.d
ENV PG_MAJOR 12
-ENV PG_VERSION 12.0
-ENV PG_SHA256 cda2397215f758b793f741c86be05468257b0e6bcb1a6113882ab5d0df0855c6
+ENV PG_VERSION 12.1
+ENV PG_SHA256 a09bf3abbaf6763980d0f8acbb943b7629a8b20073de18d867aecdb7988483ed
RUN set -ex \
\
diff --git a/postgres_alpine/docker-entrypoint.sh b/postgres_alpine/docker-entrypoint.sh
index 6dce8a1..857389d 100755
--- a/postgres_alpine/docker-entrypoint.sh
+++ b/postgres_alpine/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_WALDIR" ]; then
mkdir -p "$POSTGRES_INITDB_WALDIR"
- chown -R postgres "$POSTGRES_INITDB_WALDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_WALDIR"
fi
- exec su-exec postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_WALDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
+ set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec su-exec postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi
diff --git a/postgres_latest/Dockerfile b/postgres_latest/Dockerfile
index 274932e..b1da1db 100644
--- a/postgres_latest/Dockerfile
+++ b/postgres_latest/Dockerfile
@@ -71,7 +71,7 @@ RUN set -ex; \
apt-key list
ENV PG_MAJOR 12
-ENV PG_VERSION 12.0-2.pgdg100+1
+ENV PG_VERSION 12.1-1.pgdg100+1
RUN set -ex; \
\
diff --git a/postgres_latest/docker-entrypoint.sh b/postgres_latest/docker-entrypoint.sh
index 93ee4fb..02cb8e5 100755
--- a/postgres_latest/docker-entrypoint.sh
+++ b/postgres_latest/docker-entrypoint.sh
@@ -24,37 +24,46 @@ file_env() {
unset "$fileVar"
}
-if [ "${1:0:1}" = '-' ]; then
- set -- postgres "$@"
-fi
+# check to see if this file is being run or sourced from another script
+_is_sourced() {
+ # https://unix.stackexchange.com/a/215279
+ [ "${#FUNCNAME[@]}" -ge 2 ] \
+ && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
+ && [ "${FUNCNAME[1]}" = 'source' ]
+}
+
+# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
+docker_create_db_directories() {
+ local user; user="$(id -u)"
-# allow the container to be started with `--user`
-if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
mkdir -p "$PGDATA"
- chown -R postgres "$PGDATA"
chmod 700 "$PGDATA"
- mkdir -p /var/run/postgresql
- chown -R postgres /var/run/postgresql
- chmod 775 /var/run/postgresql
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
+ mkdir -p /var/run/postgresql || :
+ chmod 775 /var/run/postgresql || :
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
if [ "$POSTGRES_INITDB_WALDIR" ]; then
mkdir -p "$POSTGRES_INITDB_WALDIR"
- chown -R postgres "$POSTGRES_INITDB_WALDIR"
+ if [ "$user" = '0' ]; then
+ find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' +
+ fi
chmod 700 "$POSTGRES_INITDB_WALDIR"
fi
- exec gosu postgres "$BASH_SOURCE" "$@"
-fi
-
-if [ "$1" = 'postgres' ]; then
- mkdir -p "$PGDATA"
- chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
- chmod 700 "$PGDATA" 2>/dev/null || :
+ # allow the container to be started with `--user`
+ if [ "$user" = '0' ]; then
+ find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
+ find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
+ fi
+}
- # look specifically for PG_VERSION, as it is expected in the DB dir
- if [ ! -s "$PGDATA/PG_VERSION" ]; then
+# initialize empty PGDATA directory with new database via 'initdb'
+# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
+# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
+# this is also where the database user is created, specified by `POSTGRES_USER` env
+docker_init_database_dir() {
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
@@ -65,26 +74,23 @@ if [ "$1" = 'postgres' ]; then
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
fi
- file_env 'POSTGRES_USER' 'postgres'
- file_env 'POSTGRES_PASSWORD'
-
- file_env 'POSTGRES_INITDB_ARGS'
if [ "$POSTGRES_INITDB_WALDIR" ]; then
- export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
+ set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
fi
- eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
+
+ eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
# unset/cleanup "nss_wrapper" bits
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
fi
+}
+# print large warning if POSTGRES_PASSWORD is empty
+docker_verify_minimum_env() {
# check password first so we can output the warning before postgres
# messes it up
- if [ -n "$POSTGRES_PASSWORD" ]; then
- authMethod=md5
-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
cat >&2 <<-'EOWARN'
@@ -97,7 +103,7 @@ if [ "$1" = 'postgres' ]; then
EOWARN
fi
- else
+ if [ -z "$POSTGRES_PASSWORD" ]; then
# The - option suppresses leading tabs but *not* spaces. :)
cat >&2 <<-'EOWARN'
****************************************************
@@ -113,36 +119,19 @@ if [ "$1" = 'postgres' ]; then
****************************************************
EOWARN
- authMethod=trust
fi
+}
- {
- echo
- echo "host all all all $authMethod"
- } >> "$PGDATA/pg_hba.conf"
-
- # internal start of server in order to allow set-up using psql-client
- # does not listen on external TCP/IP and waits until start finishes
- PGUSER="${PGUSER:-$POSTGRES_USER}" \
- pg_ctl -D "$PGDATA" \
- -o "-c listen_addresses=''" \
- -w start
-
- file_env 'POSTGRES_DB' "$POSTGRES_USER"
-
- export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
- psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+# 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() {
+ # psql here for backwards compatiblilty "${psql[@]}"
+ psql=( docker_process_sql )
- if [ "$POSTGRES_DB" != 'postgres' ]; then
- "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
- CREATE DATABASE :"db" ;
- EOSQL
echo
- fi
- psql+=( --dbname "$POSTGRES_DB" )
-
- echo
- for f in /docker-entrypoint-initdb.d/*; do
+ local f
+ for f; do
case "$f" in
*.sh)
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
@@ -155,22 +144,133 @@ if [ "$1" = 'postgres' ]; then
. "$f"
fi
;;
- *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
- *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
+ *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$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 <my-file.sql
+docker_process_sql() {
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
+ if [ -n "$POSTGRES_DB" ]; then
+ query_runner+=( --dbname "$POSTGRES_DB" )
+ fi
+ "${query_runner[@]}" "$@"
+}
+
+# create initial database
+# uses environment variables for input: POSTGRES_DB
+docker_setup_db() {
+ if [ "$POSTGRES_DB" != 'postgres' ]; then
+ POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
+ CREATE DATABASE :"db" ;
+ EOSQL
+ echo
+ fi
+}
+
+# Loads various settings that are used elsewhere in the script
+# This should be called before any other functions
+docker_setup_env() {
+ file_env 'POSTGRES_PASSWORD'
+
+ file_env 'POSTGRES_USER' 'postgres'
+ file_env 'POSTGRES_DB' "$POSTGRES_USER"
+ file_env 'POSTGRES_INITDB_ARGS'
+
+ declare -g DATABASE_ALREADY_EXISTS
+ # look specifically for PG_VERSION, as it is expected in the DB dir
+ if [ -s "$PGDATA/PG_VERSION" ]; then
+ DATABASE_ALREADY_EXISTS='true'
+ fi
+}
+
+# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
+pg_setup_hba_conf() {
+ local authMethod='md5'
+ if [ -z "$POSTGRES_PASSWORD" ]; then
+ authMethod='trust'
+ fi
+
+ {
+ echo
+ echo "host all all all $authMethod"
+ } >> "$PGDATA/pg_hba.conf"
+}
+
+# start socket-only postgresql server for setting up or running scripts
+# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
+docker_temp_server_start() {
+ if [ "$1" = 'postgres' ]; then
+ shift
+ fi
+ # internal start of server in order to allow setup using psql client
+ # does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
PGUSER="${PGUSER:-$POSTGRES_USER}" \
+ pg_ctl -D "$PGDATA" \
+ -o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
+ -w start
+}
+
+# stop postgresql server after done setting up user and running scripts
+docker_temp_server_stop() {
+ PGUSER="${PGUSER:-postgres}" \
pg_ctl -D "$PGDATA" -m fast -w stop
+}
+
+_main() {
+ # if first arg looks like a flag, assume we want to run postgres server
+ if [ "${1:0:1}" = '-' ]; then
+ set -- postgres "$@"
+ fi
+
+ if [ "$1" = 'postgres' ]; then
+ docker_setup_env
+ # setup data directories and permissions (when run as root)
+ docker_create_db_directories
+ if [ "$(id -u)" = '0' ]; then
+ # then restart script as postgres user
+ exec gosu postgres "$BASH_SOURCE" "$@"
+ fi
+
+ # only run initialization on an empty data directory
+ if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
+ docker_verify_minimum_env
+ docker_init_database_dir
+ pg_setup_hba_conf
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
+ export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
+ docker_temp_server_start "$@"
+
+ docker_setup_db
+ docker_process_init_files /docker-entrypoint-initdb.d/*
+
+ docker_temp_server_stop
unset PGPASSWORD
echo
echo 'PostgreSQL init process complete; ready for start up.'
echo
+ else
+ echo
+ echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
+ echo
+ fi
fi
-fi
-exec "$@"
+ exec "$@"
+}
+
+if ! _is_sourced; then
+ _main "$@"
+fi |
Build test of #6989; 04d8905; $ bashbrew build postgres:12.1
Building bashbrew/cache:fe541dfb4b4a47e5175e7121363d721e8113fd99b2e68f79cd3dfd99d70a0522 (postgres:12.1)
Tagging postgres:12.1
Tagging postgres:12
Tagging postgres:latest
$ test/run.sh postgres:12.1
testing postgres:12.1
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:12.1-alpine
Building bashbrew/cache:ba1a23a6465548e4835b56f3ba35413b7866497c3d02e699ae51be058779c619 (postgres:12.1-alpine)
Tagging postgres:12.1-alpine
Tagging postgres:12-alpine
Tagging postgres:alpine
$ test/run.sh postgres:12.1-alpine
testing postgres:12.1-alpine
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:11.6
Building bashbrew/cache:ebbb9e752c62e4a81314881f512a8dc803537a3d2298c0d7e01caa3e660517be (postgres:11.6)
Tagging postgres:11.6
Tagging postgres:11
$ test/run.sh postgres:11.6
testing postgres:11.6
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:11.6-alpine
Building bashbrew/cache:f54950c5682974496fd0fbafe3b769e9016028cd92493594c9b084f04eef6bd5 (postgres:11.6-alpine)
Tagging postgres:11.6-alpine
Tagging postgres:11-alpine
$ test/run.sh postgres:11.6-alpine
testing postgres:11.6-alpine
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:10.11
Building bashbrew/cache:c050e2e2a320142572dafb3e02b7763f04287f497e4ba4e509fa36f654207d3a (postgres:10.11)
Tagging postgres:10.11
Tagging postgres:10
$ test/run.sh postgres:10.11
testing postgres:10.11
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:10.11-alpine
Building bashbrew/cache:be64bbe9d6da28871e1d3a184b35fbb341367009acb990df986d9301eca05401 (postgres:10.11-alpine)
Tagging postgres:10.11-alpine
Tagging postgres:10-alpine
$ test/run.sh postgres:10.11-alpine
testing postgres:10.11-alpine
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:9.6.16
Building bashbrew/cache:3af830af8e30d69fe38bd4abbb6176c11e936c1379390eaa808f763cd9858c09 (postgres:9.6.16)
Tagging postgres:9.6.16
Tagging postgres:9.6
Tagging postgres:9
$ test/run.sh postgres:9.6.16
testing postgres:9.6.16
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6].....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:9.6.16-alpine
Building bashbrew/cache:dc9bbe4b4c34dcd5d6027c54f9c239901a788492d39e8802ebb871702ab49e26 (postgres:9.6.16-alpine)
Tagging postgres:9.6.16-alpine
Tagging postgres:9.6-alpine
Tagging postgres:9-alpine
$ test/run.sh postgres:9.6.16-alpine
testing postgres:9.6.16-alpine
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6]....passed
$ bashbrew build postgres:9.5.20
Building bashbrew/cache:aad8e08dd77cef37b9e859fbfed913a80fe752b680f610a2d5e47d63b12ee1af (postgres:9.5.20)
Tagging postgres:9.5.20
Tagging postgres:9.5
$ test/run.sh postgres:9.5.20
testing postgres:9.5.20
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6].....passed
'postgres-initdb' [6/6].....passed
$ bashbrew build postgres:9.5.20-alpine
Building bashbrew/cache:a9ccb93fc09b797c7f609248970e48ab67b638146b97f6352645bc20236b230a (postgres:9.5.20-alpine)
Tagging postgres:9.5.20-alpine
Tagging postgres:9.5-alpine
$ test/run.sh postgres:9.5.20-alpine
testing postgres:9.5.20-alpine
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6].....passed
'postgres-initdb' [6/6].....passed
$ bashbrew build postgres:9.4.25
Building bashbrew/cache:c78e9efdb6cabff7696496142c2983885c6ed363c131bca58f8fd2d1403b0c3a (postgres:9.4.25)
Tagging postgres:9.4.25
Tagging postgres:9.4
$ test/run.sh postgres:9.4.25
testing postgres:9.4.25
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6].....passed
'postgres-initdb' [6/6].....passed
$ bashbrew build postgres:9.4.25-alpine
Building bashbrew/cache:da941e0a1b2959000beae66464fe0b12d0e4dd2f3e81844f32eb776c4d4bdbec (postgres:9.4.25-alpine)
Tagging postgres:9.4.25-alpine
Tagging postgres:9.4-alpine
$ test/run.sh postgres:9.4.25-alpine
testing postgres:9.4.25-alpine
'utc' [1/6]...passed
'cve-2014--shellshock' [2/6]...passed
'no-hard-coded-passwords' [3/6]...passed
'override-cmd' [4/6]...passed
'postgres-basics' [5/6]....passed
'postgres-initdb' [6/6].....passed
|
Is there any reason for the size increase from 12.0-alpine 72.8 MB to 12.1-alpine 146.2 MB? |
That's likely due to the JIT support.
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Changes: