kopia lustrzana https://github.com/kartoza/docker-postgis
433 wiersze
11 KiB
Bash
433 wiersze
11 KiB
Bash
#!/usr/bin/env bash
|
|
POSTGRES_MAJOR_VERSION=$(cat /tmp/pg_version.txt)
|
|
POSTGIS_MAJOR=$(cat /tmp/pg_major_version.txt)
|
|
POSTGIS_MINOR_RELEASE=$(cat /tmp/pg_minor_version.txt)
|
|
DEFAULT_DATADIR="/var/lib/postgresql/${POSTGRES_MAJOR_VERSION}/main"
|
|
# Commented for documentation. You can specify the location of
|
|
# pg_wal directory/volume using the following environment variable:
|
|
# POSTGRES_INITDB_WALDIR (default value is unset)
|
|
ROOT_CONF="/etc/postgresql/${POSTGRES_MAJOR_VERSION}/main"
|
|
PG_ENV="$ROOT_CONF/environment"
|
|
CONF="$ROOT_CONF/postgresql.conf"
|
|
WAL_ARCHIVE="/opt/archivedir"
|
|
RECOVERY_CONF="$ROOT_CONF/recovery.conf"
|
|
POSTGRES="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/postgres"
|
|
INITDB="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/initdb"
|
|
SQLDIR="/usr/share/postgresql/${POSTGRES_MAJOR_VERSION}/contrib/postgis-${POSTGIS_MAJOR}.${POSTGIS_MINOR_RELEASE}/"
|
|
SETVARS="POSTGIS_ENABLE_OUTDB_RASTERS=1 POSTGIS_GDAL_ENABLED_DRIVERS=ENABLE_ALL"
|
|
LOCALONLY="-c listen_addresses='127.0.0.1'"
|
|
PG_BASEBACKUP="/usr/bin/pg_basebackup"
|
|
NODE_PROMOTION="/usr/lib/postgresql/${POSTGRES_MAJOR_VERSION}/bin/pg_ctl"
|
|
PGSTAT_TMP="/var/run/postgresql/"
|
|
PG_PID="/var/run/postgresql/${POSTGRES_MAJOR_VERSION}-main.pid"
|
|
|
|
|
|
|
|
# Read data from secrets into env variables.
|
|
|
|
# usage: file_env VAR [DEFAULT]
|
|
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
|
|
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
|
|
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
|
|
function file_env {
|
|
local var="$1"
|
|
local fileVar="${var}_FILE"
|
|
local def="${2:-}"
|
|
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
|
|
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
|
|
exit 1
|
|
fi
|
|
local val="$def"
|
|
if [ "${!var:-}" ]; then
|
|
val="${!var}"
|
|
elif [ "${!fileVar:-}" ]; then
|
|
val="$(< "${!fileVar}")"
|
|
fi
|
|
export "$var"="$val"
|
|
unset "$fileVar"
|
|
}
|
|
|
|
function boolean() {
|
|
case $1 in
|
|
[Tt][Rr][Uu][Ee] | [Yy][Ee][Ss])
|
|
echo 'TRUE'
|
|
;;
|
|
*)
|
|
echo 'FALSE'
|
|
;;
|
|
esac
|
|
}
|
|
|
|
file_env 'POSTGRES_PASS'
|
|
file_env 'POSTGRES_USER'
|
|
file_env 'POSTGRES_DBNAME'
|
|
|
|
function create_dir() {
|
|
DATA_PATH=$1
|
|
|
|
if [[ ! -d ${DATA_PATH} ]];
|
|
then
|
|
echo "Creating" ${DATA_PATH} "directory"
|
|
mkdir -p ${DATA_PATH}
|
|
fi
|
|
}
|
|
|
|
function generate_random_string() {
|
|
STRING_LENGTH=$1
|
|
random_pass_string=$(openssl rand -base64 ${STRING_LENGTH})
|
|
if [[ ! -f /scripts/.pass_${STRING_LENGTH}.txt ]]; then
|
|
echo ${random_pass_string} > /scripts/.pass_${STRING_LENGTH}.txt
|
|
fi
|
|
export RAND=$(cat /scripts/.pass_${STRING_LENGTH}.txt)
|
|
}
|
|
|
|
# Make sure we have a user set up
|
|
if [ -z "${POSTGRES_USER}" ]; then
|
|
POSTGRES_USER=docker
|
|
fi
|
|
|
|
|
|
if [ -z "${POSTGRES_PASS}" ]; then
|
|
generate_random_string 20
|
|
POSTGRES_PASS=${RAND}
|
|
fi
|
|
|
|
|
|
if [ -z "${POSTGRES_DBNAME}" ]; then
|
|
POSTGRES_DBNAME=gis
|
|
fi
|
|
# If datadir is not defined, then use this
|
|
if [ -z "${DATADIR}" ]; then
|
|
DATADIR=${DEFAULT_DATADIR}
|
|
fi
|
|
|
|
# RECREATE_DATADIR flag default value
|
|
# Always assume that we don't want to recreate datadir if not explicitly defined
|
|
# For issue: https://github.com/kartoza/docker-postgis/issues/226
|
|
if [ -z "${RECREATE_DATADIR}" ]; then
|
|
RECREATE_DATADIR=FALSE
|
|
else
|
|
RECREATE_DATADIR=$(boolean ${RECREATE_DATADIR})
|
|
fi
|
|
if [ -z "${SSL_DIR}" ]; then
|
|
SSL_DIR="/ssl_certificates"
|
|
fi
|
|
|
|
# SSL mode
|
|
if [ -z "${PGSSLMODE}" ]; then
|
|
PGSSLMODE=require
|
|
fi
|
|
# Enable hstore and topology by default
|
|
if [ -z "${HSTORE}" ]; then
|
|
HSTORE=true
|
|
fi
|
|
if [ -z "${TOPOLOGY}" ]; then
|
|
TOPOLOGY=true
|
|
fi
|
|
# Replication settings
|
|
|
|
if [ -z "${REPLICATION}" ]; then
|
|
REPLICATION=false
|
|
fi
|
|
if [ -z "${REPLICATE_PORT}" ]; then
|
|
REPLICATE_PORT=5432
|
|
fi
|
|
if [ -z "${DESTROY_DATABASE_ON_RESTART}" ]; then
|
|
DESTROY_DATABASE_ON_RESTART=true
|
|
fi
|
|
if [ -z "${PG_MAX_WAL_SENDERS}" ]; then
|
|
PG_MAX_WAL_SENDERS=10
|
|
fi
|
|
if [ -z "${PG_WAL_KEEP_SIZE}" ]; then
|
|
PG_WAL_KEEP_SIZE=20
|
|
fi
|
|
|
|
|
|
#Logical replication settings
|
|
if [ -z "${MAX_LOGICAL_REPLICATION_WORKERS}" ]; then
|
|
MAX_LOGICAL_REPLICATION_WORKERS=4
|
|
fi
|
|
|
|
if [ -z "${MAX_SYNC_WORKERS_PER_SUBSCRIPTION}" ]; then
|
|
MAX_SYNC_WORKERS_PER_SUBSCRIPTION=2
|
|
fi
|
|
|
|
if [ -z "${IP_LIST}" ]; then
|
|
IP_LIST='*'
|
|
fi
|
|
|
|
if [ -z "${MAINTAINANCE_WORKERS}" ]; then
|
|
MAINTAINANCE_WORKERS=2
|
|
fi
|
|
|
|
if [ -z "${ARCHIVE_MODE}" ]; then
|
|
# https://www.postgresql.org/docs/12/runtime-config-wal.html
|
|
ARCHIVE_MODE=off
|
|
fi
|
|
|
|
if [ -z "${ARCHIVE_COMMAND}" ]; then
|
|
# https://www.postgresql.org/docs/12/continuous-archiving.html#BACKUP-ARCHIVING-WAL
|
|
ARCHIVE_COMMAND="test ! -f ${WAL_ARCHIVE}/%f && cp %p ${WAL_ARCHIVE}/%f"
|
|
fi
|
|
|
|
if [ -z "${RESTORE_COMMAND}" ]; then
|
|
# https://www.postgresql.org/docs/12/runtime-config-wal.html
|
|
RESTORE_COMMAND="cp ${WAL_ARCHIVE}/%f \"%p\""
|
|
fi
|
|
|
|
if [ -z "${ARCHIVE_CLEANUP_COMMAND}" ]; then
|
|
# https://www.postgresql.org/docs/12/runtime-config-wal.html
|
|
ARCHIVE_CLEANUP_COMMAND="pg_archivecleanup ${WAL_ARCHIVE} %r"
|
|
fi
|
|
|
|
if [ -z "${WAL_LEVEL}" ]; then
|
|
# https://www.postgresql.org/docs/12/runtime-config-wal.html
|
|
WAL_LEVEL=replica
|
|
fi
|
|
|
|
if [ -z "${WAL_SIZE}" ]; then
|
|
WAL_SIZE=4GB
|
|
fi
|
|
|
|
if [ -z "${MIN_WAL_SIZE}" ]; then
|
|
MIN_WAL_SIZE=1024MB
|
|
fi
|
|
|
|
if [ -z "${WAL_SEGSIZE}" ]; then
|
|
WAL_SEGSIZE=32
|
|
fi
|
|
|
|
if [ -z "${SHARED_BUFFERS}" ]; then
|
|
SHARED_BUFFERS=256MB
|
|
fi
|
|
|
|
if [ -z "${WORK_MEM}" ]; then
|
|
WORK_MEM=16MB
|
|
fi
|
|
|
|
if [ -z "${WAL_BUFFERS}" ]; then
|
|
WAL_BUFFERS=1MB
|
|
fi
|
|
|
|
if [ -z "${CHECK_POINT_TIMEOUT}" ]; then
|
|
CHECK_POINT_TIMEOUT=30min
|
|
fi
|
|
|
|
if [ -z "${MAX_WORKERS}" ]; then
|
|
MAX_WORKERS=4
|
|
fi
|
|
|
|
if [ -z "${MAINTAINANCE_WORK_MEM}" ]; then
|
|
MAINTAINANCE_WORK_MEM=128MB
|
|
fi
|
|
|
|
|
|
if [ -z "${SSL_CERT_FILE}" ]; then
|
|
SSL_CERT_FILE='/etc/ssl/certs/ssl-cert-snakeoil.pem'
|
|
fi
|
|
|
|
if [ -z "${SSL_KEY_FILE}" ]; then
|
|
SSL_KEY_FILE='/etc/ssl/private/ssl-cert-snakeoil.key'
|
|
fi
|
|
|
|
if [ -z "${POSTGRES_MULTIPLE_EXTENSIONS}" ]; then
|
|
if [[ $(dpkg -l | grep "timescaledb") > /dev/null ]];then
|
|
POSTGRES_MULTIPLE_EXTENSIONS='postgis,hstore,postgis_topology,postgis_raster,pgrouting,timescaledb'
|
|
else
|
|
POSTGRES_MULTIPLE_EXTENSIONS='postgis,hstore,postgis_topology,postgis_raster,pgrouting'
|
|
fi
|
|
fi
|
|
|
|
|
|
if [ -z "${ALLOW_IP_RANGE}" ]; then
|
|
ALLOW_IP_RANGE='0.0.0.0/0'
|
|
fi
|
|
if [ -z "${DEFAULT_ENCODING}" ]; then
|
|
DEFAULT_ENCODING="UTF8"
|
|
fi
|
|
|
|
if [ -z "${PGCLIENTENCODING}" ]; then
|
|
PGCLIENTENCODING="UTF8"
|
|
fi
|
|
|
|
if [ -z "${DEFAULT_COLLATION}" ]; then
|
|
DEFAULT_COLLATION="en_US.UTF-8"
|
|
fi
|
|
if [ -z "${DEFAULT_CTYPE}" ]; then
|
|
DEFAULT_CTYPE="en_US.UTF-8"
|
|
fi
|
|
|
|
if [ -z "${TARGET_TIMELINE}" ]; then
|
|
TARGET_TIMELINE='latest'
|
|
fi
|
|
|
|
if [ -z "${TARGET_ACTION}" ]; then
|
|
TARGET_ACTION='promote'
|
|
fi
|
|
|
|
if [ -z "${REPLICATION_USER}" ]; then
|
|
REPLICATION_USER=replicator
|
|
fi
|
|
|
|
if [ -z "${REPLICATION_PASS}" ]; then
|
|
generate_random_string 22
|
|
REPLICATION_PASS=${RAND}
|
|
fi
|
|
|
|
if [ -z "$IGNORE_INIT_HOOK_LOCKFILE" ]; then
|
|
IGNORE_INIT_HOOK_LOCKFILE=false
|
|
fi
|
|
|
|
if [ -z "$EXTRA_CONF" ]; then
|
|
EXTRA_CONF=""
|
|
fi
|
|
|
|
if [ -z "${SHARED_PRELOAD_LIBRARIES}" ]; then
|
|
if [[ $(dpkg -l | grep "timescaledb") > /dev/null ]];then
|
|
SHARED_PRELOAD_LIBRARIES='pg_cron,timescaledb'
|
|
else
|
|
SHARED_PRELOAD_LIBRARIES='pg_cron'
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$PASSWORD_AUTHENTICATION" ]; then
|
|
PASSWORD_AUTHENTICATION="scram-sha-256"
|
|
fi
|
|
|
|
if [ -z "${ALL_DATABASES}" ]; then
|
|
ALL_DATABASES=FALSE
|
|
fi
|
|
|
|
if [ -z "${FORCE_SSL}" ]; then
|
|
FORCE_SSL=FALSE
|
|
fi
|
|
|
|
if [ -z "${ACCEPT_TIMESCALE_TUNING}" ]; then
|
|
ACCEPT_TIMESCALE_TUNING=FALSE
|
|
fi
|
|
|
|
if [ -z "${TIMESCALE_TUNING_PARAMS}" ]; then
|
|
TIMESCALE_TUNING_PARAMS=
|
|
fi
|
|
|
|
# Compatibility with official postgres variable
|
|
# Official postgres variable gets priority
|
|
if [ -n "${POSTGRES_PASSWORD}" ]; then
|
|
POSTGRES_PASS=${POSTGRES_PASSWORD}
|
|
fi
|
|
if [ -n "${PGDATA}" ]; then
|
|
DATADIR=${PGDATA}
|
|
fi
|
|
|
|
if [ -n "${POSTGRES_DB}" ]; then
|
|
POSTGRES_DBNAME=${POSTGRES_DB}
|
|
fi
|
|
|
|
if [ -n "${POSTGRES_INITDB_ARGS}" ]; then
|
|
INITDB_EXTRA_ARGS=${POSTGRES_INITDB_ARGS}
|
|
fi
|
|
|
|
list=(`echo ${POSTGRES_DBNAME} | tr ',' ' '`)
|
|
arr=(${list})
|
|
SINGLE_DB=${arr[0]}
|
|
|
|
if [ -z "${TIMEZONE}" ]; then
|
|
TIMEZONE='Etc/UTC'
|
|
fi
|
|
|
|
# usable function definitions
|
|
function kill_postgres {
|
|
PID=`cat ${PG_PID}`
|
|
kill -TERM ${PID}
|
|
|
|
# Wait for background postgres main process to exit
|
|
# wait until PID file gets deleted
|
|
while ls -A ${PG_PID} 2> /dev/null; do
|
|
sleep 1
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
function restart_postgres {
|
|
|
|
kill_postgres
|
|
|
|
# Brought postgres back up again
|
|
source /scripts/env-data.sh
|
|
su - postgres -c "$SETVARS $POSTGRES -D $DATADIR -c config_file=$CONF &"
|
|
|
|
# wait for postgres to come up
|
|
until su - postgres -c "pg_isready"; do
|
|
sleep 1
|
|
done
|
|
echo "postgres ready"
|
|
return 0
|
|
}
|
|
|
|
|
|
|
|
# Running extended script or sql if provided.
|
|
# Useful for people who extends the image.
|
|
|
|
function entry_point_script {
|
|
SETUP_LOCKFILE="/docker-entrypoint-initdb.d/.entry_point.lock"
|
|
# If lockfile doesn't exists, proceed.
|
|
if [[ ! -f "${SETUP_LOCKFILE}" ]] || [ "${IGNORE_INIT_HOOK_LOCKFILE}" == true ]; then
|
|
if find "/docker-entrypoint-initdb.d" -mindepth 1 -print -quit 2>/dev/null | grep -q .; then
|
|
for f in /docker-entrypoint-initdb.d/*; do
|
|
export PGPASSWORD=${POSTGRES_PASS}
|
|
case "$f" in
|
|
*.sql) echo "$0: running $f";
|
|
if [[ "${ALL_DATABASES}" =~ [Ff][Aa][Ll][Ss][Ee] ]]; then
|
|
psql ${SINGLE_DB} -U ${POSTGRES_USER} -p 5432 -h localhost -f ${f} || true
|
|
else
|
|
for db in $(echo ${POSTGRES_DBNAME} | tr ',' ' '); do
|
|
psql ${db} -U ${POSTGRES_USER} -p 5432 -h localhost -f ${f} || true
|
|
done
|
|
fi;;
|
|
*.sql.gz) echo "$0: running $f";
|
|
if [[ "${ALL_DATABASES}" =~ [Ff][Aa][Ll][Ss][Ee] ]]; then
|
|
gunzip < "$f" | psql ${SINGLE_DB} -U ${POSTGRES_USER} -p 5432 -h localhost || true
|
|
else
|
|
for db in $(echo ${POSTGRES_DBNAME} | tr ',' ' '); do
|
|
gunzip < "$f" | psql ${db} -U ${POSTGRES_USER} -p 5432 -h localhost || true
|
|
done
|
|
fi;;
|
|
*.sh) echo "$0: running $f"; . $f || true;;
|
|
*) echo "$0: ignoring $f" ;;
|
|
esac
|
|
echo
|
|
done
|
|
# Put lock file to make sure entry point scripts were run
|
|
touch ${SETUP_LOCKFILE}
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
function configure_replication_permissions {
|
|
|
|
echo "Setup data permissions"
|
|
echo "----------------------"
|
|
chown -R postgres:postgres $(getent passwd postgres | cut -d: -f6)
|
|
su - postgres -c "echo \"${REPLICATE_FROM}:${REPLICATE_PORT}:*:${REPLICATION_USER}:${REPLICATION_PASS}\" > ~/.pgpass"
|
|
su - postgres -c "chmod 0600 ~/.pgpass"
|
|
}
|
|
|
|
function streaming_replication {
|
|
until su - postgres -c "${PG_BASEBACKUP} -X stream -h ${REPLICATE_FROM} -p ${REPLICATE_PORT} -D ${DATADIR} -U ${REPLICATION_USER} -R -vP -w --label=gis_pg_custer"
|
|
do
|
|
echo "Waiting for master to connect..."
|
|
sleep 1s
|
|
if [[ "$(ls -A ${DATADIR})" ]]; then
|
|
echo "Need empty folder. Cleaning directory..."
|
|
rm -rf ${DATADIR}/*
|
|
fi
|
|
done
|
|
|
|
}
|
|
|
|
|