-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upgrade: Container upgrades existing data on start
Postgres will not automatically upgrade existing data when moving to a different major version. These changes detect existing data and compare their major versions to see if an upgrade is required. If the upgrade is required then the correct tooling for the existing data is installed and `pg_upgrade` is run. Also part of this PR is the restructure of the data volume so that a versioned sub-directory is used instead of the root of the mount. This means that as you upgrade major versions you will keep a version of your data which can be used. Signed-off-by: Rich Bayliss <[email protected]> Change-type: minor
- Loading branch information
Rich Bayliss
committed
Apr 8, 2020
1 parent
67d5577
commit 59717dc
Showing
2 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#!/bin/bash | ||
|
||
set -e | ||
|
||
# creates a backup archive of the dir $1... | ||
backup_data () { | ||
gosu postgres tar --exclude backup.tar.gz -zcf /tmp/backup.tar.gz -C "$1" . | ||
mv /tmp/backup.tar.gz "${1}/backup.tar.gz" | ||
} | ||
|
||
# copies all the data from $1 to $2... | ||
restore_volume () { | ||
echo "=== Restoring data volume structure" | ||
find "$1" -maxdepth 1 \ | ||
! -path "$1" \ | ||
| xargs mv -t "$2" | ||
} | ||
|
||
# install the old version of Postgres, required when doing an upgrade... | ||
install_old_version () { | ||
if [ ! -d "/usr/lib/postgresql/$1/bin" ]; then | ||
sed -i 's/$/ '"$1"'/' /etc/apt/sources.list.d/pgdg.list | ||
|
||
apt-get -qq update \ | ||
&& apt-get install -qq -y --no-install-recommends \ | ||
"postgresql-$1" \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
fi | ||
} | ||
|
||
# creates a dir at $1 which is valid for Postgres data to live in... | ||
create_postgres_data_dir () { | ||
echo "=== Creating data dir $1" | ||
mkdir -p "$1" | ||
chmod 700 "$1" | ||
chown -R postgres:postgres "$1" | ||
} | ||
|
||
# echo a message and die... | ||
die_with_message () { | ||
echo "[FATAL] $1" | ||
exit 2 | ||
} | ||
|
||
# check that this is running from within a valid Postgres container environment... | ||
[ ! -z "$PG_MAJOR" ] || die_with_message "Not a compatible Postgres runtime environment" | ||
|
||
# set our target version... | ||
TARGET_VERSION="$PG_MAJOR" | ||
|
||
# ensure we have a versioned data directory... | ||
[ -d "${PGDATA}/${TARGET_VERSION}" ] || create_postgres_data_dir "${PGDATA}/${TARGET_VERSION}" | ||
|
||
# check for Postgres data in the root of the $PGDATA directory... | ||
if [ -f "${PGDATA}/PG_VERSION" ]; then | ||
SOURCE_VERSION="$(cat ${PGDATA}/PG_VERSION)" | ||
|
||
# does the data need upgrading... | ||
if [ "$SOURCE_VERSION" -ne "$TARGET_VERSION" ]; then | ||
echo "=== Upgrading data from v${SOURCE_VERSION} to v${TARGET_VERSION}" | ||
|
||
# define our directories... | ||
PGDATAOLD="${PGDATA}/${SOURCE_VERSION}" | ||
PGDATANEW="${PGDATA}/${TARGET_VERSION}" | ||
PGBINOLD="/usr/lib/postgresql/$SOURCE_VERSION/bin" | ||
PGBINNEW="/usr/lib/postgresql/$TARGET_VERSION/bin" | ||
|
||
echo "=== Installing tools for Postgres v${SOURCE_VERSION}" | ||
install_old_version "$SOURCE_VERSION" | ||
|
||
echo "=== Moving extisting data to ${PGDATAOLD}" | ||
create_postgres_data_dir "${PGDATAOLD}" | ||
find "$PGDATA" -maxdepth 1 \ | ||
! -path "$PGDATA" \ | ||
! -path "$PGDATAOLD*" \ | ||
| xargs mv -t "${PGDATAOLD}" | ||
|
||
trap "restore_volume ${PGDATAOLD} ${PGDATA}" ERR | ||
|
||
echo "=== Initialising new data directory ${PGDATANEW}" | ||
rm -rf "${PGDATANEW}" | ||
create_postgres_data_dir "${PGDATANEW}" | ||
gosu postgres initdb -D "$PGDATANEW" -U "$POSTGRES_USER" $POSTGRES_INITDB_ARGS | ||
|
||
echo "=== Beginning pg_upgrade" | ||
cd /tmp | ||
gosu postgres pg_upgrade \ | ||
-U "$POSTGRES_USER" \ | ||
--old-datadir="$PGDATAOLD" \ | ||
--new-datadir="$PGDATANEW" \ | ||
--old-bindir="$PGBINOLD" \ | ||
--new-bindir="$PGBINNEW" \ | ||
--check | ||
|
||
gosu postgres pg_upgrade \ | ||
-U "$POSTGRES_USER" \ | ||
--old-datadir="$PGDATAOLD" \ | ||
--new-datadir="$PGDATANEW" \ | ||
--old-bindir="$PGBINOLD" \ | ||
--new-bindir="$PGBINNEW" | ||
|
||
echo "=== Restoring configuration files" | ||
cp "${PGDATAOLD}/pg_hba.conf" "${PGDATANEW}/pg_hba.conf" | ||
cp "${PGDATAOLD}/pg_ident.conf" "${PGDATANEW}/pg_ident.conf" | ||
else | ||
echo "=== Moving extisting data to directory "${PGDATA}/${TARGET_VERSION}"" | ||
find "$PGDATA" -maxdepth 1 \ | ||
! -path "$PGDATA" \ | ||
| xargs mv -t "${PGDATA}/${TARGET_VERSION}" | ||
fi | ||
fi | ||
|
||
# set our runtime data directory to the versioned one... | ||
export PGDATA="${PGDATA}/${TARGET_VERSION}" | ||
|
||
# run the existing Postgres entrypoint script... | ||
. /docker-entrypoint.sh | ||
_main "$@" |