mirror of
https://github.com/ZettaIO/restic-compose-backup.git
synced 2025-10-09 20:00:58 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
74c0954e6f | ||
|
f6995eb506 | ||
|
ef28baed5e | ||
|
336cace237 | ||
|
cab4676b91 | ||
|
d002ad9390 | ||
|
98a10bf994 | ||
|
2535ce3421 | ||
|
8858f88ba4 | ||
|
c5b7f11db7 | ||
|
a099060b2e | ||
|
dd40152fe1 |
BIN
.github/logo.png
vendored
Normal file
BIN
.github/logo.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
@@ -168,3 +168,8 @@ Contributions are welcome regardless of experience level. Don't hesitate submitt
|
||||
|
||||
[restic]: https://restic.net/
|
||||
[documentation]: https://restic-compose-backup.readthedocs.io
|
||||
|
||||
---
|
||||
This project is sponsored by [zetta.io](https://www.zetta.io)
|
||||
|
||||
[](https://www.zetta.io)
|
||||
|
@@ -5,6 +5,9 @@ services:
|
||||
env_file:
|
||||
- restic_compose_backup.env
|
||||
- alerts.env
|
||||
labels:
|
||||
restic-compose-backup.volumes: true
|
||||
restic-compose-backup.volumes.include: 'src'
|
||||
volumes:
|
||||
# Map in docker socket
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
@@ -20,7 +23,7 @@ services:
|
||||
restic-compose-backup.volumes: true
|
||||
restic-compose-backup.volumes.include: "/tests"
|
||||
volumes:
|
||||
- ./tests:/srv/tests
|
||||
- ./src/tests:/srv/tests
|
||||
- ./.vscode:/srv/code
|
||||
environment:
|
||||
- SOME_VALUE=test
|
||||
|
@@ -22,7 +22,7 @@ copyright = '2019, Zetta.IO Technology AS'
|
||||
author = 'Zetta.IO Technology AS'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '0.4.0'
|
||||
release = '0.4.2'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
|
@@ -166,12 +166,27 @@ a webhook that will post embedded messages to a specific channel.
|
||||
|
||||
The url usually looks like this: ``https://discordapp.com/api/webhooks/...```
|
||||
|
||||
DOCKER_BASE_URL
|
||||
~~~~~~~~~~~~~~~
|
||||
DOCKER_HOST
|
||||
~~~~~~~~~~~
|
||||
|
||||
**Default value**: ``unix://tmp/docker.sock``
|
||||
|
||||
The location of the docker socket.
|
||||
The socket or host of the docker service.
|
||||
|
||||
DOCKER_TLS_VERIFY
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
If defined verify the host against a CA certificate.
|
||||
Path to certs is defined in ``DOCKER_CERT_PATH``
|
||||
and can be copied or mapped into this backup container.
|
||||
|
||||
DOCKER_CERT_PATH
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
A path to a directory containing TLS certificates to use when
|
||||
connecting to the Docker host. Combined with ``DOCKER_TLS_VERIFY``
|
||||
this can be used to talk to docker through TLS in cases
|
||||
were we cannot map in the docker socket.
|
||||
|
||||
Compose Labels
|
||||
--------------
|
||||
|
@@ -13,9 +13,9 @@ When releasing a bugfix version we need to update the
|
||||
main image as well.
|
||||
|
||||
```bash
|
||||
docker build src --tag zettaio/restic-compose-backup:0.3
|
||||
docker build src --tag zettaio/restic-compose-backup:0.3.3
|
||||
docker build src --tag zettaio/restic-compose-backup:0.4
|
||||
docker build src --tag zettaio/restic-compose-backup:0.4.1
|
||||
|
||||
docker push zettaio/restic-compose-backup:0.3
|
||||
docker push zettaio/restic-compose-backup:0.3.3
|
||||
docker push zettaio/restic-compose-backup:0.4
|
||||
docker push zettaio/restic-compose-backup:0.4.1
|
||||
```
|
||||
|
@@ -1,6 +1,9 @@
|
||||
# DON'T COMMIT THIS FILE IF YOU MODIFY IN DEV
|
||||
|
||||
DOCKER_BASE_URL=unix://tmp/docker.sock
|
||||
# DOCKER_HOST=unix://tmp/docker.sock
|
||||
# DOCKER_TLS_VERIFY=1
|
||||
# DOCKER_CERT_PATH=''
|
||||
|
||||
RESTIC_REPOSITORY=/restic_data
|
||||
RESTIC_PASSWORD=password
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
__version__ = '0.4.0'
|
||||
__version__ = '0.4.2'
|
||||
|
@@ -17,7 +17,7 @@ def run(image: str = None, command: str = None, volumes: dict = None,
|
||||
labels=labels,
|
||||
# auto_remove=True, # We remove the container further down
|
||||
detach=True,
|
||||
environment=environment,
|
||||
environment=environment + ['BACKUP_PROCESS_CONTAINER=true'],
|
||||
volumes=volumes,
|
||||
network_mode=f'container:{source_container_id}', # Reuse original container's network stack.
|
||||
working_dir=os.getcwd(),
|
||||
|
@@ -57,6 +57,9 @@ def status(config, containers):
|
||||
logger.info("Status for compose project '%s'", containers.project_name)
|
||||
logger.info("Repository: '%s'", config.repository)
|
||||
logger.info("Backup currently running?: %s", containers.backup_process_running)
|
||||
logger.info("Checking docker availability")
|
||||
|
||||
utils.list_containers()
|
||||
|
||||
if containers.stale_backup_process_containers:
|
||||
utils.remove_containers(containers.stale_backup_process_containers)
|
||||
@@ -117,6 +120,7 @@ def backup(config, containers):
|
||||
mounts = containers.generate_backup_mounts('/volumes')
|
||||
volumes.update(mounts)
|
||||
|
||||
logger.debug('Starting backup container with image %s', containers.this_container.image)
|
||||
try:
|
||||
result = backup_runner.run(
|
||||
image=containers.this_container.image,
|
||||
@@ -151,12 +155,18 @@ def backup(config, containers):
|
||||
|
||||
def start_backup_process(config, containers):
|
||||
"""The actual backup process running inside the spawned container"""
|
||||
if (not containers.backup_process_container
|
||||
or containers.this_container == containers.backup_process_container is False):
|
||||
if not utils.is_true(os.environ.get('BACKUP_PROCESS_CONTAINER')):
|
||||
logger.error(
|
||||
"Cannot run backup process in this container. Use backup command instead. "
|
||||
"This will spawn a new container with the necessary mounts."
|
||||
)
|
||||
alerts.send(
|
||||
subject="Cannot run backup process in this container",
|
||||
body=(
|
||||
"Cannot run backup process in this container. Use backup command instead. "
|
||||
"This will spawn a new container with the necessary mounts."
|
||||
)
|
||||
)
|
||||
exit(1)
|
||||
|
||||
status(config, containers)
|
||||
|
@@ -10,7 +10,6 @@ class Config:
|
||||
# Mandatory values
|
||||
self.repository = os.environ.get('RESTIC_REPOSITORY')
|
||||
self.password = os.environ.get('RESTIC_REPOSITORY')
|
||||
self.docker_base_url = os.environ.get('DOCKER_BASE_URL') or "unix://tmp/docker.sock"
|
||||
self.cron_schedule = os.environ.get('CRON_SCHEDULE') or self.default_crontab_schedule
|
||||
self.cron_command = os.environ.get('CRON_COMMAND') or self.default_backup_command
|
||||
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import os
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from restic_compose_backup import enums, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VOLUME_TYPE_BIND = "bind"
|
||||
VOLUME_TYPE_VOLUME = "volume"
|
||||
@@ -355,7 +357,7 @@ class RunningContainers:
|
||||
# Detect containers belonging to the current compose setup
|
||||
if (container.project_name == self.this_container.project_name
|
||||
and not container.is_oneoff):
|
||||
if container.id != self.this_container.id:
|
||||
if container != self.backup_process_container:
|
||||
self.containers.append(container)
|
||||
|
||||
@property
|
||||
|
@@ -3,7 +3,6 @@ import logging
|
||||
from typing import List
|
||||
from contextlib import contextmanager
|
||||
import docker
|
||||
from restic_compose_backup.config import Config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -11,8 +10,18 @@ TRUE_VALUES = ['1', 'true', 'True', True, 1]
|
||||
|
||||
|
||||
def docker_client():
|
||||
config = Config()
|
||||
return docker.DockerClient(base_url=config.docker_base_url)
|
||||
"""
|
||||
Create a docker client from the following environment variables::
|
||||
|
||||
DOCKER_HOST=unix://tmp/docker.sock
|
||||
DOCKER_TLS_VERIFY=1
|
||||
DOCKER_CERT_PATH=''
|
||||
"""
|
||||
# NOTE: Remove this fallback in 1.0
|
||||
if not os.environ.get('DOCKER_HOST'):
|
||||
os.environ['DOCKER_HOST'] = 'unix://tmp/docker.sock'
|
||||
|
||||
return docker.from_env()
|
||||
|
||||
|
||||
def list_containers() -> List[dict]:
|
||||
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_namespace_packages
|
||||
setup(
|
||||
name="restic-compose-backup",
|
||||
url="https://github.com/ZettaIO/restic-compose-backup",
|
||||
version="0.4.0",
|
||||
version="0.4.2",
|
||||
author="Einar Forselv",
|
||||
author_email="eforselv@gmail.com",
|
||||
packages=find_namespace_packages(include=['restic_compose_backup']),
|
||||
|
@@ -160,7 +160,7 @@
|
||||
"OpenStdin": true,
|
||||
"StdinOnce": true,
|
||||
"Env": [
|
||||
"DOCKER_BASE_URL=unix://tmp/docker.sock",
|
||||
"DOCKER_HOST=unix://tmp/docker.sock",
|
||||
"RESTIC_REPOSITORY=/tmp/backup",
|
||||
"RESTIC_PASSWORD=password",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
@@ -77,7 +77,7 @@ class ResticBackupTests(unittest.TestCase):
|
||||
]
|
||||
with mock.patch(list_containers_func, fixtures.containers(containers=containers)):
|
||||
result = RunningContainers()
|
||||
self.assertEqual(len(result.containers), 3, msg="Three containers expected")
|
||||
self.assertEqual(len(result.containers), 4, msg="Three containers expected")
|
||||
self.assertNotEqual(result.this_container, None, msg="No backup container found")
|
||||
web_service = result.get_service('web')
|
||||
self.assertNotEqual(web_service, None)
|
||||
|
Reference in New Issue
Block a user