PostgreSQL Sicherung mit Docker SDK für Python
Vermeiden Sie komplexe Bash-Skripte. Schreiben Sie Ihre Skripte in Python!
Dies ist ein kurzer Beitrag über die Sicherung einer Dockerized PostgreSQL Datenbank. Um auf die Datenbank zuzugreifen, führen wir normalerweise ein Bash-Skript auf dem Host aus, mit Befehlen wie:
docker exec -t <container> bash -c '<command>'
In diesem Beitrag ersetzen wir unser Bash-Skript durch ein Python -Skript. Warum? Weil wir Python kennen und die Programmierung in Bash zeitaufwändig sein kann. Während wir hier 'subprocess' verwenden können, um alle Systembefehle auszuführen, binden wir das Docker SDK für Python ein und erhalten eine Menge Extras. Wie immer laufe ich dies auf Ubuntu (22.04).
Backup-Vorgang
Wir werden in den folgenden Schritten ein Backup durchführen:
- Sicherung der Datenbank in eine temporäre Datei innerhalb des Containers.
- Kopieren der Sicherungsdatei außerhalb des Containers.
- Entfernen Sie die temporäre Datei.
- Anzeige des Zeitpunkts des Sicherungsvorgangs.
Das Bash-Sicherungsskript
Nachfolgend sehen Sie das Bash-Sicherungsskript. Es prüft auf Fehler während des Sicherungs- und Kopiervorgangs. Das Skript beginnt mit unseren Container- und Datenbankparametern.
#!/usr/bin/bash
# backup.sh
pg_container=8c49633bda68
pg_user=postgres
db_name=my_db
db_user=postgres
# start
SECONDS=0
# backupfile inside docker container
tmp_backupfile=/tmp/${db_name}.pg_dump
# backupfile on the host
backupfile=${db_name}.pg_dump.`date +%Y%m%d"_"%H%M%S`.sql
echo "tmp_backupfile = ${tmp_backupfile}"
echo "backupfile = ${backupfile}"
echo "removing previous tmp_backupfile ..."
docker exec -t ${pg_container} bash -c 'rm -f -- ${0}' ${tmp_backupfile}
echo "dumping database to tmp_backupfile ..."
docker exec -t --user ${pg_user} ${pg_container} bash -c 'pg_dump ${0} -Fc -U ${1} -f ${2}' ${db_name} ${pg_user} ${tmp_backupfile}
exit_code=$?
if [ $exit_code -ne 0 ] ; then
echo "dump error, exit_code = ${exit_code}"
exit $exit_code
fi
echo "copying tmp_backupfile to backupfile ..."
docker cp "${pg_container}":${tmp_backupfile} ${backupfile}
exit_code=$?
if [ $exit_code -ne 0 ] ; then
echo "copy error, exit_code = ${exit_code}"
exit $exit_code
fi
echo "removing tmp_backupfile ..."
docker exec -t ${pg_container} bash -c 'rm -f -- ${0}' ${tmp_backupfile}
fsize=`stat --printf="%s" ${backupfile}`
elapsed_secs=$SECONDS
echo "ready, backupfile = ${backupfile}, size = ${fsize}, seconds = ${elapsed_secs}"
Das Python -Sicherungsskript
Für das Python Skript installieren wir zunächst das Python SDK für Docker (in einem virtual environment):
pip install docker
Nachfolgend finden Sie das Python -Sicherungsskript. Es prüft auf Fehler während des Sicherungs- und Kopiervorgangs.
# backup.py
import datetime
import logging
import os
import subprocess
import sys
import time
import docker
def get_logger():
logger_format = '[%(asctime)s] [%(levelname)s] %(message)s'
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# console
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(logging.Formatter(logger_format))
logger.addHandler(console_handler)
return logger
logger = get_logger()
class DockerUtils:
def __init__(
self,
container=None,
):
self.client = docker.from_env()
self.container = self.client.containers.get(container)
def docker_exec(self, cmd, **kwargs):
return self.container.exec_run(cmd, **kwargs)
def remove_container_file(self, f):
r = self.docker_exec('ls ' + f)
if r.exit_code == 0:
r = self.docker_exec('rm ' + f)
def docker_cp_from_container(self, src, dst):
r = subprocess.run(['docker', 'cp', self.container.short_id + ':' + src, dst])
return r
def main():
pg_container = '8c49633bda68'
pg_user = 'postgres'
db_name = 'my_db'
db_user = 'postgres'
# start
dt_start = datetime.datetime.now()
# backupfile inside docker container
tmp_backupfile = os.path.join('/tmp/', db_name + '.pg_dump')
# backupfile on the host
backupfile = './' + db_name + '.pg_dump.' + datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
logger.debug('tmp_backupfile = {}'.format(tmp_backupfile))
logger.debug('backupfile = {}'.format(backupfile))
# instantiate and set container
du = DockerUtils(container=pg_container)
logger.debug('removing previous tmp_backupfile ...')
du.remove_container_file(tmp_backupfile)
logger.debug('dumping database to tmp_backupfile ...')
cmd = 'pg_dump {0} -Fc -U {1} -f {2}'.format(db_name, db_user, tmp_backupfile)
kwargs = {'user': pg_user}
r = du.docker_exec(cmd, **kwargs)
if r.exit_code != 0:
logger.error('dump error: {}'.format(str(r.output.decode('utf-8'))))
sys.exit()
logger.debug('copying tmp_backupfile to backupfile ...')
r = du.docker_cp_from_container(tmp_backupfile, backupfile)
if r.returncode != 0:
logger.error('copy error = {}'.format(r.returncode))
sys.exit()
logger.debug('removing tmp_backupfile ...')
du.remove_container_file(tmp_backupfile)
fsize = os.stat(backupfile).st_size
elapsed_secs = int((datetime.datetime.now() - dt_start).total_seconds())
logger.info('ready, backupfile = {}, size = {}, seconds = {}'.format(backupfile, fsize, elapsed_secs))
if __name__ == "__main__":
main()
Ausführung ohne virtual environment
Aber halt, mit Python brauchen wir einen virtual environment. Um dies zu vermeiden, können wir eine ausführbare Datei mit PyInstaller erstellen. Installieren Sie zunächst PyInstaller:
pip install pyinstaller
Dann erstellen Sie die ausführbare Datei mit dem folgenden Befehl:
pyinstaller --onefile backup.py
Dadurch wird eine ausführbare Datei im Verzeichnis './dist' erstellt:
dist/backup
Wir können dies ausführen und diese ausführbare Datei in unseren Pfad aufnehmen.
Zusammenfassung
Wir brauchten das Docker SDK für Python hier nicht wirklich, wir hätten auch 'subprocess' verwenden können, aber indem wir es einbinden, können wir auch eine Menge anderer Dinge tun.
Es gibt keinen großen Unterschied zwischen dem Bash-Skript und dem Skript Python . Ein paar Zeilen in der Bash zu schreiben ist einfach. Aber sobald wir ein wenig mehr Funktionalität und Kontrolle wollen, kann es sehr zeitaufwändig werden. Wenn man kein Bash-Guru ist, muss man Befehle nachschlagen, lernen, wie man Funktionen schreibt, und Dinge testen. Wenn wir ein Python -Skript schreiben, brauchen wir immer noch Kenntnisse über Linux -Befehle, aber wir können dies auf die wenigen Funktionen beschränken, die wir brauchen. Für die restlichen Funktionen können wir unsere Python -Kenntnisse nutzen.
Links / Impressum
Docker - docker cp
https://docs.docker.com/engine/reference/commandline/cp
Docker SDK for Python
https://docker-py.readthedocs.io
Dockerize & Backup A Postgres Database
https://dev.to/mattcale/dockerize-backup-a-postgres-database-2b1l
PostgreSQL - pg_dump
https://www.postgresql.org/docs/current/app-pgdump.html
PyInstaller
https://pyinstaller.org
Why is pg_restore segfaulting in Docker?
https://stackoverflow.com/questions/63934856/why-is-pg-restore-segfaulting-in-docker
Mehr erfahren
Docker
Neueste
- Ausblenden der Primärschlüssel der Datenbank UUID Ihrer Webanwendung
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas