4.0.3-debian-9-r0 release
This commit is contained in:
parent
6ea7620e54
commit
b2651a2956
|
|
@ -0,0 +1,30 @@
|
|||
FROM bitnami/minideb-extras-base:stretch-r346
|
||||
LABEL maintainer "Bitnami <containers@bitnami.com>"
|
||||
|
||||
ENV BITNAMI_PKG_CHMOD="-R g+rwX" \
|
||||
HOME="/" \
|
||||
OS_ARCH="amd64" \
|
||||
OS_FLAVOUR="debian-9" \
|
||||
OS_NAME="linux"
|
||||
|
||||
# Install required system packages and dependencies
|
||||
RUN install_packages libbsd0 libc6 libedit2 libgcc1 libicu57 liblzma5 libncurses5 libnss-wrapper libssl1.1 libstdc++6 libtinfo5 libuuid1 libxml2 libxslt1.1 locales zlib1g
|
||||
RUN . ./libcomponent.sh && component_unpack "postgresql-repmgr" "4.0.3-0" --checksum 4b97f19154174f5b09cb9358b2266a265fb1c96aba192828884d91c8645c5bfb
|
||||
RUN echo 'en_GB.UTF-8 UTF-8' >> /etc/locale.gen && locale-gen
|
||||
RUN echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen && locale-gen
|
||||
|
||||
COPY rootfs /
|
||||
RUN /postunpack.sh
|
||||
ENV BITNAMI_APP_NAME="postgresql-repmgr" \
|
||||
BITNAMI_IMAGE_VERSION="4.0.3-debian-9-r0" \
|
||||
LANG="en_US.UTF-8" \
|
||||
LANGUAGE="en_US:en" \
|
||||
NAMI_PREFIX="/.nami" \
|
||||
NSS_WRAPPER_LIB="/usr/lib/libnss_wrapper.so" \
|
||||
PATH="/opt/bitnami/postgresql-repmgr/bin:/opt/bitnami/repmgr/bin:/opt/bitnami/postgresql/bin:$PATH"
|
||||
|
||||
EXPOSE 5432
|
||||
|
||||
USER 1001
|
||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||
CMD [ "/run.sh" ]
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
version: '2'
|
||||
services:
|
||||
pg-0:
|
||||
image: bitnami/postgresql-repmgr:4
|
||||
ports:
|
||||
- 5432
|
||||
volumes:
|
||||
- pg_0_data:/bitnami/postgresql
|
||||
environment:
|
||||
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
|
||||
- POSTGRESQL_USERNAME=customuser
|
||||
- POSTGRESQL_PASSWORD=custompassword
|
||||
- POSTGRESQL_DATABASE=customdatabase
|
||||
- REPMGR_PASSWORD=repmgrpassword
|
||||
- REPMGR_PRIMARY_HOST=pg-0
|
||||
- REPMGR_PARTNER_NODES=pg-0,pg-1
|
||||
- REPMGR_NODE_NAME=pg-0
|
||||
- REPMGR_NODE_NETWORK_NAME=pg-0
|
||||
pg-1:
|
||||
image: bitnami/postgresql-repmgr:4
|
||||
ports:
|
||||
- 5432
|
||||
volumes:
|
||||
- pg_1_data:/bitnami/postgresql
|
||||
environment:
|
||||
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
|
||||
- POSTGRESQL_USERNAME=customuser
|
||||
- POSTGRESQL_PASSWORD=custompassword
|
||||
- POSTGRESQL_DATABASE=customdatabase
|
||||
- REPMGR_PASSWORD=repmgrpassword
|
||||
- REPMGR_PRIMARY_HOST=pg-0
|
||||
- REPMGR_PARTNER_NODES=pg-0,pg-1
|
||||
- REPMGR_NODE_NAME=pg-1
|
||||
- REPMGR_NODE_NETWORK_NAME=pg-1
|
||||
volumes:
|
||||
pg_0_data:
|
||||
driver: local
|
||||
pg_1_data:
|
||||
driver: local
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
#set -o xtrace
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load libraries
|
||||
. /liblog.sh
|
||||
. /libbitnami.sh
|
||||
. /libpostgresql.sh
|
||||
. /librepmgr.sh
|
||||
|
||||
# Load PostgreSQL & repmgr environment variables
|
||||
eval "$(repmgr_env)"
|
||||
eval "$(postgresql_env)"
|
||||
export MODULE=postgresql-repmgr
|
||||
|
||||
print_welcome_page
|
||||
|
||||
# Enable the nss_wrapper settings
|
||||
postgresql_enable_nss_wrapper
|
||||
|
||||
if [[ "$*" = *"/run.sh"* ]]; then
|
||||
info "** Starting PostgreSQL with Replication Manager setup **"
|
||||
/setup.sh
|
||||
touch "$POSTGRESQL_TMP_DIR"/.initialized
|
||||
info "** PostgreSQL with Replication Manager setup finished! **"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
exec "$@"
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
|
||||
header="[REPMGR EVENT::$2]"
|
||||
export header
|
||||
echo "$header Node id: $1; Event type: $2; Success [1|0]: $3; Time: $4; Details: $5"
|
||||
|
||||
if [[ $3 -ne 1 ]];then
|
||||
echo "$header The event failed! No need to do anything."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $1 -ne $(repmgr_get_node_id) ]]; then
|
||||
echo "$header The event did not happen on me! No need to do anything."
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC2154
|
||||
|
||||
echo "$header Locking primary..."
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
|
||||
readonly query="SELECT upstream_node_id FROM repmgr.nodes WHERE node_id=$(repmgr_get_node_id)"
|
||||
readonly new_upstream_node_id="$(echo "$query" | BITNAMI_DEBUG=true postgresql_execute "$REPMGR_DATABASE" "$POSTGRESQL_REPLICATION_USER" "$POSTGRESQL_REPLICATION_PASSWORD" "" "" "-tA")"
|
||||
if [[ -n "$new_upstream_node_id" ]]; then
|
||||
# shellcheck disable=SC2154
|
||||
echo "$header Locking standby (new_upstream_node_id=$new_upstream_node_id)..."
|
||||
echo "$new_upstream_node_id" > "$REPMGR_STANDBY_ROLE_LOCK_FILE_NAME"
|
||||
fi
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC2154
|
||||
|
||||
echo "$header Unlocking primary..."
|
||||
rm -f "$REPMGR_PRIMARY_ROLE_LOCK_FILE_NAME"
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC2154
|
||||
|
||||
echo "$header Unlocking standby..."
|
||||
rm -f "$REPMGR_STANDBY_ROLE_LOCK_FILE_NAME"
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/anotate_event_processing.sh"
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/lock_primary.sh"
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/unlock_standby.sh"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/anotate_event_processing.sh"
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/lock_standby.sh"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/anotate_event_processing.sh"
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/unlock_primary.sh"
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/anotate_event_processing.sh"
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/lock_primary.sh"
|
||||
. "$REPMGR_EVENTS_DIR/execs/includes/unlock_standby.sh"
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load libraries
|
||||
. /librepmgr.sh
|
||||
. /libpostgresql.sh
|
||||
|
||||
eval "$(repmgr_env)"
|
||||
eval "$(postgresql_env)"
|
||||
|
||||
echo "[REPMGR EVENT] Node id: $1; Event type: $2; Success [1|0]: $3; Time: $4; Details: $5"
|
||||
event_script="$REPMGR_EVENTS_DIR/execs/$2.sh"
|
||||
echo "Looking for the script: $event_script"
|
||||
if [[ -f "$event_script" ]]; then
|
||||
echo "[REPMGR EVENT] will execute script '$event_script' for the event"
|
||||
. "$event_script"
|
||||
else
|
||||
echo "[REPMGR EVENT] no script '$event_script' found. Skipping..."
|
||||
fi
|
||||
|
|
@ -0,0 +1,788 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Bitnami PostgreSQL library
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load Generic Libraries
|
||||
. /libfile.sh
|
||||
. /liblog.sh
|
||||
. /libservice.sh
|
||||
. /libvalidations.sh
|
||||
|
||||
|
||||
########################
|
||||
# Overwrite info, debug, warn and error functions (liblog.sh)
|
||||
########################
|
||||
postgresql_info() {
|
||||
MODULE=postgresql info "${*}"
|
||||
}
|
||||
postgresql_debug() {
|
||||
MODULE=postgresql debug "${*}"
|
||||
}
|
||||
postgresql_warn() {
|
||||
MODULE=postgresql warn "${*}"
|
||||
}
|
||||
postgresql_error() {
|
||||
MODULE=postgresql error "${*}"
|
||||
}
|
||||
|
||||
########################
|
||||
# Configure libnss_wrapper so PostgreSQL commands work with a random user.
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_enable_nss_wrapper() {
|
||||
if ! getent passwd "$(id -u)" &> /dev/null && [ -e "$NSS_WRAPPER_LIB" ]; then
|
||||
postgresql_debug "Configuring libnss_wrapper..."
|
||||
export LD_PRELOAD="$NSS_WRAPPER_LIB"
|
||||
# shellcheck disable=SC2155
|
||||
export NSS_WRAPPER_PASSWD="$(mktemp)"
|
||||
# shellcheck disable=SC2155
|
||||
export NSS_WRAPPER_GROUP="$(mktemp)"
|
||||
echo "postgres:x:$(id -u):$(id -g):PostgreSQL:$POSTGRESQL_DATA_DIR:/bin/false" > "$NSS_WRAPPER_PASSWD"
|
||||
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Load global variables used on PostgreSQL configuration.
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Series of exports to be used as 'eval' arguments
|
||||
#########################
|
||||
postgresql_env() {
|
||||
declare_env_alias() {
|
||||
local -r alias="${1:?missing environment variable alias}"
|
||||
local -r original="${2:?missing original environment variable}"
|
||||
|
||||
if printenv "${original}" > /dev/null; then
|
||||
cat << EOF
|
||||
export $alias="${!original}"
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
# Alias created for official PostgreSQL image compatibility
|
||||
[[ -z "${POSTGRESQL_DATABASE:-}" ]] && declare_env_alias POSTGRESQL_DATABASE POSTGRES_DB
|
||||
[[ -z "${POSTGRESQL_USERNAME:-}" ]] && declare_env_alias POSTGRESQL_USERNAME POSTGRES_USER
|
||||
[[ -z "${POSTGRESQL_DATA_DIR:-}" ]] && declare_env_alias POSTGRESQL_DATA_DIR PGDATA
|
||||
|
||||
local -r suffixes=(
|
||||
"PASSWORD" "POSTGRES_PASSWORD" "INITDB_WAL_DIR" "INITDB_ARGS" "CLUSTER_APP_NAME"
|
||||
"MASTER_HOST" "MASTER_PORT_NUMBER" "NUM_SYNCHRONOUS_REPLICAS"
|
||||
"PORT_NUMBER" "REPLICATION_MODE" "REPLICATION_PASSWORD" "REPLICATION_USER" "FSYNC"
|
||||
"SYNCHRONOUS_COMMIT_MODE" "PASSWORD_FILE" "POSTGRES_PASSWORD_FILE"
|
||||
"REPLICATION_PASSWORD_FILE" "INIT_MAX_TIMEOUT"
|
||||
)
|
||||
for s in "${suffixes[@]}"; do
|
||||
declare_env_alias "POSTGRESQL_${s}" "POSTGRES_${s}"
|
||||
done
|
||||
|
||||
# Ensure the image is compatible with Helm chart 3.x.x series
|
||||
local -r postgresql_data="${POSTGRESQL_DATA_DIR:-${PGDATA:-}}"
|
||||
if [[ -n "${postgresql_data:-}" ]]; then
|
||||
if [[ -d "${postgresql_data}/data" ]] || [[ "${postgresql_data}" = "/bitnami/postgresql" ]]; then
|
||||
postgresql_warn "Data directory is set with a legacy value, adapting POSTGRESQL_DATA_DIR..."
|
||||
postgresql_warn "POSTGRESQL_DATA_DIR set to \"${postgresql_data}/data\"!!"
|
||||
cat << EOF
|
||||
export POSTGRESQL_DATA_DIR="${postgresql_data}/data"
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
cat <<"EOF"
|
||||
# Paths
|
||||
export POSTGRESQL_VOLUME_DIR="${POSTGRESQL_VOLUME_DIR:-/bitnami/postgresql}"
|
||||
export POSTGRESQL_DATA_DIR="${POSTGRESQL_DATA_DIR:-$POSTGRESQL_VOLUME_DIR/data}"
|
||||
export POSTGRESQL_BASE_DIR="/opt/bitnami/postgresql"
|
||||
export POSTGRESQL_CONF_DIR="$POSTGRESQL_BASE_DIR/conf"
|
||||
export POSTGRESQL_MOUNTED_CONF_DIR="/bitnami/postgresql/conf"
|
||||
export POSTGRESQL_CONF_FILE="$POSTGRESQL_CONF_DIR/postgresql.conf"
|
||||
export POSTGRESQL_PGHBA_FILE="$POSTGRESQL_CONF_DIR/pg_hba.conf"
|
||||
export POSTGRESQL_RECOVERY_FILE="$POSTGRESQL_DATA_DIR/recovery.conf"
|
||||
export POSTGRESQL_LOG_DIR="$POSTGRESQL_BASE_DIR/logs"
|
||||
export POSTGRESQL_LOG_FILE="$POSTGRESQL_LOG_DIR/postgresql.log"
|
||||
export POSTGRESQL_TMP_DIR="$POSTGRESQL_BASE_DIR/tmp"
|
||||
export POSTGRESQL_PID_FILE="$POSTGRESQL_TMP_DIR/postgresql.pid"
|
||||
export POSTGRESQL_BIN_DIR="$POSTGRESQL_BASE_DIR/bin"
|
||||
export POSTGRESQL_INITSCRIPTS_DIR=/docker-entrypoint-initdb.d
|
||||
export PATH="$POSTGRESQL_BIN_DIR:$PATH"
|
||||
|
||||
# Users
|
||||
export POSTGRESQL_DAEMON_USER="postgresql"
|
||||
export POSTGRESQL_DAEMON_GROUP="postgresql"
|
||||
|
||||
# Settings
|
||||
export POSTGRESQL_INIT_MAX_TIMEOUT=${POSTGRESQL_INIT_MAX_TIMEOUT:-60}
|
||||
export POSTGRESQL_CLUSTER_APP_NAME=${POSTGRESQL_CLUSTER_APP_NAME:-walreceiver}
|
||||
export POSTGRESQL_DATABASE="${POSTGRESQL_DATABASE:-postgres}"
|
||||
export POSTGRESQL_INITDB_ARGS="${POSTGRESQL_INITDB_ARGS:-}"
|
||||
export ALLOW_EMPTY_PASSWORD="${ALLOW_EMPTY_PASSWORD:-no}"
|
||||
export POSTGRESQL_INITDB_WAL_DIR="${POSTGRESQL_INITDB_WAL_DIR:-}"
|
||||
export POSTGRESQL_MASTER_HOST="${POSTGRESQL_MASTER_HOST:-}"
|
||||
export POSTGRESQL_MASTER_PORT_NUMBER="${POSTGRESQL_MASTER_PORT_NUMBER:-5432}"
|
||||
export POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS="${POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS:-0}"
|
||||
export POSTGRESQL_PORT_NUMBER="${POSTGRESQL_PORT_NUMBER:-5432}"
|
||||
export POSTGRESQL_REPLICATION_MODE="${POSTGRESQL_REPLICATION_MODE:-master}"
|
||||
export POSTGRESQL_REPLICATION_USER="${POSTGRESQL_REPLICATION_USER:-}"
|
||||
export POSTGRESQL_SYNCHRONOUS_COMMIT_MODE="${POSTGRESQL_SYNCHRONOUS_COMMIT_MODE:-on}"
|
||||
export POSTGRESQL_FSYNC="${POSTGRESQL_FSYNC:-on}"
|
||||
export POSTGRESQL_USERNAME="${POSTGRESQL_USERNAME:-postgres}"
|
||||
EOF
|
||||
if [[ -f "${POSTGRESQL_PASSWORD_FILE:-}" ]]; then
|
||||
cat <<"EOF"
|
||||
export POSTGRESQL_PASSWORD="$(< "${POSTGRESQL_PASSWORD_FILE}")"
|
||||
EOF
|
||||
else
|
||||
cat <<"EOF"
|
||||
export POSTGRESQL_PASSWORD="${POSTGRESQL_PASSWORD:-}"
|
||||
EOF
|
||||
fi
|
||||
if [[ -f "${POSTGRESQL_REPLICATION_PASSWORD_FILE:-}" ]]; then
|
||||
cat <<"EOF"
|
||||
export POSTGRESQL_REPLICATION_PASSWORD="$(< "${POSTGRESQL_REPLICATION_PASSWORD_FILE}")"
|
||||
EOF
|
||||
else
|
||||
cat <<"EOF"
|
||||
export POSTGRESQL_REPLICATION_PASSWORD="${POSTGRESQL_REPLICATION_PASSWORD:-}"
|
||||
EOF
|
||||
fi
|
||||
if [[ -f "${POSTGRESQL_POSTGRES_PASSWORD_FILE:-}" ]]; then
|
||||
cat <<"EOF"
|
||||
export POSTGRESQL_POSTGRES_PASSWORD="$(< "${POSTGRESQL_POSTGRES_PASSWORD_FILE}")"
|
||||
EOF
|
||||
else
|
||||
cat <<"EOF"
|
||||
export POSTGRESQL_POSTGRES_PASSWORD="${POSTGRESQL_POSTGRES_PASSWORD:-}"
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Validate settings in POSTGRESQL_* environment variables
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_validate() {
|
||||
postgresql_info "Validating settings in POSTGRESQL_* env vars.."
|
||||
|
||||
# Auxiliary functions
|
||||
empty_password_enabled_warn() {
|
||||
postgresql_warn "You set the environment variable ALLOW_EMPTY_PASSWORD=${ALLOW_EMPTY_PASSWORD}. For safety reasons, do not use this flag in a production environment."
|
||||
}
|
||||
empty_password_error() {
|
||||
postgresql_error "The $1 environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow the container to be started with blank passwords. This is recommended only for development."
|
||||
exit 1
|
||||
}
|
||||
if is_boolean_yes "$ALLOW_EMPTY_PASSWORD"; then
|
||||
empty_password_enabled_warn
|
||||
else
|
||||
if [[ -z "$POSTGRESQL_PASSWORD" ]]; then
|
||||
empty_password_error "POSTGRESQL_PASSWORD"
|
||||
exit 1
|
||||
fi
|
||||
if (( ${#POSTGRESQL_PASSWORD} > 100 )); then
|
||||
postgresql_error "The password cannot be longer than 100 characters. Set the environment variable POSTGRESQL_PASSWORD with a shorter value"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$POSTGRESQL_USERNAME" ]] && [[ -z "$POSTGRESQL_PASSWORD" ]]; then
|
||||
empty_password_error "POSTGRESQL_PASSWORD"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$POSTGRESQL_USERNAME" ]] && [[ "$POSTGRESQL_USERNAME" != "postgres" ]] && [[ -n "$POSTGRESQL_PASSWORD" ]] && [[ -z "$POSTGRESQL_DATABASE" ]]; then
|
||||
postgresql_error "In order to use a custom PostgreSQL user you need to set the environment variable POSTGRESQL_DATABASE as well"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$POSTGRESQL_REPLICATION_MODE" ]]; then
|
||||
if [[ "$POSTGRESQL_REPLICATION_MODE" = "master" ]]; then
|
||||
if (( POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS < 0 )); then
|
||||
postgresql_error "The number of synchronous replicas cannot be less than 0. Set the environment variable POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$POSTGRESQL_REPLICATION_MODE" = "slave" ]]; then
|
||||
if [[ -z "$POSTGRESQL_MASTER_HOST" ]]; then
|
||||
postgresql_error "Slave replication mode chosen without setting the environment variable POSTGRESQL_MASTER_HOST. Use it to indicate where the Master node is running"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "$POSTGRESQL_REPLICATION_USER" ]]; then
|
||||
postgresql_error "Slave replication mode chosen without setting the environment variable POSTGRESQL_REPLICATION_USER. Make sure that the master also has this parameter set"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
postgresql_error "Invalid replication mode. Available options are 'master/slave'"
|
||||
exit 1
|
||||
fi
|
||||
# Common replication checks
|
||||
if [[ -n "$POSTGRESQL_REPLICATION_USER" ]] && [[ -z "$POSTGRESQL_REPLICATION_PASSWORD" ]]; then
|
||||
empty_password_error "POSTGRESQL_REPLICATION_PASSWORD"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if is_boolean_yes "$ALLOW_EMPTY_PASSWORD"; then
|
||||
empty_password_enabled_warn
|
||||
else
|
||||
if [[ -z "$POSTGRESQL_PASSWORD" ]]; then
|
||||
empty_password_error "POSTGRESQL_PASSWORD"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$POSTGRESQL_USERNAME" ]] && [[ -z "$POSTGRESQL_PASSWORD" ]]; then
|
||||
empty_password_error "POSTGRESQL_PASSWORD"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Create basic postgresql.conf file using the example provided in the share/ folder
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_create_config() {
|
||||
postgresql_info "postgresql.conf file not detected. Generating it..."
|
||||
cp "$POSTGRESQL_BASE_DIR/share/postgresql.conf.sample" "$POSTGRESQL_CONF_FILE"
|
||||
# Update default value for 'include_dir' directive
|
||||
# ref: https://github.com/postgres/postgres/commit/fb9c475597c245562a28d1e916b575ac4ec5c19f#diff-f5544d9b6d218cc9677524b454b41c60
|
||||
if ! grep include_dir "$POSTGRESQL_CONF_FILE" > /dev/null; then
|
||||
postgresql_error "include_dir line is not present in $POSTGRESQL_CONF_FILE. This may be due to a changes in a new version of PostgreSQL. Please check"
|
||||
exit 1
|
||||
fi
|
||||
sed -i -E "/#include_dir/i include_dir = 'conf.d'" "$POSTGRESQL_CONF_FILE"
|
||||
}
|
||||
|
||||
########################
|
||||
# Create basic pg_hba.conf file
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_create_pghba() {
|
||||
postgresql_info "pg_hba.conf file not detected. Generating it..."
|
||||
cat << EOF > "$POSTGRESQL_PGHBA_FILE"
|
||||
host all all 0.0.0.0/0 trust
|
||||
host all all ::1/128 trust
|
||||
EOF
|
||||
}
|
||||
|
||||
########################
|
||||
# Change pg_hba.conf so it allows local UNIX socket-based connections
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_allow_local_connection() {
|
||||
cat << EOF >> "$POSTGRESQL_PGHBA_FILE"
|
||||
local all all trust
|
||||
EOF
|
||||
}
|
||||
|
||||
########################
|
||||
# Change pg_hba.conf so only password-based authentication is allowed
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_restrict_pghba() {
|
||||
if [[ -n "$POSTGRESQL_PASSWORD" ]]; then
|
||||
sed -i 's/trust/md5/g' "$POSTGRESQL_PGHBA_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Change pg_hba.conf so it allows access from replication users
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_add_replication_to_pghba() {
|
||||
local replication_auth="trust"
|
||||
if [[ -n "$POSTGRESQL_REPLICATION_PASSWORD" ]]; then
|
||||
replication_auth="md5"
|
||||
fi
|
||||
cat << EOF >> "$POSTGRESQL_PGHBA_FILE"
|
||||
host replication all 0.0.0.0/0 ${replication_auth}
|
||||
EOF
|
||||
}
|
||||
|
||||
########################
|
||||
# Change a PostgreSQL configuration file by setting a property
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# $1 - property
|
||||
# $2 - value
|
||||
# $3 - Path to configuration file (default: $POSTGRESQL_CONF_FILE)
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_set_property() {
|
||||
local -r property="${1:?missing property}"
|
||||
local -r value="${2:?missing value}"
|
||||
local -r conf_file="${3:-$POSTGRESQL_CONF_FILE}"
|
||||
sed -i "s?^#*\s*${property}\s*=.*?${property} = '${value}'?g" "$conf_file"
|
||||
}
|
||||
|
||||
########################
|
||||
# Create a user for master-slave replication
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_create_replication_user() {
|
||||
local -r escaped_password="${POSTGRESQL_REPLICATION_PASSWORD//\'/\'\'}"
|
||||
postgresql_info "Creating replication user $POSTGRESQL_REPLICATION_USER"
|
||||
echo "CREATE ROLE \"$POSTGRESQL_REPLICATION_USER\" REPLICATION LOGIN ENCRYPTED PASSWORD '$escaped_password'" | postgresql_execute
|
||||
}
|
||||
|
||||
########################
|
||||
# Change postgresql.conf by setting replication parameters
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_configure_replication_parameters() {
|
||||
postgresql_info "Configuring replication parameters"
|
||||
postgresql_set_property "wal_level" "hot_standby"
|
||||
postgresql_set_property "max_wal_size" "400MB"
|
||||
postgresql_set_property "max_wal_senders" "16"
|
||||
postgresql_set_property "wal_keep_segments" "12"
|
||||
postgresql_set_property "hot_standby" "on"
|
||||
if (( POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS > 0 )); then
|
||||
postgresql_set_property "synchronous_commit" "$POSTGRESQL_SYNCHRONOUS_COMMIT_MODE"
|
||||
postgresql_set_property "synchronous_standby_names" "$POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS ($POSTGRESQL_CLUSTER_APP_NAME)"
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Change postgresql.conf by setting fsync
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_configure_fsync() {
|
||||
postgresql_info "Configuring fsync"
|
||||
postgresql_set_property "fsync" "$POSTGRESQL_FSYNC"
|
||||
}
|
||||
|
||||
########################
|
||||
# Alter password of the postgres user
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# Password
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_alter_postgres_user() {
|
||||
local -r escaped_password="${1//\'/\'\'}"
|
||||
postgresql_info "Changing password of postgres"
|
||||
echo "ALTER ROLE postgres WITH PASSWORD '$escaped_password';" | postgresql_execute
|
||||
}
|
||||
|
||||
########################
|
||||
# Create an admin user with all privileges in POSTGRESQL_DATABASE
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_create_admin_user() {
|
||||
local -r escaped_password="${POSTGRESQL_PASSWORD//\'/\'\'}"
|
||||
postgresql_info "Creating user ${POSTGRESQL_USERNAME}"
|
||||
echo "CREATE ROLE \"${POSTGRESQL_USERNAME}\" WITH LOGIN CREATEDB PASSWORD '${escaped_password}';" | postgresql_execute
|
||||
postgresql_info "Grating access to \"${POSTGRESQL_USERNAME}\" to the database \"${POSTGRESQL_DATABASE}\""
|
||||
echo "GRANT ALL PRIVILEGES ON DATABASE \"${POSTGRESQL_DATABASE}\" TO \"${POSTGRESQL_USERNAME}\"\;" | postgresql_execute "" "postgres" "$POSTGRESQL_PASSWORD"
|
||||
}
|
||||
|
||||
########################
|
||||
# Create a database with name $POSTGRESQL_DATABASE
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_create_custom_database() {
|
||||
echo "CREATE DATABASE \"$POSTGRESQL_DATABASE\"" | postgresql_execute "" "postgres" "" "localhost"
|
||||
}
|
||||
|
||||
########################
|
||||
# Change postgresql.conf to listen in 0.0.0.0
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_enable_remote_connections() {
|
||||
postgresql_set_property "listen_addresses" "*"
|
||||
}
|
||||
|
||||
########################
|
||||
# Check if a given configuration file was mounted externally
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# $1 - Filename
|
||||
# Returns:
|
||||
# 1 if the file was mounted externally, 0 otherwise
|
||||
#########################
|
||||
postgresql_is_file_external() {
|
||||
local -r filename=$1
|
||||
if [[ -d "$POSTGRESQL_MOUNTED_CONF_DIR" ]] && [[ -f "$POSTGRESQL_MOUNTED_CONF_DIR"/"$filename" ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Ensure PostgreSQL is initialized
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_initialize() {
|
||||
postgresql_info "Initializing PostgreSQL database..."
|
||||
|
||||
# This fixes an issue where the trap would kill the entrypoint.sh, if a PID was left over from a previous run
|
||||
# Exec replaces the process without creating a new one, and when the container is restarted it may have the same PID
|
||||
rm -f "$POSTGRESQL_PID_FILE"
|
||||
|
||||
# User injected custom configuration
|
||||
if [[ -d "$POSTGRESQL_MOUNTED_CONF_DIR" ]] && compgen -G "$POSTGRESQL_MOUNTED_CONF_DIR"/* > /dev/null; then
|
||||
postgresql_debug "Copying files from $POSTGRESQL_MOUNTED_CONF_DIR to $POSTGRESQL_CONF_DIR"
|
||||
cp -fr "$POSTGRESQL_MOUNTED_CONF_DIR"/. "$POSTGRESQL_CONF_DIR"
|
||||
fi
|
||||
local create_conf_file=yes
|
||||
local create_pghba_file=yes
|
||||
|
||||
if postgresql_is_file_external "postgresql.conf"; then
|
||||
postgresql_info "Custom configuration $POSTGRESQL_CONF_FILE detected"
|
||||
create_conf_file=no
|
||||
fi
|
||||
|
||||
if postgresql_is_file_external "pg_hba.conf"; then
|
||||
postgresql_info "Custom configuration $POSTGRESQL_PGHBA_FILE detected"
|
||||
create_pghba_file=no
|
||||
fi
|
||||
|
||||
postgresql_debug "Ensuring expected directories/files exist..."
|
||||
for dir in "$POSTGRESQL_TMP_DIR" "$POSTGRESQL_LOG_DIR"; do
|
||||
ensure_dir_exists "$dir"
|
||||
am_i_root && chown "$POSTGRESQL_DAEMON_USER:$POSTGRESQL_DAEMON_GROUP" "$dir"
|
||||
done
|
||||
is_boolean_yes "$create_conf_file" && postgresql_create_config
|
||||
is_boolean_yes "$create_pghba_file" && postgresql_create_pghba && postgresql_allow_local_connection
|
||||
|
||||
if ! is_dir_empty "$POSTGRESQL_DATA_DIR"; then
|
||||
postgresql_info "Deploying PostgreSQL with persisted data..."
|
||||
local -r postmaster_path="$POSTGRESQL_DATA_DIR"/postmaster.pid
|
||||
if [[ -f "$postmaster_path" ]]; then
|
||||
postgresql_info "Cleaning stale postmaster.pid file"
|
||||
rm "$postmaster_path"
|
||||
fi
|
||||
is_boolean_yes "$create_pghba_file" && postgresql_restrict_pghba
|
||||
is_boolean_yes "$create_conf_file" && postgresql_configure_replication_parameters
|
||||
is_boolean_yes "$create_conf_file" && postgresql_configure_fsync
|
||||
[[ "$POSTGRESQL_REPLICATION_MODE" = "master" ]] && [[ -n "$POSTGRESQL_REPLICATION_USER" ]] && is_boolean_yes "$create_pghba_file" && postgresql_add_replication_to_pghba
|
||||
else
|
||||
ensure_dir_exists "$POSTGRESQL_DATA_DIR"
|
||||
am_i_root && chown "$POSTGRESQL_DAEMON_USER:$POSTGRESQL_DAEMON_GROUP" "$POSTGRESQL_DATA_DIR"
|
||||
if [[ "$POSTGRESQL_REPLICATION_MODE" = "master" ]]; then
|
||||
postgresql_master_init_db
|
||||
postgresql_start_bg
|
||||
[[ -n "${POSTGRESQL_DATABASE}" ]] && [[ "$POSTGRESQL_DATABASE" != "postgres" ]] && postgresql_create_custom_database
|
||||
if [[ "$POSTGRESQL_USERNAME" = "postgres" ]]; then
|
||||
postgresql_alter_postgres_user "$POSTGRESQL_PASSWORD"
|
||||
else
|
||||
if [[ -n "$POSTGRESQL_POSTGRES_PASSWORD" ]]; then
|
||||
postgresql_alter_postgres_user "$POSTGRESQL_POSTGRES_PASSWORD"
|
||||
fi
|
||||
postgresql_create_admin_user
|
||||
fi
|
||||
is_boolean_yes "$create_pghba_file" && postgresql_restrict_pghba
|
||||
[[ -n "$POSTGRESQL_REPLICATION_USER" ]] && postgresql_create_replication_user
|
||||
is_boolean_yes "$create_conf_file" && postgresql_configure_replication_parameters
|
||||
is_boolean_yes "$create_conf_file" && postgresql_configure_fsync
|
||||
[[ -n "$POSTGRESQL_REPLICATION_USER" ]] && is_boolean_yes "$create_pghba_file" && postgresql_add_replication_to_pghba
|
||||
else
|
||||
postgresql_slave_init_db
|
||||
is_boolean_yes "$create_pghba_file" && postgresql_restrict_pghba
|
||||
is_boolean_yes "$create_conf_file" && postgresql_configure_replication_parameters
|
||||
is_boolean_yes "$create_conf_file" && postgresql_configure_fsync
|
||||
postgresql_configure_recovery
|
||||
fi
|
||||
fi
|
||||
|
||||
# Delete conf files generated on first run
|
||||
rm -f "$POSTGRESQL_DATA_DIR"/postgresql.conf "$POSTGRESQL_DATA_DIR"/pg_hba.conf
|
||||
}
|
||||
|
||||
########################
|
||||
# Run custom initialization scripts
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_custom_init_scripts() {
|
||||
postgresql_info "Loading custom scripts..."
|
||||
if [[ -n $(find "$POSTGRESQL_INITSCRIPTS_DIR/" -type f -regex ".*\.\(sh\|sql\|sql.gz\)") ]] && [[ ! -f "$POSTGRESQL_VOLUME_DIR/.user_scripts_initialized" ]] ; then
|
||||
postgresql_info "Loading user's custom files from $POSTGRESQL_INITSCRIPTS_DIR ...";
|
||||
postgresql_start_bg
|
||||
find "$POSTGRESQL_INITSCRIPTS_DIR/" -type f -regex ".*\.\(sh\|sql\|sql.gz\)" | sort | while read -r f; do
|
||||
case "$f" in
|
||||
*.sh)
|
||||
if [[ -x "$f" ]]; then
|
||||
postgresql_debug "Executing $f"; "$f"
|
||||
else
|
||||
postgresql_debug "Sourcing $f"; . "$f"
|
||||
fi
|
||||
;;
|
||||
*.sql) postgresql_debug "Executing $f"; postgresql_execute "$POSTGRESQL_DATABASE" "$POSTGRESQL_USERNAME" "$POSTGRESQL_PASSWORD" < "$f";;
|
||||
*.sql.gz) postgresql_debug "Executing $f"; gunzip -c "$f" | postgresql_execute "$POSTGRESQL_DATABASE" "$POSTGRESQL_USERNAME" "$POSTGRESQL_PASSWORD";;
|
||||
*) postgresql_debug "Ignoring $f" ;;
|
||||
esac
|
||||
done
|
||||
touch "$POSTGRESQL_VOLUME_DIR"/.user_scripts_initialized
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Stop PostgreSQL
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_stop() {
|
||||
postgresql_info "Stopping PostgreSQL..."
|
||||
stop_service_using_pid "$POSTGRESQL_PID_FILE"
|
||||
}
|
||||
|
||||
########################
|
||||
# Execute an arbitrary query/queries against the running PostgreSQL service
|
||||
# Stdin:
|
||||
# Query/queries to execute
|
||||
# Globals:
|
||||
# BITNAMI_DEBUG
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# $1 - Database where to run the queries
|
||||
# $2 - User to run queries
|
||||
# $3 - Password
|
||||
# $4 - Host
|
||||
# $5 - Port
|
||||
# $6 - Extra options (eg. -tA)
|
||||
# Returns:
|
||||
# None
|
||||
postgresql_execute() {
|
||||
local -r db="${1:-}"
|
||||
local -r user="${2:-postgres}"
|
||||
local -r pass="${3:-}"
|
||||
local -r host="${4:-localhost}"
|
||||
local -r port="${5:-5432}"
|
||||
local -r opts="${6:-}"
|
||||
|
||||
local args=( "-h" "$host" "-p" "$port" "-U" "$user" )
|
||||
local cmd=("$POSTGRESQL_BIN_DIR/psql")
|
||||
[[ -n "$db" ]] && args+=( "-d" "$db" )
|
||||
[[ -n "$opts" ]] && args+=( "$opts" )
|
||||
if [[ "${BITNAMI_DEBUG:-false}" = true ]]; then
|
||||
PGPASSWORD=$pass "${cmd[@]}" "${args[@]}"
|
||||
elif [[ "${NO_ERRORS:-false}" = true ]]; then
|
||||
PGPASSWORD=$pass "${cmd[@]}" "${args[@]}" 2>/dev/null
|
||||
else
|
||||
PGPASSWORD=$pass "${cmd[@]}" "${args[@]}" >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Start PostgreSQL and wait until it is ready
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
postgresql_start_bg() {
|
||||
local -r pg_ctl_flags=("-w" "-D" "$POSTGRESQL_DATA_DIR" "-l" "$POSTGRESQL_LOG_FILE" "-o" "--config-file=$POSTGRESQL_CONF_FILE --external_pid_file=$POSTGRESQL_PID_FILE --hba_file=$POSTGRESQL_PGHBA_FILE")
|
||||
postgresql_info "Starting PostgreSQL in background..."
|
||||
is_postgresql_running && return
|
||||
if [[ "${BITNAMI_DEBUG:-false}" = true ]]; then
|
||||
"$POSTGRESQL_BIN_DIR"/pg_ctl "start" "${pg_ctl_flags[@]}"
|
||||
else
|
||||
"$POSTGRESQL_BIN_DIR"/pg_ctl "start" "${pg_ctl_flags[@]}" >/dev/null 2>&1
|
||||
fi
|
||||
local -r pg_isready_args=("-U" "postgres")
|
||||
local counter=$POSTGRESQL_INIT_MAX_TIMEOUT
|
||||
while ! "$POSTGRESQL_BIN_DIR"/pg_isready "${pg_isready_args[@]}" >/dev/null 2>&1; do
|
||||
sleep 1
|
||||
counter=$((counter - 1 ))
|
||||
if (( counter <= 0 )); then
|
||||
postgresql_error "PostgreSQL is not ready after $POSTGRESQL_INIT_MAX_TIMEOUT seconds"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
########################
|
||||
# Check if PostgreSQL is running
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Boolean
|
||||
#########################
|
||||
is_postgresql_running() {
|
||||
local pid
|
||||
pid="$(get_pid_from_file "$POSTGRESQL_PID_FILE")"
|
||||
|
||||
if [[ -z "$pid" ]]; then
|
||||
false
|
||||
else
|
||||
is_service_running "$pid"
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Initialize master node database by running initdb
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Boolean
|
||||
#########################
|
||||
postgresql_master_init_db() {
|
||||
local initdb_args=()
|
||||
if [[ -n "${POSTGRESQL_INITDB_ARGS[*]}" ]]; then
|
||||
initdb_args+=("${POSTGRESQL_INITDB_ARGS[@]}")
|
||||
fi
|
||||
if [[ -n "$POSTGRESQL_INITDB_WAL_DIR" ]]; then
|
||||
ensure_dir_exists "$POSTGRESQL_INITDB_WAL_DIR"
|
||||
am_i_root && chown "$POSTGRESQL_DAEMON_USER:$POSTGRESQL_DAEMON_GROUP" "$POSTGRESQL_INITDB_WAL_DIR"
|
||||
initdb_args+=("--waldir" "$POSTGRESQL_INITDB_WAL_DIR")
|
||||
fi
|
||||
if [[ -n "${initdb_args[*]:-}" ]]; then
|
||||
postgresql_info "Initializing PostgreSQL with ${initdb_args[*]} extra initdb arguments"
|
||||
if [[ "${BITNAMI_DEBUG:-false}" = true ]]; then
|
||||
"$POSTGRESQL_BIN_DIR/initdb" -E UTF8 -D "$POSTGRESQL_DATA_DIR" -U "postgres" "${initdb_args[@]}"
|
||||
else
|
||||
"$POSTGRESQL_BIN_DIR/initdb" -E UTF8 -D "$POSTGRESQL_DATA_DIR" -U "postgres" "${initdb_args[@]}" >/dev/null 2>&1
|
||||
fi
|
||||
elif [[ "${BITNAMI_DEBUG:-false}" = true ]]; then
|
||||
"$POSTGRESQL_BIN_DIR/initdb" -E UTF8 -D "$POSTGRESQL_DATA_DIR" -U "postgres"
|
||||
else
|
||||
"$POSTGRESQL_BIN_DIR/initdb" -E UTF8 -D "$POSTGRESQL_DATA_DIR" -U "postgres" >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Initialize slave node by running pg_basebackup
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Boolean
|
||||
#########################
|
||||
postgresql_slave_init_db() {
|
||||
postgresql_info "Waiting for replication master to accept connections (${POSTGRESQL_INIT_MAX_TIMEOUT} timeout)..."
|
||||
local -r check_args=("-U" "$POSTGRESQL_REPLICATION_USER" "-h" "$POSTGRESQL_MASTER_HOST" "-p" "$POSTGRESQL_MASTER_PORT_NUMBER" "-d" "postgres")
|
||||
local -r check_cmd=("$POSTGRESQL_BIN_DIR"/pg_isready)
|
||||
local ready_counter=$POSTGRESQL_INIT_MAX_TIMEOUT
|
||||
|
||||
while ! PGPASSWORD=$POSTGRESQL_REPLICATION_PASSWORD "${check_cmd[@]}" "${check_args[@]}";do
|
||||
sleep 1
|
||||
ready_counter=$(( ready_counter - 1 ))
|
||||
if (( ready_counter <= 0 )); then
|
||||
postgresql_error "PostgreSQL master is not ready after $POSTGRESQL_INIT_MAX_TIMEOUT seconds"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
done
|
||||
postgresql_info "Replicating the initial database"
|
||||
local -r backup_args=("-D" "$POSTGRESQL_DATA_DIR" "-U" "$POSTGRESQL_REPLICATION_USER" "-h" "$POSTGRESQL_MASTER_HOST" "-p" "$POSTGRESQL_MASTER_PORT_NUMBER" "-X" "stream" "-w" "-v" "-P")
|
||||
local -r backup_cmd=("$POSTGRESQL_BIN_DIR"/pg_basebackup)
|
||||
local replication_counter=$POSTGRESQL_INIT_MAX_TIMEOUT
|
||||
while ! PGPASSWORD=$POSTGRESQL_REPLICATION_PASSWORD "${backup_cmd[@]}" "${backup_args[@]}";do
|
||||
postgresql_debug "Backup command failed. Sleeping and trying again"
|
||||
sleep 1
|
||||
replication_counter=$(( replication_counter - 1 ))
|
||||
if (( replication_counter <= 0 )); then
|
||||
postgresql_error "Slave replication failed after trying for $POSTGRESQL_INIT_MAX_TIMEOUT seconds"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
chmod 0700 "$POSTGRESQL_DATA_DIR"
|
||||
}
|
||||
|
||||
########################
|
||||
# Create recovery.conf in slave node
|
||||
# Globals:
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Boolean
|
||||
#########################
|
||||
postgresql_configure_recovery() {
|
||||
postgresql_info "Setting up streaming replication slave..."
|
||||
cp -f "$POSTGRESQL_BASE_DIR/share/recovery.conf.sample" "$POSTGRESQL_RECOVERY_FILE"
|
||||
chmod 600 "$POSTGRESQL_RECOVERY_FILE"
|
||||
postgresql_set_property "standby_mode" "on" "$POSTGRESQL_RECOVERY_FILE"
|
||||
postgresql_set_property "primary_conninfo" "host=$POSTGRESQL_MASTER_HOST port=$POSTGRESQL_MASTER_PORT_NUMBER user=$POSTGRESQL_REPLICATION_USER password=$POSTGRESQL_REPLICATION_PASSWORD application_name=$POSTGRESQL_CLUSTER_APP_NAME" "$POSTGRESQL_RECOVERY_FILE"
|
||||
postgresql_set_property "trigger_file" "/tmp/postgresql.trigger.$POSTGRESQL_MASTER_PORT_NUMBER" "$POSTGRESQL_RECOVERY_FILE"
|
||||
}
|
||||
|
|
@ -0,0 +1,595 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Bitnami Postgresql Repmgr library
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load Generic Libraries
|
||||
. /liblog.sh
|
||||
. /libfs.sh
|
||||
. /libos.sh
|
||||
. /libvalidations.sh
|
||||
|
||||
########################
|
||||
# Overwrite info, debug, warn and error functions (liblog.sh)
|
||||
########################
|
||||
repmgr_info() {
|
||||
MODULE=repmgr info "${*}"
|
||||
}
|
||||
repmgr_debug() {
|
||||
MODULE=repmgr debug "${*}"
|
||||
}
|
||||
repmgr_warn() {
|
||||
MODULE=repmgr warn "${*}"
|
||||
}
|
||||
repmgr_error() {
|
||||
MODULE=repmgr error "${*}"
|
||||
}
|
||||
|
||||
########################
|
||||
# Loads global variables used on repmgr configuration.
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Series of exports to be used as 'eval' arguments
|
||||
#########################
|
||||
repmgr_env() {
|
||||
cat <<"EOF"
|
||||
# Paths
|
||||
export REPMGR_BASE_DIR="/opt/bitnami/repmgr"
|
||||
export REPMGR_CONF_DIR="${REPMGR_BASE_DIR}/conf"
|
||||
export REPMGR_TMP_DIR="${REPMGR_BASE_DIR}/tmp"
|
||||
export REPMGR_EVENTS_DIR="${REPMGR_BASE_DIR}/events"
|
||||
export REPMGR_PRIMARY_ROLE_LOCK_FILE_NAME="${REPMGR_TMP_DIR}/master.lock"
|
||||
export REPMGR_STANDBY_ROLE_LOCK_FILE_NAME="${REPMGR_TMP_DIR}/standby.lock"
|
||||
export REPMGR_BIN_DIR="${REPMGR_BASE_DIR}/bin"
|
||||
export REPMGR_CONF_FILE="${REPMGR_CONF_DIR}/repmgr.conf"
|
||||
export REPMGR_PID_FILE="${REPMGR_TMP_DIR}/repmgr.pid"
|
||||
export PATH="${REPMGR_BIN_DIR}:$PATH"
|
||||
|
||||
# Settings
|
||||
export REPMGR_NODE_ID="${REPMGR_NODE_ID:-}"
|
||||
export REPMGR_NODE_NAME="${REPMGR_NODE_NAME:-$(hostname)}"
|
||||
export REPMGR_NODE_NETWORK_NAME="${REPMGR_NODE_NETWORK_NAME:-}"
|
||||
export REPMGR_NODE_PRIORITY="${REPMGR_NODE_PRIORITY:-100}"
|
||||
|
||||
export REPMGR_PORT_NUMBER="${REPMGR_PORT_NUMBER:-5432}"
|
||||
export REPMGR_LOG_LEVEL="${REPMGR_LOG_LEVEL:-NOTICE}"
|
||||
|
||||
export REPMGR_START_OPTIONS="${REPMGR_START_OPTIONS:-}"
|
||||
export REPMGR_CONNECT_TIMEOUT="${REPMGR_CONNECT_TIMEOUT:-5}"
|
||||
export REPMGR_RECONNECT_ATTEMPTS="${REPMGR_RECONNECT_ATTEMPTS:-3}"
|
||||
export REPMGR_RECONNECT_INTERVAL="${REPMGR_RECONNECT_INTERVAL:-5}"
|
||||
|
||||
export REPMGR_PARTNER_NODES="${REPMGR_PARTNER_NODES:-}"
|
||||
export REPMGR_PRIMARY_HOST="${REPMGR_PRIMARY_HOST:-}"
|
||||
export REPMGR_PRIMARY_PORT="${REPMGR_PRIMARY_PORT:-5432}"
|
||||
|
||||
export REPMGR_USE_REPLICATION_SLOTS="${REPMGR_USE_REPLICATION_SLOTS:-1}"
|
||||
export REPMGR_STANDBY_ROLE_LOCK_FILE_NAME="${REPMGR_TMP_DIR}/standby.lock"
|
||||
export REPMGR_MASTER_RESPONSE_TIMEOUT="${REPMGR_MASTER_RESPONSE_TIMEOUT:-20}"
|
||||
export REPMGR_DEGRADED_MONITORING_TIMEOUT="${REPMGR_DEGRADED_MONITORING_TIMEOUT:-5}"
|
||||
|
||||
# These are internal
|
||||
export REPMGR_SWITCH_ROLE="${REPMGR_SWITCH_ROLE:-no}"
|
||||
export REPMGR_CURRENT_PRIMARY_HOST=""
|
||||
|
||||
# Aliases to setup PostgreSQL environment variables
|
||||
export PGCONNECT_TIMEOUT="${PGCONNECT_TIMEOUT:-10}"
|
||||
|
||||
# Credentials
|
||||
export REPMGR_USERNAME="${REPMGR_USERNAME:-repmgr}"
|
||||
export REPMGR_DATABASE="${REPMGR_DATABASE:-repmgr}"
|
||||
EOF
|
||||
if [[ -f "${REPMGR_PASSWORD_FILE:-}" ]]; then
|
||||
cat <<"EOF"
|
||||
export REPMGR_PASSWORD="$(< "${REPMGR_PASSWORD_FILE}")"
|
||||
EOF
|
||||
else
|
||||
cat <<"EOF"
|
||||
export REPMGR_PASSWORD="${REPMGR_PASSWORD:-}"
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Get repmgr node id
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# String
|
||||
#########################
|
||||
repmgr_get_node_id() {
|
||||
local num
|
||||
if [[ "$REPMGR_NODE_ID" != "" ]]; then
|
||||
echo "$REPMGR_NODE_ID"
|
||||
else
|
||||
num="${REPMGR_NODE_NAME##*-}"
|
||||
if [[ "$num" != "" ]]; then
|
||||
num=$((num+1000))
|
||||
echo "$num"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Validate settings in REPMGR_* env. variables
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_validate() {
|
||||
repmgr_info "Validating settings in REPMGR_* env vars..."
|
||||
|
||||
# Auxiliary functions
|
||||
print_error_exit() {
|
||||
repmgr_error "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ -z "$REPMGR_PARTNER_NODES" ]]; then
|
||||
print_error_exit "The list of partner nodes cannot be empty. Set the environment variable REPMGR_PARTNER_NODES with a comma separated list of partner nodes."
|
||||
fi
|
||||
if [[ -z "$REPMGR_PRIMARY_HOST" ]]; then
|
||||
print_error_exit "The initial primary host is required. Set the environment variable REPMGR_PRIMARY_HOST with the initial primary host."
|
||||
fi
|
||||
if [[ -z "$REPMGR_NODE_NAME" ]]; then
|
||||
print_error_exit "The node name is required. Set the environment variable REPMGR_NODE_NAME with the node name."
|
||||
elif [[ ! "$REPMGR_NODE_NAME" =~ ^[A-Za-z]+-[0-9]+$ ]]; then
|
||||
print_error_exit "The node name does not follow the required format. Valid format: [A-Za-z]+-[0-9]+"
|
||||
fi
|
||||
if [[ -z "$(repmgr_get_node_id)" ]]; then
|
||||
print_error_exit "The node id is required. Set the environment variable REPMGR_NODE_ID with the node id."
|
||||
fi
|
||||
if [[ -z "$REPMGR_NODE_NETWORK_NAME" ]]; then
|
||||
print_error_exit "The node network name is required. Set the environment variable REPMGR_NODE_NETWORK_NAME with the node network name."
|
||||
fi
|
||||
# Credentials validations
|
||||
if [[ -z "$REPMGR_USERNAME" ]] || [[ -z "$REPMGR_PASSWORD" ]]; then
|
||||
print_error_exit "The repmgr credentials are mandatory. Set the environment variables REPMGR_USERNAME and REPMGR_PASSWORD with the repmgr credentials."
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Ask partner nodes which node is the primary
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# Non
|
||||
# Returns:
|
||||
# String
|
||||
#########################
|
||||
repmgr_get_upstream_node() {
|
||||
local primary_conninfo
|
||||
local pretending_primary=""
|
||||
|
||||
if [[ -n "$REPMGR_PARTNER_NODES" ]]; then
|
||||
repmgr_info "Querying all partner nodes for common upstream node..."
|
||||
read -r -a nodes <<< "$(tr ',;' ' ' <<< "${REPMGR_PARTNER_NODES}")"
|
||||
for node in "${nodes[@]}"; do
|
||||
repmgr_debug "Checking node $node..."
|
||||
local query="SELECT conninfo FROM repmgr.show_nodes WHERE (upstream_node_name IS NULL OR upstream_node_name = '') AND active=true"
|
||||
if ! primary_conninfo="$(echo "$query" | NO_ERRORS=true postgresql_execute "$REPMGR_DATABASE" "$REPMGR_USERNAME" "$REPMGR_PASSWORD" "$node" "$REPMGR_PRIMARY_PORT" "-tA")"; then
|
||||
repmgr_debug "Skipping: failed to get primary from the node $node!"
|
||||
continue
|
||||
elif [[ -z "$primary_conninfo" ]]; then
|
||||
repmgr_debug "Skipping: failed to get information about primary nodes!"
|
||||
continue
|
||||
elif [[ "$(echo "$primary_conninfo" | wc -l)" -eq 1 ]]; then
|
||||
local -r suggested_primary="$(echo "$primary_conninfo" | awk -F 'host=' '{print $2}' | awk '{print $1}')"
|
||||
repmgr_debug "Pretending primary role node - ${suggested_primary}"
|
||||
if [[ -n "$pretending_primary" ]]; then
|
||||
if [[ "${pretending_primary}" != "${suggested_primary}" ]]; then
|
||||
repmgr_warn "Conflict of pretending primary role nodes (previously: $pretending_primary, now: $suggested_primary)"
|
||||
pretending_primary="" && break
|
||||
fi
|
||||
else
|
||||
repmgr_debug "Pretending primary set to $suggested_primary!"
|
||||
pretending_primary="$suggested_primary"
|
||||
fi
|
||||
else
|
||||
repmgr_warn "There were more than one primary when getting primary from node $node"
|
||||
pretending_primary="" && break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$pretending_primary"
|
||||
}
|
||||
|
||||
########################
|
||||
# Gets the node that is currently set as primary node
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# String
|
||||
#########################
|
||||
repmgr_get_primary_node() {
|
||||
local upstream_node
|
||||
local primary_node=""
|
||||
|
||||
upstream_node="$(repmgr_get_upstream_node)"
|
||||
[[ -n "$upstream_node" ]] && repmgr_info "Auto-detected primary node: '$upstream_node'"
|
||||
|
||||
if [[ -f "$REPMGR_PRIMARY_ROLE_LOCK_FILE_NAME" ]]; then
|
||||
repmgr_info "This node was acting as a primary before restart!"
|
||||
|
||||
if [[ -z "$upstream_node" ]] || [[ "$upstream_node" = "$REPMGR_NODE_NETWORK_NAME" ]]; then
|
||||
repmgr_info "Can not find new primary. Starting PostgreSQL normally..."
|
||||
else
|
||||
repmgr_info "Current master is $upstream_node. Cloning/rewinding it and acting as a standby node..."
|
||||
rm -f "$REPMGR_PRIMARY_ROLE_LOCK_FILE_NAME"
|
||||
export REPMGR_SWITCH_ROLE="yes"
|
||||
primary_node="$upstream_node"
|
||||
fi
|
||||
else
|
||||
if [[ -z "$upstream_node" ]]; then
|
||||
[[ "$REPMGR_PRIMARY_HOST" != "$REPMGR_NODE_NETWORK_NAME" ]] && primary_node="$REPMGR_PRIMARY_HOST"
|
||||
else
|
||||
primary_node="$upstream_node"
|
||||
fi
|
||||
fi
|
||||
|
||||
[[ -n "$primary_node" ]] && repmgr_debug "Primary node: $primary_node"
|
||||
echo "$primary_node"
|
||||
}
|
||||
|
||||
########################
|
||||
# Generates env vars for the node
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# Series of exports to be used as 'eval' arguments
|
||||
#########################
|
||||
repmgr_set_role() {
|
||||
local role="standby"
|
||||
local primary_node
|
||||
|
||||
primary_node="$(repmgr_get_primary_node)"
|
||||
if [[ -z "$primary_node" ]]; then
|
||||
repmgr_info "There are no nodes with primary role. Assuming the primary role..."
|
||||
role="primary"
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
export REPMGR_ROLE="$role"
|
||||
export REPMGR_CURRENT_PRIMARY_HOST="$primary_node"
|
||||
EOF
|
||||
}
|
||||
|
||||
########################
|
||||
# Change a Repmgr configuration file by setting a property
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# $1 - property
|
||||
# $2 - value
|
||||
# $3 - Path to configuration file (default: $REPMGR_CONF_FILE)
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_set_property() {
|
||||
local -r property="${1:?missing property}"
|
||||
local -r value="${2:-}"
|
||||
local -r conf_file="${3:-$REPMGR_CONF_FILE}"
|
||||
sed -i "s?^#*\s*${property}\s*=.*?${property} = '${value}'?g" "$conf_file"
|
||||
}
|
||||
|
||||
|
||||
########################
|
||||
# Create the repmgr user (with )
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_create_repmgr_user() {
|
||||
local postgres_password="$POSTGRESQL_PASSWORD"
|
||||
local -r escaped_password="${REPMGR_PASSWORD//\'/\'\'}"
|
||||
repmgr_info "Creating repmgr user: $REPMGR_USERNAME"
|
||||
|
||||
[[ "$POSTGRESQL_USERNAME" != "postgres" ]] && [[ -n "$POSTGRESQL_POSTGRES_PASSWORD" ]] && postgres_password="$POSTGRESQL_POSTGRES_PASSWORD"
|
||||
# The repmgr user is created as superuser for simplicity (ref: https://repmgr.org/docs/4.3/quickstart-repmgr-user-database.html)
|
||||
echo "CREATE ROLE \"${REPMGR_USERNAME}\" WITH LOGIN CREATEDB PASSWORD '${escaped_password}';" | postgresql_execute "" "postgres" "$postgres_password"
|
||||
echo "ALTER USER ${REPMGR_USERNAME} WITH SUPERUSER;" | postgresql_execute "" "postgres" "$postgres_password"
|
||||
# set the repmgr user's search path to include the 'repmgr' schema name (ref: https://repmgr.org/docs/4.3/quickstart-repmgr-user-database.html)
|
||||
echo "ALTER USER ${REPMGR_USERNAME} SET search_path TO repmgr, \"\$user\", public;" | postgresql_execute "" "postgres" "$postgres_password"
|
||||
}
|
||||
|
||||
########################
|
||||
# Creates the repmgr database
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_create_repmgr_db() {
|
||||
local postgres_password="$POSTGRESQL_PASSWORD"
|
||||
repmgr_info "Creating repmgr database: $REPMGR_DATABASE"
|
||||
|
||||
[[ "$POSTGRESQL_USERNAME" != "postgres" ]] && [[ -n "$POSTGRESQL_POSTGRES_PASSWORD" ]] && postgres_password="$POSTGRESQL_POSTGRES_PASSWORD"
|
||||
echo "CREATE DATABASE $REPMGR_DATABASE;" | postgresql_execute "" "postgres" "$postgres_password"
|
||||
}
|
||||
|
||||
########################
|
||||
# Use a different PostgreSQL configuration file by pretending it's an injected custom configuration
|
||||
# Globals:
|
||||
# POSTGRESQL_MOUNTED_CONF_DIR
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_inject_postgresql_configuration() {
|
||||
repmgr_debug "Injecting a new postgresql.conf file..."
|
||||
postgresql_create_config
|
||||
# ref: https://repmgr.org/docs/4.3/quickstart-postgresql-configuration.html
|
||||
postgresql_set_property "shared_preload_libraries" "repmgr"
|
||||
postgresql_set_property "max_wal_senders" "10"
|
||||
postgresql_set_property "max_replication_slots" "10"
|
||||
postgresql_set_property "wal_level" "hot_standby"
|
||||
postgresql_set_property "archive_mode" "on"
|
||||
postgresql_set_property "hot_standby" "on"
|
||||
postgresql_set_property "archive_command" "/bin/true"
|
||||
# Redirect logs to POSTGRESQL_LOG_FILE
|
||||
postgresql_set_property "logging_collector" "on"
|
||||
postgresql_set_property "log_directory" "$POSTGRESQL_LOG_DIR"
|
||||
postgresql_set_property "log_filename" "postgresql.log"
|
||||
cp "$POSTGRESQL_CONF_FILE" "$POSTGRESQL_MOUNTED_CONF_DIR/postgresql.conf"
|
||||
}
|
||||
|
||||
########################
|
||||
# Use a different pg_hba.conf file by pretending it's an injected custom configuration\
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_inject_pghba_configuration() {
|
||||
repmgr_debug "Injecting a new pg_hba.conf file..."
|
||||
cat > "${POSTGRESQL_MOUNTED_CONF_DIR}/pg_hba.conf" << EOF
|
||||
host all $REPMGR_USERNAME 0.0.0.0/0 trust
|
||||
host $REPMGR_DATABASE $REPMGR_USERNAME 0.0.0.0/0 trust
|
||||
host replication $REPMGR_USERNAME 0.0.0.0/0 trust
|
||||
host all all 0.0.0.0/0 trust
|
||||
host all all ::1/128 trust
|
||||
local all all trust
|
||||
EOF
|
||||
}
|
||||
|
||||
########################
|
||||
# Prepare PostgreSQL default configuration
|
||||
# Globals:
|
||||
# POSTGRESQL_MOUNTED_CONF_DIR
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_postgresql_configuration() {
|
||||
repmgr_info "Preparing PostgreSQL configuration..."
|
||||
# User injected custom configuration
|
||||
if [[ -d "$POSTGRESQL_MOUNTED_CONF_DIR" ]] && compgen -G "$POSTGRESQL_MOUNTED_CONF_DIR"/* > /dev/null; then
|
||||
repmgr_debug "User injected custom configuration detected!"
|
||||
else
|
||||
ensure_dir_exists "$POSTGRESQL_MOUNTED_CONF_DIR"
|
||||
repmgr_inject_postgresql_configuration
|
||||
repmgr_inject_pghba_configuration
|
||||
fi
|
||||
}
|
||||
|
||||
########################
|
||||
# Generates repmgr config files
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_generate_repmgr_config() {
|
||||
repmgr_info "Preparing repmgr configuration..."
|
||||
|
||||
cat << EOF >> "$REPMGR_CONF_FILE"
|
||||
event_notification_command='${REPMGR_EVENTS_DIR}/router.sh %n %e %s "%t" "%d"'
|
||||
ssh_options=-o \"StrictHostKeyChecking no\" -v
|
||||
use_replication_slots=$REPMGR_USE_REPLICATION_SLOTS
|
||||
pg_bindir=$POSTGRESQL_BIN_DIR
|
||||
|
||||
# FIXME: these 2 parameter should work
|
||||
node_id=$(repmgr_get_node_id)
|
||||
node_name=$REPMGR_NODE_NAME
|
||||
conninfo='user=$REPMGR_USERNAME password=$REPMGR_PASSWORD host=$REPMGR_NODE_NAME dbname=$REPMGR_DATABASE port=$REPMGR_PRIMARY_PORT connect_timeout=$REPMGR_CONNECT_TIMEOUT'
|
||||
failover=automatic
|
||||
promote_command='PGPASSWORD=$REPMGR_PASSWORD repmgr standby promote -f "$REPMGR_CONF_FILE" --log-level DEBUG --verbose'
|
||||
follow_command='PGPASSWORD=$REPMGR_PASSWORD repmgr standby follow -f "$REPMGR_CONF_FILE" -W --log-level DEBUG --verbose'
|
||||
reconnect_attempts=$REPMGR_RECONNECT_ATTEMPTS
|
||||
reconnect_interval=$REPMGR_RECONNECT_INTERVAL
|
||||
log_level=$REPMGR_LOG_LEVEL
|
||||
priority=$REPMGR_NODE_PRIORITY
|
||||
degraded_monitoring_timeout=$REPMGR_DEGRADED_MONITORING_TIMEOUT
|
||||
data_directory=$POSTGRESQL_DATA_DIR
|
||||
async_query_timeout=$REPMGR_MASTER_RESPONSE_TIMEOUT
|
||||
EOF
|
||||
}
|
||||
|
||||
########################
|
||||
# Waits until the primary node responds
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_wait_primary_node() {
|
||||
local return_value=1
|
||||
local -i timeout=300
|
||||
local -i step=10
|
||||
local -i max_tries=$(( timeout / step ))
|
||||
local schemata
|
||||
repmgr_info "Waiting for primary node..."
|
||||
repmgr_debug "Wait for schema $REPMGR_DATABASE.repmgr on $REPMGR_CURRENT_PRIMARY_HOST:$REPMGR_PRIMARY_PORT, will try $max_tries times with $step delay seconds (TIMEOUT=$timeout)"
|
||||
for ((i = 0 ; i <= timeout ; i+=step )); do
|
||||
local query="SELECT 1 FROM information_schema.schemata WHERE catalog_name='$REPMGR_DATABASE' AND schema_name='repmgr'"
|
||||
if ! schemata="$(echo "$query" | NO_ERRORS=true postgresql_execute "$REPMGR_DATABASE" "$REPMGR_USERNAME" "$REPMGR_PASSWORD" "$REPMGR_CURRENT_PRIMARY_HOST" "$REPMGR_PRIMARY_PORT" "-tA")"; then
|
||||
repmgr_debug "Host $REPMGR_CURRENT_PRIMARY_HOST:$REPMGR_PRIMARY_PORT is not accessible"
|
||||
else
|
||||
if [[ $schemata -ne 1 ]]; then
|
||||
repmgr_debug "Schema $REPMGR_DATABASE.repmgr is still not accessible"
|
||||
else
|
||||
repmgr_debug "Schema $REPMGR_DATABASE.repmgr exists!"
|
||||
return_value=0 && break
|
||||
fi
|
||||
fi
|
||||
sleep "$step"
|
||||
done
|
||||
return $return_value
|
||||
}
|
||||
|
||||
########################
|
||||
# Clones data from primary node
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# POSTGRESQL_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_clone_primary() {
|
||||
repmgr_info "Cloning data from primary node..."
|
||||
local -r flags=("-h" "$REPMGR_CURRENT_PRIMARY_HOST" "-p" "$REPMGR_PRIMARY_PORT" "-U" "$REPMGR_USERNAME" "-d" "$REPMGR_DATABASE" "-D" "$POSTGRESQL_DATA_DIR" "standby" "clone" "--fast-checkpoint" "--force")
|
||||
|
||||
PGPASSWORD="$REPMGR_PASSWORD" debug_execute "${REPMGR_BIN_DIR}/repmgr" "${flags[@]}"
|
||||
}
|
||||
|
||||
########################
|
||||
# Rejoin node
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_rewind() {
|
||||
repmgr_info "Rejoining node..."
|
||||
|
||||
repmgr_debug "Deleting old data..."
|
||||
rm -rf "$POSTGRESQL_DATA_DIR" && ensure_dir_exists "$POSTGRESQL_DATA_DIR"
|
||||
|
||||
repmgr_debug "Cloning data from primary node..."
|
||||
repmgr_clone_primary
|
||||
}
|
||||
|
||||
########################
|
||||
# Register a node as primary
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_register_primary() {
|
||||
repmgr_info "Registering Primary..."
|
||||
local -r flags=("-f" "$REPMGR_CONF_FILE" "master" "register" "--force")
|
||||
|
||||
debug_execute "${REPMGR_BIN_DIR}/repmgr" "${flags[@]}"
|
||||
}
|
||||
|
||||
########################
|
||||
# Unregister secondary node
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_unregister_standby() {
|
||||
repmgr_info "Unregistering secondary node..."
|
||||
|
||||
echo "DELETE FROM repmgr.nodes WHERE conninfo LIKE '%host=$REPMGR_NODE_NETWORK_NAME%'" | postgresql_execute "$REPMGR_DATABASE" "$REPMGR_USERNAME" "$REPMGR_PASSWORD" "$REPMGR_CURRENT_PRIMARY_HOST" "$REPMGR_PRIMARY_PORT"
|
||||
}
|
||||
|
||||
########################
|
||||
# Resgister a node as secondary
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_register_standby() {
|
||||
repmgr_info "Registering Standby node..."
|
||||
local -r flags=("-f" "$REPMGR_CONF_FILE" "standby" "register" "--force")
|
||||
|
||||
debug_execute "${REPMGR_BIN_DIR}/repmgr" "${flags[@]}"
|
||||
}
|
||||
|
||||
########################
|
||||
# Initialize repmgr service
|
||||
# Globals:
|
||||
# REPMGR_*
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
#########################
|
||||
repmgr_initialize() {
|
||||
repmgr_debug "Node ID: $(repmgr_get_node_id), Rol: $REPMGR_ROLE, Primary Node: $REPMGR_CURRENT_PRIMARY_HOST"
|
||||
repmgr_info "Initializing Repmgr..."
|
||||
|
||||
if [[ "$REPMGR_ROLE" = "standby" ]]; then
|
||||
repmgr_wait_primary_node || exit 1
|
||||
# TODO: better way to detect it's a 1st boot
|
||||
if [[ ! -f "$POSTGRESQL_CONF_FILE" ]] || ! is_boolean_yes "$REPMGR_SWITCH_ROLE"; then
|
||||
repmgr_clone_primary
|
||||
else
|
||||
repmgr_rewind
|
||||
fi
|
||||
fi
|
||||
postgresql_initialize
|
||||
# Allow remote connections, required to register primary and standby nodes
|
||||
postgresql_enable_remote_connections
|
||||
# Configure port and restrict access to PostgreSQL (MD5)
|
||||
postgresql_set_property "port" "$POSTGRESQL_PORT_NUMBER"
|
||||
postgresql_restrict_pghba
|
||||
if [[ "$REPMGR_ROLE" = "primary" ]]; then
|
||||
repmgr_create_repmgr_user
|
||||
repmgr_create_repmgr_db
|
||||
# Restart PostgreSQL
|
||||
postgresql_stop
|
||||
postgresql_start_bg
|
||||
repmgr_register_primary
|
||||
else
|
||||
postgresql_start_bg
|
||||
repmgr_unregister_standby
|
||||
repmgr_register_standby
|
||||
fi
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load libraries
|
||||
. /libfs.sh
|
||||
. /libpostgresql.sh
|
||||
|
||||
. /librepmgr.sh
|
||||
|
||||
# Load PostgreSQL & repmgr environment variables
|
||||
eval "$(repmgr_env)"
|
||||
eval "$(postgresql_env)"
|
||||
|
||||
for dir in "$POSTGRESQL_INITSCRIPTS_DIR" "$POSTGRESQL_TMP_DIR" "$POSTGRESQL_LOG_DIR" "$POSTGRESQL_CONF_DIR" "${POSTGRESQL_CONF_DIR}/conf.d" "$POSTGRESQL_VOLUME_DIR" "$REPMGR_CONF_DIR" "$REPMGR_TMP_DIR"; do
|
||||
ensure_dir_exists "$dir"
|
||||
chmod -R g+rwX "$dir"
|
||||
done
|
||||
|
||||
# Copying events handlers
|
||||
mv /events "$REPMGR_EVENTS_DIR"
|
||||
chmod +x "$REPMGR_EVENTS_DIR"/router.sh "$REPMGR_EVENTS_DIR"/execs/*sh "$REPMGR_EVENTS_DIR"/execs/includes/*sh
|
||||
|
||||
# Redirect all logging to stdout
|
||||
ln -sf /dev/stdout "$POSTGRESQL_LOG_FILE"
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace # Uncomment this line for debugging purpose
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load libraries
|
||||
. /liblog.sh
|
||||
. /libpostgresql.sh
|
||||
. /librepmgr.sh
|
||||
|
||||
# Load PostgreSQL & repmgr environment variables
|
||||
eval "$(repmgr_env)"
|
||||
eval "$(postgresql_env)"
|
||||
|
||||
readonly repmgr_flags=("--pid-file=$REPMGR_PID_FILE" "-f" "$REPMGR_CONF_FILE")
|
||||
readonly repmgr_cmd=$(command -v repmgrd)
|
||||
|
||||
postgresql_start_bg
|
||||
info "** Starting repmgrd **"
|
||||
# TODO: properly test running the container as root
|
||||
if am_i_root; then
|
||||
exec gosu "$POSTGRESQL_DAEMON_USER" "${repmgr_cmd}" "${repmgr_flags[@]}"
|
||||
else
|
||||
exec "${repmgr_cmd}" "${repmgr_flags[@]}"
|
||||
fi
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Bitnami PostgreSQL setup
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
#set -o xtrace
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
# shellcheck disable=SC1091
|
||||
|
||||
# Load Libraries
|
||||
. /libpostgresql.sh
|
||||
. /librepmgr.sh
|
||||
|
||||
# Load PostgreSQL & repmgr environment variables
|
||||
eval "$(repmgr_env)"
|
||||
eval "$(postgresql_env)"
|
||||
|
||||
# Ensure PostgreSQL & repmgr environment variables settings are valid
|
||||
repmgr_validate
|
||||
postgresql_validate
|
||||
|
||||
# Set the environment variables for the node's role
|
||||
eval "$(repmgr_set_role)"
|
||||
|
||||
# Ensure PostgreSQL is stopped when this script ends.
|
||||
trap "postgresql_stop" EXIT
|
||||
# Ensure 'daemon' user exists when running as 'root'
|
||||
am_i_root && ensure_user_exists "$POSTGRESQL_DAEMON_USER" "$POSTGRESQL_DAEMON_GROUP"
|
||||
# Prepare PostgreSQL default configuration
|
||||
repmgr_postgresql_configuration
|
||||
# Prepare repmgr configuration
|
||||
repmgr_generate_repmgr_config
|
||||
# Initialize PostgreSQL & repmgr
|
||||
repmgr_initialize
|
||||
|
|
@ -0,0 +1,547 @@
|
|||
# What is PostgreSQL with Replication Manager?
|
||||
|
||||
> [PostgreSQL](https://www.postgresql.org) is an open source object-relational database known for its reliability and data integrity. This solution includes [repmgr](https://repmgr.org), an open-source tool for managing replication and failover on PostgreSQL clusters.
|
||||
|
||||
# TL;DR;
|
||||
|
||||
```bash
|
||||
$ docker run --name postgresql-repmgr bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
```bash
|
||||
$ curl -sSL https://raw.githubusercontent.com/bitnami/bitnami-docker-postgresql-repmgr/master/docker-compose.yml > docker-compose.yml
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
# Why use Bitnami Images?
|
||||
|
||||
* Bitnami closely tracks upstream source changes and promptly publishes new versions of this image using our automated systems.
|
||||
* With Bitnami images the latest bug fixes and features are available as soon as possible.
|
||||
* Bitnami containers, virtual machines and cloud images use the same components and configuration approach - making it easy to switch between formats based on your project needs.
|
||||
* All our images are based on [minideb](https://github.com/bitnami/minideb) a minimalist Debian based container image which gives you a small base container image and the familiarity of a leading linux distribution.
|
||||
* All Bitnami images available in Docker Hub are signed with [Docker Content Trust (DTC)](https://docs.docker.com/engine/security/trust/content_trust/). You can use `DOCKER_CONTENT_TRUST=1` to verify the integrity of the images.
|
||||
* Bitnami container images are released daily with the latest distribution packages available.
|
||||
|
||||
> This [CVE scan report](https://quay.io/repository/bitnami/postgresql-repmgr?tab=tags) contains a security report with all open CVEs. To get the list of actionable security issues, find the "latest" tag, click the vulnerability report link under the corresponding "Security scan" field and then select the "Only show fixable" filter on the next page.
|
||||
|
||||
# Why use a non-root container?
|
||||
|
||||
Non-root container images add an extra layer of security and are generally recommended for production environments. However, because they run as a non-root user, privileged tasks are typically off-limits. Learn more about non-root containers [in our docs](https://docs.bitnami.com/containers/how-to/work-with-non-root-containers/).
|
||||
|
||||
# How to deploy Postgresql-repmgr in Kubernetes?
|
||||
|
||||
Deploying Bitnami applications as Helm Charts is the easiest way to get started with our applications on Kubernetes. Read more about the installation in the [Bitnami PostgreSQL HA Chart GitHub repository](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha).
|
||||
|
||||
Bitnami containers can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters.
|
||||
|
||||
# Supported tags and respective `Dockerfile` links
|
||||
|
||||
> NOTE: Debian 8 images have been deprecated in favor of Debian 9 images. Bitnami will not longer publish new Docker images based on Debian 8.
|
||||
|
||||
Learn more about the Bitnami tagging policy and the difference between rolling tags and immutable tags [in our documentation page](https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/).
|
||||
|
||||
|
||||
* [`4-centos-7`, `-centos-7-r0` (4/centos-7/Dockerfile)](https://github.com/bitnami/bitnami-docker-postgresql-repmgr/blob/-centos-7-r0/4/centos-7/Dockerfile)
|
||||
* [`4-debian-9`, `4.0.3-debian-9-r0`, `4`, `4.0.3`, `4.0.3-r0`, `latest` (4/debian-9/Dockerfile)](https://github.com/bitnami/bitnami-docker-postgresql-repmgr/blob/4.0.3-debian-9-r0/4/debian-9/Dockerfile)
|
||||
|
||||
Subscribe to project updates by watching the [bitnami/postgresql-repmgr GitHub repo](https://github.com/bitnami/bitnami-docker-postgresql-repmgr).
|
||||
|
||||
# Get this image
|
||||
|
||||
The recommended way to get the Bitnami PostgreSQL with Replication Manager Docker Image is to pull the prebuilt image from the [Docker Hub Registry](https://hub.docker.com/r/bitnami/postgresql-repmgr).
|
||||
|
||||
```bash
|
||||
$ docker pull bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
To use a specific version, you can pull a versioned tag. You can view the [list of available versions](https://hub.docker.com/r/bitnami/postgresql-repmgr/tags/) in the Docker Hub Registry.
|
||||
|
||||
```bash
|
||||
$ docker pull bitnami/postgresql-repmgr:[TAG]
|
||||
```
|
||||
|
||||
If you wish, you can also build the image yourself.
|
||||
|
||||
```bash
|
||||
$ docker build -t bitnami/postgresql-repmgr:latest 'https://github.com/bitnami/bitnami-docker-postgresql-repmgr.git#master:4/debian-9'
|
||||
```
|
||||
|
||||
# Persisting your application
|
||||
|
||||
If you remove the container all your data will be lost, and the next time you run the image the database will be reinitialized. To avoid this loss of data, you should mount a volume that will persist even after the container is removed.
|
||||
|
||||
For persistence you should mount a directory at the `/bitnami/postgresql` path. If the mounted directory is empty, it will be initialized on the first run.
|
||||
|
||||
```bash
|
||||
$ docker run \
|
||||
-v /path/to/postgresql-repmgr-persistence:/bitnami/postgresql \
|
||||
bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
The [`docker-compose.yml`](https://github.com/bitnami/bitnami-docker-postgresql/blob/master/docker-compose.yml) file present in this repository already configures persistence.
|
||||
|
||||
# Connecting to other containers
|
||||
|
||||
Using [Docker container networking](https://docs.docker.com/engine/userguide/networking/), a PostgreSQL server running inside a container can easily be accessed by your application containers and vice-versa.
|
||||
|
||||
Containers attached to the same network can communicate with each other using the container name as the hostname.
|
||||
|
||||
## Using the Command Line
|
||||
|
||||
In this example, we will create a PostgreSQL client instance that will connect to the server instance that is running on the same docker network as the client.
|
||||
|
||||
### Step 1: Create a network
|
||||
|
||||
```bash
|
||||
$ docker network create my-network --driver bridge
|
||||
```
|
||||
|
||||
### Step 2: Launch the postgresql-repmgr container within your network
|
||||
|
||||
Use the `--network <NETWORK>` argument to the `docker run` command to attach the container to the `my-network` network.
|
||||
|
||||
```bash
|
||||
$ docker run --detach --rm --name pg-0 \
|
||||
--network my-network \
|
||||
--env REPMGR_PARTNER_NODES=pg-0 \
|
||||
--env REPMGR_NODE_NAME=pg-0 \
|
||||
--env REPMGR_NODE_NETWORK_NAME=pg-0 \
|
||||
--env REPMGR_PRIMARY_HOST=pg-0 \
|
||||
--env REPMGR_PASSWORD=repmgrpass \
|
||||
--env POSTGRESQL_PASSWORD=secretpass \
|
||||
bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
### Step 3: Launch your PostgreSQL client instance
|
||||
|
||||
Finally we create a new container instance to launch the PostgreSQL client and connect to the server created in the previous step:
|
||||
|
||||
```bash
|
||||
$ docker run -it --rm \
|
||||
--network my-network \
|
||||
bitnami/postgresql:10 \
|
||||
psql -h pg-0 -U postgres
|
||||
```
|
||||
|
||||
## Using Docker Compose
|
||||
|
||||
When not specified, Docker Compose automatically sets up a new network and attaches all deployed services to that network. However, we will explicitly define a new `bridge` network named `my-network`. In this example we assume that you want to connect to the PostgreSQL server from your own custom application image which is identified in the following snippet by the service name `myapp`.
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
networks:
|
||||
my-network:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
pg-0:
|
||||
image: 'bitnami/postgresql-repmgr:latest'
|
||||
networks:
|
||||
- my-network
|
||||
environment:
|
||||
- POSTGRESQL_PASSWORD=custompassword
|
||||
- REPMGR_PASSWORD=repmgrpassword
|
||||
- REPMGR_PRIMARY_HOST=pg-0
|
||||
- REPMGR_NODE_NETWORK_NAME=pg-0
|
||||
- REPMGR_NODE_NAME=pg-0
|
||||
- EPMGR_PARTNER_NODES=pg-0
|
||||
myapp:
|
||||
image: 'YOUR_APPLICATION_IMAGE'
|
||||
networks:
|
||||
- my-network
|
||||
```
|
||||
|
||||
> **IMPORTANT**:
|
||||
>
|
||||
> 1. Please update the **YOUR_APPLICATION_IMAGE_** placeholder in the above snippet with your application image
|
||||
> 2. In your application container, use the hostname `pg-0` to connect to the PostgreSQL server
|
||||
|
||||
Launch the containers using:
|
||||
|
||||
```bash
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
# Configuration
|
||||
|
||||
## Initializing a new instance
|
||||
|
||||
When the container is executed for the first time, it will execute the files with extensions `.sh`, `.sql` and `.sql.gz` located at `/docker-entrypoint-initdb.d`.
|
||||
|
||||
In order to have your custom files inside the docker image you can mount them as a volume.
|
||||
|
||||
## Setting the root and repmgr passwords on first run
|
||||
|
||||
In the above commands you may have noticed the use of the `POSTGRESQL_PASSWORD` and `REPMGR_PASSWORD` environment variables. Passing the `POSTGRESQL_PASSWORD` environment variable when running the image for the first time will set the password of the `postgres` user to the value of `POSTGRESQL_PASSWORD` (or the content of the file specified in `POSTGRESQL_PASSWORD_FILE`). In the same way, passing the `REPMGR_PASSWORD` environment variable sets the password of the `repmgr` user to the value of `REPMGR_PASSWORD` (or the content of the file specified in `REPMGR_PASSWORD_FILE`).
|
||||
|
||||
```bash
|
||||
$ docker run --name pg-0 --env REPMGR_PASSWORD=repmgrpass --env POSTGRESQL_PASSWORD=secretpass bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
or by modifying the [`docker-compose.yml`](https://github.com/bitnami/bitnami-docker-postgresql-repmgr/blob/master/docker-compose.yml) file present in this repository:
|
||||
|
||||
```diff
|
||||
...
|
||||
services:
|
||||
pg-0:
|
||||
...
|
||||
environment:
|
||||
- - POSTGRESQL_PASSWORD=adminpassword
|
||||
+ - POSTGRESQL_PASSWORD=password123
|
||||
- - REPMGR_PASSWORD=repmgrpassword
|
||||
+ - REPMGR_PASSWORD=password123
|
||||
...
|
||||
pg-1:
|
||||
...
|
||||
environment:
|
||||
- - POSTGRESQL_PASSWORD=adminpassword
|
||||
+ - POSTGRESQL_PASSWORD=password123
|
||||
- - REPMGR_PASSWORD=repmgrpassword
|
||||
+ - REPMGR_PASSWORD=password123
|
||||
...
|
||||
```
|
||||
|
||||
**Note!**
|
||||
Both `postgres` and `repmgr` users are superusers and have full administrative access to the PostgreSQL database.
|
||||
|
||||
Refer to [Creating a database user on first run](#creating-a-database-user-on-first-run) if you want to set an unprivileged user and a password for the `postgres` user.
|
||||
|
||||
## Creating a database on first run
|
||||
|
||||
By passing the `POSTGRESQL_DATABASE` environment variable when running the image for the first time, a database will be created. This is useful if your application requires that a database already exists, saving you from having to manually create the database using the PostgreSQL client.
|
||||
|
||||
```bash
|
||||
$ docker run --name pg-0 --env POSTGRESQL_DATABASE=my_database bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
## Creating a database user on first run
|
||||
|
||||
You can also create a restricted database user that only has permissions for the database created with the [`POSTGRESQL_DATABASE`](#creating-a-database-on-first-run) environment variable. To do this, provide the `POSTGRESQL_USERNAME` environment variable.
|
||||
|
||||
```bash
|
||||
$ docker run --name pg-0 --env POSTGRESQL_USERNAME=my_user --env POSTGRESQL_PASSWORD=password123 --env POSTGRESQL_DATABASE=my_database bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
The [`docker-compose.yml`](https://github.com/bitnami/bitnami-docker-postgresql/blob/master/docker-compose.yml) file present in this repository already configures this setup.
|
||||
|
||||
**Note!**
|
||||
When `POSTGRESQL_USERNAME` is specified, the `postgres` user is not assigned a password and as a result you cannot login remotely to the PostgreSQL server as the `postgres` user. If you still want to have access with the user `postgres`, please set the `POSTGRESQL_POSTGRES_PASSWORD` environment variable (or the content of the file specified in `POSTGRESQL_POSTGRES_PASSWORD_FILE`).
|
||||
|
||||
## Setting up a HA PostgreSQL cluster with streaming replication and repmgr
|
||||
|
||||
A HA PostgreSQL cluster with [Streaming replication](https://www.postgresql.org/docs/10/warm-standby.html#STREAMING-REPLICATION) and [repmgr](https://repmgr.org) can easily be setup with the Bitnami PostgreSQL with Replication Manager Docker Image using the following environment variables:
|
||||
|
||||
- `POSTGRESQL_PASSWORD`: Password for `postgres` user. No defaults.
|
||||
- `POSTGRESQL_PASSWORD_FILE`: Path to a file that contains the `postgres` user password. This will override the value specified in `POSTGRESQL_PASSWORD`. No defaults.
|
||||
- `REPMGR_USERNAME`: Username for `repmgr` user. Defaults to `repmgr`.
|
||||
- `REPMGR_PASSWORD_FILE`: Path to a file that contains the `repmgr` user password. This will override the value specified in `REPMGR_PASSWORD`. No defaults.
|
||||
- `REPMGR_PASSWORD`: Password for `repmgr` user. No defaults.
|
||||
- `REPMGR_PRIMARY_HOST`: Hostname of the initial primary node. No defaults.
|
||||
- `REPMGR_PARTNER_NODES`: Comma separated list of partner nodes in the cluster. No defaults.
|
||||
- `REPMGR_NODE_NAME`: Node name. No defaults.
|
||||
- `REPMGR_NODE_NETWORK_NAME`: Node hostname. No defaults.
|
||||
|
||||
In a HA PostgreSQL cluster you can have one primary and zero or more standby nodes. The primary node is in read-write mode, while the standby nodes are in read-only mode. For best performance its advisable to limit the reads to the standby nodes.
|
||||
|
||||
### Step 1: Create a network
|
||||
|
||||
```bash
|
||||
$ docker network create my-network --driver bridge
|
||||
```
|
||||
|
||||
### Step 2: Create the initial primary node
|
||||
|
||||
The first step is to start the initial primary node:
|
||||
|
||||
```bash
|
||||
$ docker run --detach --name pg-0 \
|
||||
--network my-network \
|
||||
--env REPMGR_PARTNER_NODES=pg-0,pg-1 \
|
||||
--env REPMGR_NODE_NAME=pg-0 \
|
||||
--env REPMGR_NODE_NETWORK_NAME=pg-0 \
|
||||
--env REPMGR_PRIMARY_HOST=pg-0 \
|
||||
--env REPMGR_PASSWORD=repmgrpass \
|
||||
--env POSTGRESQL_PASSWORD=secretpass \
|
||||
bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
### Step 3: Create a standby node
|
||||
|
||||
Next we start a standby node:
|
||||
|
||||
```bash
|
||||
$ docker run --detach --name pg-1 \
|
||||
--network my-network \
|
||||
--env REPMGR_PARTNER_NODES=pg-0,pg-1 \
|
||||
--env REPMGR_NODE_NAME=pg-1 \
|
||||
--env REPMGR_NODE_NETWORK_NAME=pg-1 \
|
||||
--env REPMGR_PRIMARY_HOST=pg-0 \
|
||||
--env REPMGR_PASSWORD=repmgrpass \
|
||||
--env POSTGRESQL_PASSWORD=secretpass \
|
||||
bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
With these three commands you now have a two node PostgreSQL primary-standby streaming replication cluster up and running. You can scale the cluster by adding/removing standby nodes without incurring any downtime.
|
||||
|
||||
> **Note**: The cluster replicates the primary in its entirety, which includes all users and databases.
|
||||
|
||||
If the master goes down, **repmgr** will ensure any of the standby nodes takes the primary role, guaranteeing high availability.
|
||||
|
||||
> **Note**: The configuration of the other nodes in the cluster needs to be updated so that they are aware of them. This would require you to restart the old nodes adapting the `REPMGR_PARTNER_NODES` environment variable.
|
||||
|
||||
With Docker Compose the HA PostgreSQL cluster can be setup using the [`docker-compose.yml`](https://github.com/bitnami/bitnami-docker-postgresql/blob/master/docker-compose.yml) file present in this repository:
|
||||
|
||||
```bash
|
||||
$ curl -sSL https://raw.githubusercontent.com/bitnami/bitnami-docker-postgresql-repmgr/master/docker-compose.yml > docker-compose.yml
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
## Configuration file
|
||||
|
||||
The image looks for a `postgresql.conf` file in `/opt/bitnami/postgresql/conf/`. You can mount a volume at `/bitnami/postgresql/conf/` and copy/edit the `postgresql.conf` file in the `/path/to/postgresql-persistence/conf/`. The default configurations will be populated to the `conf/` directory if it's empty.
|
||||
|
||||
```
|
||||
/path/to/postgresql-persistence/conf/
|
||||
└── postgresql.conf
|
||||
|
||||
0 directories, 1 file
|
||||
```
|
||||
|
||||
As the PostgreSQL with Replication manager image is non-root, you need to set the proper permissions to the mounted directory in your host:
|
||||
|
||||
```bash
|
||||
$ sudo chgrp -R root /path/to/postgresql-persistence/conf/
|
||||
$ sudo chmod -R g+rwX /path/to/postgresql-persistence/conf/
|
||||
```
|
||||
|
||||
### Step 1: Run the PostgreSQL image
|
||||
|
||||
Run the PostgreSQL image, mounting a directory from your host.
|
||||
|
||||
```bash
|
||||
$ docker run --name pg-0 \
|
||||
-v /path/to/postgresql-persistence/conf/:/bitnami/postgresql/conf/ \
|
||||
bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
or using Docker Compose:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
pg-0:
|
||||
image: bitnami/postgresql-repmgr:latest
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- /path/to/postgresql-persistence/conf/:/bitnami/postgresql/conf/
|
||||
pg-1:
|
||||
image: bitnami/postgresql-repmgr:latest
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- /path/to/postgresql-persistence/conf/:/bitnami/postgresql/conf/
|
||||
```
|
||||
|
||||
### Step 2: Edit the configuration
|
||||
|
||||
Edit the configuration on your host using your favorite editor.
|
||||
|
||||
```bash
|
||||
vi /path/to/postgresql-persistence/conf/postgresql.conf
|
||||
```
|
||||
|
||||
### Step 3: Restart PostgreSQL
|
||||
|
||||
After changing the configuration, restart your PostgreSQL container for changes to take effect.
|
||||
|
||||
```bash
|
||||
$ docker restart pg-0
|
||||
```
|
||||
|
||||
or using Docker Compose:
|
||||
|
||||
```bash
|
||||
$ docker-compose restart pg-0
|
||||
$ docker-compose restart pg-1
|
||||
```
|
||||
|
||||
Refer to the [server configuration](http://www.postgresql.org/docs/10/static/runtime-config.html) manual for the complete list of configuration options.
|
||||
|
||||
### Allow settings to be loaded from files other than the default `postgresql.conf`
|
||||
|
||||
Apart of using a custom `postgresql.conf`, you can include files ending in `.conf` from the `conf.d` directory in the volume at `/bitnami/postgresql/conf/`.
|
||||
For this purpose, the default `postgresql.conf` contains the following section:
|
||||
|
||||
```
|
||||
#------------------------------------------------------------------------------
|
||||
# CONFIG FILE INCLUDES
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# These options allow settings to be loaded from files other than the
|
||||
# default postgresql.conf.
|
||||
|
||||
include_dir = 'conf.d' # Include files ending in '.conf' from directory 'conf.d'
|
||||
```
|
||||
|
||||
In your host, you should create the extended configuration file under the `conf.d` directory:
|
||||
|
||||
```bash
|
||||
mkdir -p /path/to/postgresql-persistence/conf/conf.d/
|
||||
vi /path/to/postgresql-persistence/conf/conf.d/extended.conf
|
||||
```
|
||||
|
||||
If you are using your custom `postgresql.conf`, you should create (or uncomment) the above section in your config file, in this case the `/path/to/postgresql-persistence/conf/` structure should be something like
|
||||
|
||||
```
|
||||
/path/to/postgresql-persistence/conf/
|
||||
├── conf.d
|
||||
│ └── extended.conf
|
||||
└── postgresql.conf
|
||||
|
||||
1 directory, 2 files
|
||||
```
|
||||
|
||||
|
||||
## Environment variables aliases
|
||||
|
||||
Please see the list of environment variable available in the Bitnami PostgreSQL with Replication Manager container in the next table:
|
||||
|
||||
| Environment Variable | Default value |
|
||||
| :----------------------------------- | :--------------------------------- |
|
||||
| REPMGR_NODE_ID | `nil` |
|
||||
| REPMGR_NODE_NAME | `nil` |
|
||||
| REPMGR_NODE_NETWORK_NAME | `nil` |
|
||||
| REPMGR_NODE_PRIORITY | `100` |
|
||||
| REPMGR_PARTNER_NODES | `nil` |
|
||||
| REPMGR_PRIMARY_HOST | `nil` |
|
||||
| REPMGR_PRIMARY_PORT | `5432` |
|
||||
| REPMGR_NODE_ID | `nil` |
|
||||
| REPMGR_PORT_NUMBER | `5432` |
|
||||
| REPMGR_LOG_LEVEL | `NOTICE` |
|
||||
| REPMGR_START_OPTIONS | `nil` |
|
||||
| REPMGR_CONNECT_TIMEOUT | `5` |
|
||||
| REPMGR_RECONNECT_ATTEMPTS | `3` |
|
||||
| REPMGR_RECONNECT_INTERVAL | `5` |
|
||||
| REPMGR_USE_REPLICATION_SLOTS | `1` |
|
||||
| REPMGR_MASTER_RESPONSE_TIMEOUT | `20` |
|
||||
| REPMGR_DEGRADED_MONITORING_TIMEOUT | `5` |
|
||||
| REPMGR_USERNAME | `repmgr` |
|
||||
| REPMGR_DATABASE | `repmgr` |
|
||||
| REPMGR_PASSWORD | `nil` |
|
||||
| REPMGR_PASSWORD_FILE | `nil` |
|
||||
| POSTGRESQL_USERNAME | `postgres` |
|
||||
| POSTGRESQL_DATABASE | `nil` |
|
||||
| POSTGRESQL_PASSWORD | `nil` |
|
||||
| POSTGRESQL_PASSWORD_FILE | `nil` |
|
||||
| POSTGRESQL_POSTGRES_PASSWORD | `nil` |
|
||||
| POSTGRESQL_POSTGRES_PASSWORD_FILE | `nil` |
|
||||
| POSTGRESQL_PORT_NUMBER | `5432` |
|
||||
| POSTGRESQL_INITDB_ARGS | `nil` |
|
||||
|
||||
# Logging
|
||||
|
||||
The Bitnami PostgreSQL with Replication Manager Docker image sends the container logs to `stdout`. To view the logs:
|
||||
|
||||
```bash
|
||||
$ docker logs pg-0
|
||||
```
|
||||
|
||||
You can configure the containers [logging driver](https://docs.docker.com/engine/admin/logging/overview/) using the `--log-driver` option if you wish to consume the container logs differently. In the default configuration docker uses the `json-file` driver.
|
||||
|
||||
# Maintenance
|
||||
|
||||
## Upgrade this image
|
||||
|
||||
Bitnami provides up-to-date versions of PostgreSQL with Replication Manager, including security patches, soon after they are made upstream. We recommend that you follow these steps to upgrade your container.
|
||||
|
||||
### Step 1: Get the updated image
|
||||
|
||||
```bash
|
||||
$ docker pull bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
or if you're using Docker Compose, update the value of the image property to `bitnami/postgresql-repmgr:latest`.
|
||||
|
||||
### Step 2: Stop the running container
|
||||
|
||||
Stop the currently running container using the command
|
||||
|
||||
```bash
|
||||
$ docker stop pg-0
|
||||
```
|
||||
|
||||
or using Docker Compose:
|
||||
|
||||
```bash
|
||||
$ docker-compose stop pg-0
|
||||
$ docker-compose stop pg-1
|
||||
```
|
||||
|
||||
Next, take a snapshot of the persistent volume `/path/to/postgresql-persistence` using:
|
||||
|
||||
```bash
|
||||
$ rsync -a /path/to/postgresql-persistence /path/to/postgresql-persistence.bkp.$(date +%Y%m%d-%H.%M.%S)
|
||||
```
|
||||
|
||||
### Step 3: Remove the currently running container
|
||||
|
||||
```bash
|
||||
$ docker rm -v pg-0
|
||||
```
|
||||
|
||||
or using Docker Compose:
|
||||
|
||||
```bash
|
||||
$ docker-compose rm -v pg-0
|
||||
$ docker-compose rm -v pg-1
|
||||
```
|
||||
|
||||
### Step 4: Run the new image
|
||||
|
||||
Re-create your container from the new image.
|
||||
|
||||
```bash
|
||||
$ docker run --name pg-0 bitnami/postgresql-repmgr:latest
|
||||
```
|
||||
|
||||
or using Docker Compose:
|
||||
|
||||
```bash
|
||||
$ docker-compose up pg-0
|
||||
$ docker-compose up pg-1
|
||||
```
|
||||
|
||||
# Contributing
|
||||
|
||||
We'd love for you to contribute to this container. You can request new features by creating an [issue](https://github.com/bitnami/bitnami-docker-postgresql-repmgr/issues), or submit a [pull request](https://github.com/bitnami/bitnami-docker-postgresql-repmgr/pulls) with your contribution.
|
||||
|
||||
# Issues
|
||||
|
||||
If you encountered a problem running this container, you can file an [issue](https://github.com/bitnami/bitnami-docker-postgresql-repmgr/issues). For us to provide better support, be sure to include the following information in your issue:
|
||||
|
||||
- Host OS and version
|
||||
- Docker version (`docker version`)
|
||||
- Output of `docker info`
|
||||
- Version of this container
|
||||
- The command you used to run the container, and any relevant output you saw (masking any sensitive information)
|
||||
|
||||
# License
|
||||
|
||||
Copyright 2019 Bitnami
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
version: '2'
|
||||
services:
|
||||
pg-0:
|
||||
image: bitnami/postgresql-repmgr:4
|
||||
ports:
|
||||
- 5432
|
||||
volumes:
|
||||
- pg_0_data:/bitnami/postgresql
|
||||
environment:
|
||||
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
|
||||
- POSTGRESQL_USERNAME=customuser
|
||||
- POSTGRESQL_PASSWORD=custompassword
|
||||
- POSTGRESQL_DATABASE=customdatabase
|
||||
- REPMGR_PASSWORD=repmgrpassword
|
||||
- REPMGR_PRIMARY_HOST=pg-0
|
||||
- REPMGR_PARTNER_NODES=pg-0,pg-1
|
||||
- REPMGR_NODE_NAME=pg-0
|
||||
- REPMGR_NODE_NETWORK_NAME=pg-0
|
||||
pg-1:
|
||||
image: bitnami/postgresql-repmgr:4
|
||||
ports:
|
||||
- 5432
|
||||
volumes:
|
||||
- pg_1_data:/bitnami/postgresql
|
||||
environment:
|
||||
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
|
||||
- POSTGRESQL_USERNAME=customuser
|
||||
- POSTGRESQL_PASSWORD=custompassword
|
||||
- POSTGRESQL_DATABASE=customdatabase
|
||||
- REPMGR_PASSWORD=repmgrpassword
|
||||
- REPMGR_PRIMARY_HOST=pg-0
|
||||
- REPMGR_PARTNER_NODES=pg-0,pg-1
|
||||
- REPMGR_NODE_NAME=pg-1
|
||||
- REPMGR_NODE_NETWORK_NAME=pg-1
|
||||
volumes:
|
||||
pg_0_data:
|
||||
driver: local
|
||||
pg_1_data:
|
||||
driver: local
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
## This is test deployment for Kubernetes platforms.
|
||||
## This is _not_ intended to be used in producction.
|
||||
##
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: test-postgresql-repmgr
|
||||
labels:
|
||||
app.kubernetes.io/name: test-postgresql-repmgr
|
||||
spec:
|
||||
serviceName: test-postgresql-repmgr-headless
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: test-postgresql-repmgr
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: test-postgresql-repmgr
|
||||
spec:
|
||||
containers:
|
||||
- image: bitnami/postgresql-repmgr
|
||||
name: postgresql-repmgr
|
||||
env:
|
||||
- name: POSTGRESQL_POSTGRES_PASSWORD
|
||||
value: "adminpassword"
|
||||
- name: POSTGRESQL_USERNAME
|
||||
value: "customuser"
|
||||
- name: POSTGRESQL_PASSWORD
|
||||
value: "custompassword"
|
||||
- name: POSTGRESQL_DATABASE
|
||||
value: "customdatabase"
|
||||
- name: REPMGR_PASSWORD
|
||||
value: "repmgrpassword"
|
||||
- name: REPMGR_PRIMARY_HOST
|
||||
value: "test-postgresql-repmgr-0"
|
||||
- name: REPMGR_NODE_NAME
|
||||
value: "test-postgresql-repmgr-0"
|
||||
- name: REPMGR_NODE_NETWORK_NAME
|
||||
value: "test-postgresql-repmgr-0"
|
||||
- name: REPMGR_PARTNER_NODES
|
||||
value: "test-postgresql-repmgr-0"
|
||||
ports:
|
||||
- name: postgresql
|
||||
containerPort: 5432
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: test-postgresql-repmgr
|
||||
labels:
|
||||
app.kubernetes.io/name: test-postgresql-repmgr
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
targetPort: postgresql
|
||||
selector:
|
||||
app.kubernetes.io/name: test-postgresql-repmgr
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: test-postgresql-repmgr-headless
|
||||
labels:
|
||||
app.kubernetes.io/name: test-postgresql-repmgr
|
||||
spec:
|
||||
ClusterIP: None
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
protocol: TCP
|
||||
targetPort: postgresql
|
||||
selector:
|
||||
app.kubernetes.io/name: test-postgresql-repmgr
|
||||
Loading…
Reference in New Issue