forked from coop-cloud/backup-bot-two
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			main
			...
			backup_vol
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e360c3d8f8 | |||
| 50b317c12d | |||
| 9cb3a469f3 | |||
| 24d2c0e85b | 
							
								
								
									
										16
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								.drone.yml
									
									
									
									
									
								
							| @ -7,22 +7,6 @@ steps: | |||||||
|     commands: |     commands: | ||||||
|       - shellcheck backup.sh |       - shellcheck backup.sh | ||||||
|  |  | ||||||
|   - name: publish image |  | ||||||
|     image: plugins/docker |  | ||||||
|     settings: |  | ||||||
|       auto_tag: true |  | ||||||
|       username: thecoopcloud |  | ||||||
|       password: |  | ||||||
|         from_secret: thecoopcloud_password |  | ||||||
|       repo: thecoopcloud/backup-bot-two |  | ||||||
|       tags: latest |  | ||||||
|     depends_on: |  | ||||||
|       - run shellcheck |  | ||||||
|     when: |  | ||||||
|       event: |  | ||||||
|         exclude: |  | ||||||
|           - pull_request |  | ||||||
|  |  | ||||||
| trigger: | trigger: | ||||||
|   branch: |   branch: | ||||||
|     - main |     - main | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							| @ -1,13 +0,0 @@ | |||||||
| FROM docker:24.0.2-dind |  | ||||||
|  |  | ||||||
| RUN apk add --upgrade --no-cache \ |  | ||||||
|   bash \ |  | ||||||
|   curl \ |  | ||||||
|   jq \ |  | ||||||
|   restic |  | ||||||
|  |  | ||||||
| COPY backup.sh /usr/bin/backup.sh |  | ||||||
| COPY setup-cron.sh /usr/bin/setup-cron.sh |  | ||||||
| RUN chmod +x /usr/bin/backup.sh /usr/bin/setup-cron.sh |  | ||||||
|  |  | ||||||
| ENTRYPOINT [ "/usr/bin/setup-cron.sh" ] |  | ||||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							| @ -4,7 +4,7 @@ | |||||||
|  |  | ||||||
| _This Time, It's Easily Configurable_ | _This Time, It's Easily Configurable_ | ||||||
|  |  | ||||||
| Automatically take backups from running Docker Swarm services into a volume. | Automatically take backups from all volumes of running Docker Swarm services and runs pre- and post commands. | ||||||
|  |  | ||||||
| ## Background | ## Background | ||||||
|  |  | ||||||
| @ -49,15 +49,13 @@ services: | |||||||
|   db: |   db: | ||||||
|     deploy: |     deploy: | ||||||
|       labels: |       labels: | ||||||
|         backupbot.backup: "true" |         backupbot.backup: ${BACKUP:-"true"}  | ||||||
|         backupbot.backup.pre-hook: 'mysqldump -u root -p"$(cat /run/secrets/db_root_password)" -f /tmp/dump/dump.db' |         backupbot.backup.pre-hook: 'mysqldump -u root -p"$(cat /run/secrets/db_root_password)" -f /volume_path/dump.db' | ||||||
|         backupbot.backup.post-hook: "rm -rf /tmp/dump/dump.db" |         backupbot.backup.post-hook: "rm -rf /volume_path/dump.db" | ||||||
|         backupbot.backup.path: "/tmp/dump/,/etc/foo/" |  | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| - `backupbot.backup` -- set to `true` to back up this service (REQUIRED) | - `backupbot.backup` -- set to `true` to back up this service (REQUIRED) | ||||||
| - `backupbot.backup.path` -- comma separated list of file paths within the service to copy (REQUIRED) | - `backupbot.backup.pre-hook` -- command to run before copying files (optional), save all dumps into the volumes | ||||||
| - `backupbot.backup.pre-hook` -- command to run before copying files (optional) |  | ||||||
| - `backupbot.backup.post-hook` -- command to run after copying files (optional) | - `backupbot.backup.post-hook` -- command to run after copying files (optional) | ||||||
|  |  | ||||||
| As in the above example, you can reference Docker Secrets, e.g. for looking up database passwords, by reading the files in `/run/secrets` directly. | As in the above example, you can reference Docker Secrets, e.g. for looking up database passwords, by reading the files in `/run/secrets` directly. | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								abra.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								abra.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | export ENTRYPOINT_VERSION=v1 | ||||||
|  | export BACKUP_VERSION=v1 | ||||||
							
								
								
									
										49
									
								
								backup.sh
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								backup.sh
									
									
									
									
									
								
							| @ -1,12 +1,14 @@ | |||||||
