Gitlab Omnibus ships with Postgres 9.6. Unfortunately for me, several online references suggest using an external Postgres database container when using the Docker-based release of Gitlab but fail to mention the extremely important requirement: Gitlab only supports the same version of Postgres externally as internally. This fact is buried in the install requirements document, but even there it specifies “9.6 or newer,” but in the case of Docker installs, it should say “9.6 exactly.”
TL;DR:
Run a python script against the v11 dump to remove AS integer
from CREATE SEQUENCE
statements, then import the database normally.
Lay of the Land
Given a docker-compose.yml
similar to this (note it’s a bit obfuscated):
version: '3.5'
services:
gitlab:
image: 'gitlab/gitlab-ce:latest'
container_name: "gitlab"
restart: always
hostname: 'git.sebastientaggart.com'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://git.sebastientaggart.com'
# set the SSH port
gitlab_rails['gitlab_shell_ssh_port'] = 10022
# Disable built-in NGINX and encryption, Caddy handles this
gitlab_workhorse['listen_network'] = "tcp"
gitlab_workhorse['listen_addr'] = "0.0.0.0:3000"
nginx['enable'] = false
letsencrypt['enable'] = false
letsencrypt['auto_renew'] = false
postgresql['enable'] = false
gitlab_rails['db_username'] = "gitlab"
gitlab_rails['db_password'] = "{PASSWORD}"
gitlab_rails['db_host'] = "postgresql-gitlab"
gitlab_rails['db_port'] = "5432"
gitlab_rails['db_database'] = "gitlab"
gitlab_rails['db_adapter'] = 'postgresql'
gitlab_rails['db_encoding'] = 'utf8'
gitlab_rails['time_zone'] = 'America/New_York'
gitlab_rails['rack_attack_git_basic_auth'] = {
'enabled' => true,
'ip_whitelist' => ["127.0.0.1"],
'maxretry' => 10, # Limit the number of Git HTTP authentication attempts per IP
'findtime' => 60, # Reset the auth attempt counter per IP after 60 seconds
'bantime' => 3600 # Ban an IP for one hour (3600s) after too many auth attempts
}
# Add any other gitlab.rb configuration here, each on its own line
ports:
- '3000:3000' # HTTP (workhorse, main UI)
- '10022:22' # SSH port
volumes:
- './data/gitlab/config:/etc/gitlab'
- './data/gitlab/logs:/var/log/gitlab'
- './data/gitlab/data:/var/opt/gitlab'
postgresql-gitlab:
image: 'postgres:11.1-alpine'
container_name: "gitlab_postgresql"
restart: always
environment:
- POSTGRES_USER=gitlab
- POSTGRES_PASSWORD={PASSWORD}
- POSTGRES_DB=gitlab
volumes:
- ./data/postgresql-gitlab:/var/lib/postgresql/data
An attempt at backing up using the usual rake
, e.g. docker exec -t gitlab gitlab-rake gitlab:backup:create
will fail with:
Dumping PostgreSQL database gitlab ... pg_dump: server version: 11.1; pg_dump version: 9.6.11
pg_dump: aborting because of server version mismatch
Getting the DB Dump Out
In order to get the export to work at all, it’s necessary to sh into the container and upgrade the postgresql client to 11.
echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main" >> /etc/apt/sources.list.d/pgdg.list
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
apt install wget ca-certificates
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
apt update
apt install postgresql-client
ln -s /usr/bin/psql /usr/bin/pg_dump /opt/gitlab/bin/
Now the export will work via:
docker exec -t gitlab_postgresql pg_dumpall -c -U gitlab > dump_11_`date +%d-%m-%Y"_"%H_%M_%S`.sql
Note this is a manually executed command against the postgresql container, NOT the usual rake command, since we are only attempting to downgrade Postgres back to 9.6. As we’ll see below, actually converting back to using the bundled Postgres doesn’t work even after taking these steps.
Cleaning Up Between Import/Export Operations
In my case, I’m voluming the Postgresql data directory to preserve the database between container resets. During this operation we need to erase this data before setting an older version of Postgres in the docker-compose.yml
.
sudo rm -rf /opt/docker/gitlab/data/postgresql-gitlab/*
Downgrading from 10 to 9
Exporting from 11, then importing into 10 works fine, however, going from 10 to 9 fails with DB errors. The fix to these is possible with a Python script from stack overflow:
#!/usr/bin/env python3
import sys
#
# Downgrades pg_dump 10 script to 9.x
# removing 'AS integer' from 'CREATE SEQUENCE' statement
#
# Usage:
# $ python3 pgdump_10_to_9.py < test10.sql > test9.sql
# or:
# $ cat test10.sql | ./pgdump_10_to_9.py > test9.sql
#
# To obtain a compressed 9.x sql script from a compressed 10 sql script:
#
# $ gunzip -c test10.sql.gz | ./pgdump_10_to_9.py | gzip > test9.sql.gz
#
inside_create_sequence = False
for row in sys.stdin.readlines():
if inside_create_sequence and row.strip().lower() == 'as integer':
pass
else:
print(row, end='', flush=True)
inside_create_sequence = row.strip().startswith('CREATE SEQUENCE ')
Save this script as pgdump_10_to_9.py
, chmod +x pgdump_10_to_9.py
, and run it:
# Assuming we have an existing dump named dump_10_12-04-2019_15_09_16.sql
cat dump_10_12-04-2019_15_09_16.sql | ./pgdump_10_to_9.py > dump_9_compatible.sql
# This would export a 9-compatible file to dump_9_compatible.sql
Now update your compose to use a Postgres 9.6 image, and import:
cat dump_9_compatible.sql | docker exec -i gitlab_postgresql psql -U gitlab
And voila! You’ve downgraded back to an older version of Postgres that’s more compatible with Gitlab.