Compare commits
No commits in common. "34d0c7a381fa188c1c18d0382b452bf9cd258f98" and "274a733dae2dd72cb17ecc3facf0ac7e0e3fed9c" have entirely different histories.
34d0c7a381
...
274a733dae
77
backup.py
77
backup.py
@ -15,8 +15,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
|
|
||||||
COMPOSE_PATH = Path('docker-compose.yml')
|
COMPOSE_PATH = Path('docker-compose.yml')
|
||||||
BACKUP_VOL_PATH = Path('./backup/docker_named_volumes')
|
BACKUP_PATH = Path('./data/bkp')
|
||||||
BACKUP_SQL_PATH = Path('./backup/docker_sql_dumps')
|
|
||||||
VOLUME_PREFIX = 'docker_'
|
VOLUME_PREFIX = 'docker_'
|
||||||
|
|
||||||
|
|
||||||
@ -54,9 +53,6 @@ def build_services_graph(services):
|
|||||||
def group_services(services, graph):
|
def group_services(services, graph):
|
||||||
grouped_services = {}
|
grouped_services = {}
|
||||||
for service in services:
|
for service in services:
|
||||||
# Do not include if SQL
|
|
||||||
if is_sql(services[service]):
|
|
||||||
continue
|
|
||||||
root = graph.find(service)
|
root = graph.find(service)
|
||||||
if root not in grouped_services:
|
if root not in grouped_services:
|
||||||
grouped_services[root] = {'services': []}
|
grouped_services[root] = {'services': []}
|
||||||
@ -69,33 +65,32 @@ def group_volumes(services, volumes, services_group):
|
|||||||
for group_name, group in services_group.items():
|
for group_name, group in services_group.items():
|
||||||
group_volumes = group.setdefault('volumes', [])
|
group_volumes = group.setdefault('volumes', [])
|
||||||
for service in group['services']:
|
for service in group['services']:
|
||||||
for volume in [v.split(':')[0] for v in services[service].get('volumes', [])]:
|
for volume in [v.split(':')[0] for v in services[service]['volumes']]:
|
||||||
if volume in volumes: group_volumes += [volume]
|
if volume in volumes: group_volumes += [volume]
|
||||||
|
|
||||||
return services_group
|
return services_group
|
||||||
|
|
||||||
|
def backup(volume):
|
||||||
def is_sql(service):
|
|
||||||
return 'postgres' in service['image']
|
|
||||||
|
|
||||||
|
|
||||||
def get_date_string():
|
|
||||||
current_date = datetime.now()
|
current_date = datetime.now()
|
||||||
return current_date.strftime("%Y-%m-%d")
|
date_string = current_date.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
|
||||||
def backup_named_volume(volume):
|
|
||||||
date_string = get_date_string()
|
|
||||||
archive_name = f'{date_string}_{volume}.tar'
|
archive_name = f'{date_string}_{volume}.tar'
|
||||||
print(f'backup volume {volume} to {BACKUP_VOL_PATH}/{archive_name}')
|
print(f'backup volume {volume} to {BACKUP_PATH}/{archive_name}')
|
||||||
|
|
||||||
subprocess.run(f'docker run --rm --volume {VOLUME_PREFIX}{volume}:/data --volume {BACKUP_VOL_PATH.resolve()}:/bkp ubuntu tar -cf /bkp/{archive_name} -C /data .'.split())
|
subprocess.run(f'docker run --rm --volume {VOLUME_PREFIX}{volume}:/data --volume {BACKUP_PATH.resolve()}:/bkp ubuntu tar -cf /bkp/{archive_name} -C /data .'.split())
|
||||||
|
|
||||||
|
|
||||||
def run_docker_compose(cmd): subprocess.run(f'docker compose {cmd}'.split())
|
def run_docker_compose(cmd):
|
||||||
|
subprocess.run(f'docker compose {cmd}'.split())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
with COMPOSE_PATH.open() as cf:
|
||||||
|
compose = yaml.safe_load(cf)
|
||||||
|
|
||||||
|
services = compose['services']
|
||||||
|
volumes = compose['volumes']
|
||||||
|
|
||||||
|
|
||||||
def backup_named_volumes(services, volumes):
|
|
||||||
services_graph = build_services_graph(services)
|
services_graph = build_services_graph(services)
|
||||||
services_group = group_services(services, services_graph)
|
services_group = group_services(services, services_graph)
|
||||||
services_group = group_volumes(services, volumes, services_group)
|
services_group = group_volumes(services, volumes, services_group)
|
||||||
@ -107,45 +102,9 @@ def backup_named_volumes(services, volumes):
|
|||||||
print('no volumes')
|
print('no volumes')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f'{group["volumes"]}: run backup...')
|
print('run backup...')
|
||||||
|
|
||||||
run_docker_compose(f'stop {" ".join(group["services"])}')
|
run_docker_compose(f'stop {" ".join(group["services"])}')
|
||||||
for volume in group['volumes']:
|
for volume in group['volumes']:
|
||||||
backup_named_volume(volume)
|
backup(volume)
|
||||||
run_docker_compose(f'start {" ".join(group["services"])}')
|
run_docker_compose(f'start {" ".join(group["services"])}')
|
||||||
|
|
||||||
|
|
||||||
def backup_sql_dumps(services, volumes):
|
|
||||||
for service_name, service in services.items():
|
|
||||||
if not is_sql(service):
|
|
||||||
continue
|
|
||||||
#print(f'Service {service_name} run sql dump...')
|
|
||||||
backup_sql_dump(service_name, service)
|
|
||||||
|
|
||||||
|
|
||||||
def backup_sql_dump(service_name, service):
|
|
||||||
date_string = get_date_string()
|
|
||||||
dump_name = f'{date_string}_{service_name}.sql'
|
|
||||||
dump_path = BACKUP_SQL_PATH / dump_name
|
|
||||||
|
|
||||||
dump_path.parent.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
user = service['environment']['POSTGRES_USER']
|
|
||||||
db = service['environment']['POSTGRES_DB']
|
|
||||||
|
|
||||||
print(f'Service {service_name} dump database to {dump_path}')
|
|
||||||
|
|
||||||
with dump_path.open('wb') as f:
|
|
||||||
subprocess.run(f'docker compose exec -T {service_name} pg_dump -U {user} {db}'.split(),
|
|
||||||
check=True,
|
|
||||||
stdout=f)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
with COMPOSE_PATH.open() as cf:
|
|
||||||
compose = yaml.safe_load(cf)
|
|
||||||
|
|
||||||
services = compose['services']
|
|
||||||
volumes = compose['volumes']
|
|
||||||
|
|
||||||
backup_named_volumes(services, volumes)
|
|
||||||
backup_sql_dumps(services, volumes)
|
|
||||||
|
|||||||
@ -503,15 +503,6 @@ services:
|
|||||||
ENTE_APPS_CAST: https://tele-photos.guiotte.fr
|
ENTE_APPS_CAST: https://tele-photos.guiotte.fr
|
||||||
ENTE_APPS_EMBED_ALBUMS: https://capsule-photos.guiotte.fr
|
ENTE_APPS_EMBED_ALBUMS: https://capsule-photos.guiotte.fr
|
||||||
ENTE_APPS_ACCOUNTS: https://comptes-photos.guiotte.fr
|
ENTE_APPS_ACCOUNTS: https://comptes-photos.guiotte.fr
|
||||||
ENTE_INTERNAL_ADMIN: 1580559962386438
|
|
||||||
ENTE_INTERNAL_DISABLE_REGISTRATION: true
|
|
||||||
ENTE_SMTP_HOST: ${MAIL_SERVER}
|
|
||||||
ENTE_SMTP_PORT: ${MAIL_SMTP_PORT}
|
|
||||||
ENTE_SMTP_USERNAME: ${MAIL_USERNAME}
|
|
||||||
ENTE_SMTP_PASSWORD: ${MAIL_PASSWORD}
|
|
||||||
ENTE_SMTP_SENDER_NAME: Ente
|
|
||||||
ENTE_SMTP_EMAIL: ${MAIL_USERNAME}
|
|
||||||
ENTE_SMTP_ENCRYPTION: ssl
|
|
||||||
secrets:
|
secrets:
|
||||||
- ente-db-pw
|
- ente-db-pw
|
||||||
- ente-s3-key
|
- ente-s3-key
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user