| #!/bin/bash | #!/bin/bash | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
| server_name="${SERVER_NAME:?SERVER_NAME not set}" | server_name="${SERVER_NAME:?SERVER_NAME not set}" | ||||||
|  |  | ||||||
| restic_password_file="${RESTIC_PASSWORD_FILE:?RESTIC_PASSWORD_FILE not set}" | restic_password_file="${RESTIC_PASSWORD_FILE:?RESTIC_PASSWORD_FILE not set}" | ||||||
|  |  | ||||||
| restic_host="${RESTIC_HOST:?RESTIC_HOST not set}" | restic_host="${RESTIC_HOST:?RESTIC_HOST not set}" | ||||||
|  |  | ||||||
| backup_path="${BACKUP_DEST:?BACKUP_DEST not set}" | backup_paths=() | ||||||
|  |  | ||||||
| # shellcheck disable=SC2153 | # shellcheck disable=SC2153 | ||||||
| ssh_key_file="${SSH_KEY_FILE}" | ssh_key_file="${SSH_KEY_FILE}" | ||||||
| @ -71,8 +73,8 @@ else | |||||||
| 	mapfile -t services < <(docker service ls --format '{{ .Name }}') | 	mapfile -t services < <(docker service ls --format '{{ .Name }}') | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | post_commands=() | ||||||
| if [[ \ $*\  != *\ --skip-backup\ * ]]; then | if [[ \ $*\  != *\ --skip-backup\ * ]]; then | ||||||
| 	rm -rf "${backup_path}" |  | ||||||
|  |  | ||||||
| 	for service in "${services[@]}"; do | 	for service in "${services[@]}"; do | ||||||
| 		echo "service: $service" | 		echo "service: $service" | ||||||
| @ -80,36 +82,21 @@ if [[ \ $*\  != *\ --skip-backup\ * ]]; then | |||||||
| 		if echo "$details" | jq -r '.["backupbot.backup"]' | grep -q 'true'; then | 		if echo "$details" | jq -r '.["backupbot.backup"]' | grep -q 'true'; then | ||||||
| 			pre=$(echo "$details" | jq -r '.["backupbot.backup.pre-hook"]') | 			pre=$(echo "$details" | jq -r '.["backupbot.backup.pre-hook"]') | ||||||
| 			post=$(echo "$details" | jq -r '.["backupbot.backup.post-hook"]') | 			post=$(echo "$details" | jq -r '.["backupbot.backup.post-hook"]') | ||||||
| 			path=$(echo "$details" | jq -r '.["backupbot.backup.path"]') |  | ||||||
|  |  | ||||||
| 			if [ "$path" = "null" ]; then |  | ||||||
| 				echo "ERROR: missing 'path' for $service" |  | ||||||
| 				continue # or maybe exit? |  | ||||||
| 			fi |  | ||||||
|  |  | ||||||
| 			container=$(docker container ls -f "name=$service" --format '{{ .ID }}') | 			container=$(docker container ls -f "name=$service" --format '{{ .ID }}') | ||||||
|  | 			stack_name=$(echo "$details" | jq -r '.["com.docker.stack.namespace"]') | ||||||
| 			echo "backing up $service" |  | ||||||
|  |  | ||||||
| 			if [ "$pre" != "null" ]; then | 			if [ "$pre" != "null" ]; then | ||||||
| 				# run the precommand | 				# run the precommand | ||||||
| 				# shellcheck disable=SC2086 | 				echo "executing precommand $pre in container $container" | ||||||
| 				docker exec "$container" sh -c "$pre" | 				docker exec "$container" sh -c "$pre" | ||||||
| 			fi | 			fi | ||||||
|  |  | ||||||
| 			# run the backup |  | ||||||
| 			for p in ${path//,/ }; do |  | ||||||
| 				# creates the parent folder, so `docker cp` has reliable behaviour no matter if $p ends with `/` or `/.` |  | ||||||
| 				dir=$backup_path/$service/$(dirname "$p") |  | ||||||
| 				test -d "$dir" || mkdir -p "$dir" |  | ||||||
| 				docker cp -a "$container:$p" "$dir/$(basename "$p")" |  | ||||||
| 			done |  | ||||||
|  |  | ||||||
| 			if [ "$post" != "null" ]; then | 			if [ "$post" != "null" ]; then | ||||||
| 				# run the postcommand | 				# append post command | ||||||
| 				# shellcheck disable=SC2086 | 				post_commands+=("docker exec $container sh -c \"$post\"") | ||||||
| 				docker exec "$container" sh -c "$post" |  | ||||||
| 			fi | 			fi | ||||||
|  |  | ||||||
|  | 			# add volume paths to backup path | ||||||
|  | 			backup_paths+=(/var/lib/docker/volumes/"${stack_name}"_*) | ||||||
| 		fi | 		fi | ||||||
| 	done | 	done | ||||||
|  |  | ||||||
| @ -121,10 +108,12 @@ if [[ \ $*\  != *\ --skip-backup\ * ]]; then | |||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ \ $*\  != *\ --skip-upload\ * ]]; then | if [[ \ $*\  != *\ --skip-upload\ * ]]; then | ||||||
| 	_restic backup --host "$server_name" --tag coop-cloud "$backup_path" | 	echo "${backup_paths[@]}" | ||||||
|  | 	_restic backup --host "$server_name" --tag coop-cloud "${backup_paths[@]}" | ||||||
| 	if [ "$REMOVE_BACKUP_VOLUME_AFTER_UPLOAD" -eq 1 ]; then |  | ||||||
| 		echo "Cleaning up ${backup_path}" |  | ||||||
| 		rm -rf "${backup_path}" |  | ||||||
| 	fi |  | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | # run post commands | ||||||
|  | for post in "${post_commands[@]}"; do | ||||||
|  | 	echo "executing postcommand $post" | ||||||
|  | 	eval "$post" | ||||||
|  | done | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								compose.yml
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								compose.yml
									
									
									
									
									
								
							| @ -2,11 +2,10 @@ | |||||||
| version: "3.8" | version: "3.8" | ||||||
| services: | services: | ||||||
|   app: |   app: | ||||||
|     image: thecoopcloud/backup-bot-two:latest |     image: docker:24.0.2-dind | ||||||
| #    build: . |  | ||||||
|     volumes: |     volumes: | ||||||
|       - "/var/run/docker.sock:/var/run/docker.sock" |       - "/var/run/docker.sock:/var/run/docker.sock" | ||||||
|       - "backups:/backups" |       - "/var/lib/docker/volumes/:/var/lib/docker/volumes/:ro" | ||||||
|     environment: |     environment: | ||||||
|       - CRON_SCHEDULE |       - CRON_SCHEDULE | ||||||
|       - RESTIC_REPO |       - RESTIC_REPO | ||||||
| @ -19,17 +18,25 @@ services: | |||||||
|       - restic_password |       - restic_password | ||||||
|     deploy: |     deploy: | ||||||
|       labels: |       labels: | ||||||
|         - "traefik.enable=true" |  | ||||||
|         - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=8008" |  | ||||||
|         - "traefik.http.routers.${STACK_NAME}.rule=" |  | ||||||
|         - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" |  | ||||||
|         - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" |  | ||||||
|         - coop-cloud.${STACK_NAME}.version=0.1.0+latest |         - coop-cloud.${STACK_NAME}.version=0.1.0+latest | ||||||
|  |     configs: | ||||||
| volumes: |       - source: entrypoint | ||||||
|   backups: |         target: /entrypoint.sh | ||||||
|  |         mode: 0555 | ||||||
|  |       - source: backup | ||||||
|  |         target: /backup.sh | ||||||
|  |         mode: 0555 | ||||||
|  |     entrypoint: ['/entrypoint.sh'] | ||||||
|  |  | ||||||
| secrets: | secrets: | ||||||
|   restic_password: |   restic_password: | ||||||
|     external: true |     external: true | ||||||
|     name: ${STACK_NAME}_restic_password_${SECRET_RESTIC_PASSWORD_VERSION} |     name: ${STACK_NAME}_restic_password_${SECRET_RESTIC_PASSWORD_VERSION} | ||||||
|  |  | ||||||
|  | configs: | ||||||
|  |   entrypoint: | ||||||
|  |     name: ${STACK_NAME}_entrypoint_${ENTRYPOINT_VERSION} | ||||||
|  |     file: entrypoint.sh | ||||||
|  |   backup: | ||||||
|  |     name: ${STACK_NAME}_backup_${BACKUP_VERSION} | ||||||
|  |     file: backup.sh | ||||||
|  | |||||||
| @ -1,11 +1,12 @@ | |||||||
| #!/bin/bash | #!/bin/sh | ||||||
| 
 | 
 | ||||||
| set -e | set -e | ||||||
| set -o pipefail | 
 | ||||||
|  | apk add --upgrade --no-cache bash curl jq restic | ||||||
| 
 | 
 | ||||||
| cron_schedule="${CRON_SCHEDULE:?CRON_SCHEDULE not set}" | cron_schedule="${CRON_SCHEDULE:?CRON_SCHEDULE not set}" | ||||||
| 
 | 
 | ||||||
| echo "$cron_schedule /usr/bin/backup.sh" | crontab - | echo "$cron_schedule /backup.sh" | crontab - | ||||||
| crontab -l | crontab -l | ||||||
| 
 | 
 | ||||||
| crond -f -d8 -L /dev/stdout | crond -f -d8 -L /dev/stdout | ||||||
		Reference in New Issue
	
	Block a user