Created
August 12, 2021 02:41
-
-
Save joshbrooks/918c6c093114002c97225894f632ff5e to your computer and use it in GitHub Desktop.
This is a single file class to do a backup; rsync that backup over to a local dir; and load that as initial data in a postgis container
This file contains hidden or 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
#!/usr/bin/env python | |
import docker | |
import logging | |
from docker import DockerClient | |
import time | |
import subprocess | |
import sys | |
from dataclasses import dataclass | |
logger = logging.getLogger() | |
logger.setLevel(logging.INFO) | |
@dataclass | |
class ContainerRebuild: | |
# Server config | |
user: str | |
host: str | |
db: str | |
tmpdir: str | |
# Local container config | |
# Note these are for local container and | |
# django setting, not for host | |
postgres_user: str | |
postgres_db: str | |
postgres_password: str | |
# Container config | |
image: str | |
tag: str | |
def rsync(self): | |
""" | |
Runs pg_dump on the server, and then 'rsyncs' the result over | |
""" | |
logger.info("Calling pg_dump on the server") | |
subprocess.call( | |
F"ssh {self.user}@{self.host} pg_dump --format=custom --compress=0 postgresql:///{self.db} --format=directory -f {self.tmpdir}".split() | |
) | |
logger.info("Calling rsync") | |
subprocess.call( | |
F"rsync -avz {self.user}@{self.host}:{self.tmpdir} .".split() | |
) | |
logger.info("Remove temp backup dir") | |
subprocess.call(F"ssh {self.user}@{self.host} rm -rf {self.tmpdir}".split()) | |
logger.info('Rsync complete') | |
def start_container(self, client): | |
""" | |
Run a container to load the data | |
This will run a postgis container with the specified data | |
and wait until it is ready to connect | |
""" | |
logger.info("Starting container") | |
container = client.containers.run( | |
image = "postgis/postgis:12-3.1", | |
environment = { | |
"POSTGRES_USER": self.postgres_user, | |
"POSTGRES_DB": self.postgres_db, | |
"POSTGRES_PASSWORD": self.postgres_password | |
}, | |
detach=True, | |
) | |
logger.info("Awaiting postgres, this may take some time...") | |
ready_command = ["pg_isready", "-h", "localhost", "-U", self.postgres_user] | |
logger.info('Checking for postgres') | |
response = container.exec_run(ready_command) | |
while response[0] != 0: | |
logger.info(".") | |
time.sleep(2) | |
response = container.exec_run(ready_command) | |
logger.info("Postgres reported ready") | |
return container | |
def write_archive(self, container): | |
""" | |
Write content of the "/var/lib/postgresql/data" as 'pg_data_dir.tar' | |
""" | |
logger.info('Copy content of the "/var/lib/postgresql/data" as pg_data_dir.tar') | |
bits, stat = container.get_archive("/var/lib/postgresql/data") | |
with open("./pg_data_dir.tar", "wb") as volume_data: | |
for chunk in bits: | |
volume_data.write(chunk) | |
def run(self): | |
self.rsync() | |
client = docker.from_env() # type: DockerClient | |
container = self.start_container(client) | |
container.exec_run(cmd=f"pg_restore -u {self.postgres_user} -d {self.postgres_db} /source", user="postgres") | |
self.write_archive(container) | |
container.stop() | |
container.remove() | |
client.images.build(path=".", tag=self.tag) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment