init commit
This commit is contained in:
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
FROM alpine:latest
|
||||
|
||||
# Install dependencies
|
||||
RUN apk update && apk add --no-cache \
|
||||
bash \
|
||||
rsync \
|
||||
coreutils \
|
||||
cronie \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
|
||||
# Copy backup and list scripts
|
||||
COPY backup.sh /usr/local/bin/backup.sh
|
||||
COPY list.sh /usr/local/bin/list.sh
|
||||
# Mark them executables
|
||||
RUN chmod +x /usr/local/bin/backup.sh
|
||||
RUN chmod +x /usr/local/bin/list.sh
|
||||
|
||||
# Add crontab file and needed cache directory
|
||||
RUN mkdir -p /root/.cache/crontab && chmod 700 /root/.cache/crontab
|
||||
COPY crontab.txt /etc/crontabs/root
|
||||
RUN crontab /etc/crontabs/root
|
||||
|
||||
# Start cron in foreground
|
||||
CMD ["/usr/sbin/crond", "-f"]
|
||||
33
README
Normal file
33
README
Normal file
@@ -0,0 +1,33 @@
|
||||
#What is this
|
||||
This is a docker for a cron job that runs rsync to backup folders.
|
||||
the backup.sh is the backup script but the cronjob call list.sh which thenc calls backup.sh
|
||||
this is to make listing multiple folders easier.
|
||||
|
||||
#Setup
|
||||
#Source and destination
|
||||
On docker compose you'll find volumes
|
||||
```
|
||||
volumes:
|
||||
- /path/to/sources/:/source/
|
||||
- /path/to/backups/:/backup/
|
||||
```
|
||||
change `path/to/source` and `path/to/backups` to the paths where the folders you'll want to backup are and where the backup is going to
|
||||
|
||||
##List
|
||||
```
|
||||
/usr/local/bin/backup.sh /source/project1 /backup/project1-backup --keep-trash=false --rsync-delete=true
|
||||
```
|
||||
this is the list the cronjob will run.
|
||||
`/usr/local/bin/backup.sh` is just the name of the backup script, does not need change
|
||||
`/source/project1` Param 1 is the folder you want a backup of, if need change
|
||||
`/backup/project1-backup` Param 2 is the folder where the backup will go
|
||||
`--keep-trash=false` Param 3 is if a "trash" folder will be kept, this means that any file deleted from the source folder will have it's latest backup moved to a "trash" folder where it'll stay for 30 days, after that, it too will be deleted
|
||||
`--rsync-delete=true` Param 4 if used, delete flag will be called for rsync, deleting any file on backup folder that has been deleted from souce
|
||||
|
||||
if both are false, then any deleted files will be kept indefinitely in the backup folder.
|
||||
|
||||
|
||||
#Building and running
|
||||
build with
|
||||
`docker build -t cron-backuper .`
|
||||
and use `docker compose up` to bring it up(it's easier to config volumes that way)
|
||||
122
backup.sh
Executable file
122
backup.sh
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
|
||||
############################################
|
||||
#
|
||||
# SETUP
|
||||
#
|
||||
############################################
|
||||
# Logs to file and stdout
|
||||
log() {
|
||||
local now
|
||||
now=$(date "+%Y/%m/%d %H:%M:%S")
|
||||
echo "$now - $1" | tee -a "$LOGFILE"
|
||||
}
|
||||
|
||||
############################################
|
||||
#
|
||||
# ARGUMENT CHECK
|
||||
#
|
||||
############################################
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "Usage: $0 <source_dir> <destination_dir> [--keep-trash=true|false]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_DIR="$1"
|
||||
DESTINATION_ROOT="$2"
|
||||
DESTINATION_DIR="$DESTINATION_ROOT/backup"
|
||||
TRASH_DIR="$DESTINATION_ROOT/trash"
|
||||
LOGFILE="$DESTINATION_ROOT/backup.log"
|
||||
KEEP_TRASH=false
|
||||
RSYNC_DELETE=false
|
||||
|
||||
shift 2
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--keep-trash=true) KEEP_TRASH=true ;;
|
||||
--keep-trash=false) KEEP_TRASH=false ;;
|
||||
--rsync-delete=true) RSYNC_DELETE=true ;;
|
||||
--rsync-delete=false) RSYNC_DELETE=false ;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
############################################
|
||||
#
|
||||
# STARTUP
|
||||
#
|
||||
############################################
|
||||
# Create directories if they don't exist
|
||||
mkdir -p "$SOURCE_DIR" "$DESTINATION_DIR" "$TRASH_DIR"
|
||||
#Create log file if it doesn't exist
|
||||
[ -e "$LOGFILE" ] || touch "$LOGFILE"
|
||||
|
||||
log "SOURCE_DIR: $SOURCE_DIR"
|
||||
log "DESTINATION_DIR: $DESTINATION_DIR"
|
||||
log "TRASH_DIR: $TRASH_DIR"
|
||||
log "LOGFILE: $LOGFILE"
|
||||
|
||||
############################################
|
||||
#
|
||||
# BACKUP
|
||||
#
|
||||
############################################
|
||||
log "$SOURCE_DIR $DESTINATION_DIR"
|
||||
if rsync -ah "$SOURCE_DIR/" "$DESTINATION_DIR/" 2>>"$LOGFILE"; then
|
||||
log "Backup completed successfully"
|
||||
else
|
||||
log "Backup failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$KEEP_TRASH" != "true" ]; then
|
||||
log "Skipping trash operations"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
############################################
|
||||
#
|
||||
# MOVE DELETED FILES TO TRASH
|
||||
#
|
||||
############################################
|
||||
# Iterate over all files in DESTINATION and look for files not in SOURCE to move to TRASH
|
||||
find "$DESTINATION_DIR" -type f | while read -r dest_file; do
|
||||
# Construct the relative path of the file inside DESTINATION
|
||||
rel_path="${dest_file#$DESTINATION_DIR/}"
|
||||
#log "REL_PATH: $rel_path"
|
||||
# Construct the corresponding SOURCE file path
|
||||
source_file="$SOURCE_DIR/$rel_path"
|
||||
#log "SOURCE_FILE: $source_file"
|
||||
|
||||
# If the file doesn't exist in SOURCE, move it to TRASH preserving folder structure
|
||||
if [ ! -f "$source_file" ]; then
|
||||
# Create the directory structure inside TRASH
|
||||
dest_dir=$(dirname "$TRASH_DIR/$rel_path")
|
||||
#log "DEST_DIR: $dest_dir"
|
||||
mkdir -p "$dest_dir"
|
||||
|
||||
# Move the file to TRASH
|
||||
mv "$dest_file" "$TRASH_DIR/${rel_path}_$(date +%s)"
|
||||
# Updates last changed timestamp to now so 30 days counter starts on move
|
||||
touch "$TRASH_DIR/${rel_path}_$(date +%s)"
|
||||
#log "Moved: $dest_file -> $TRASH_DIR/$rel_path"
|
||||
fi
|
||||
done
|
||||
|
||||
############################################
|
||||
#
|
||||
# CLEANUP
|
||||
#
|
||||
############################################
|
||||
# Remove empty directories from DESTINATION_DIR
|
||||
find "$DESTINATION_DIR" -type d -empty -delete
|
||||
|
||||
# Deleting files older than 30 days from trash and cleaning up empty directories.
|
||||
find "$TRASH_DIR" -type f -mtime +30 -exec rm -f {} \;
|
||||
find "$TRASH_DIR" -type d -empty -delete
|
||||
|
||||
log "Done!!"
|
||||
2
crontab.txt
Normal file
2
crontab.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
0 3 * * * /usr/local/bin/list.sh >> /proc/1/fd/1 2>&1
|
||||
|
||||
8
docker-compose.yml
Normal file
8
docker-compose.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
backup:
|
||||
image: cron-backuper
|
||||
container_name: cron-backuper
|
||||
volumes:
|
||||
- /path/to/sources/:/source/
|
||||
- /path/to/backups/:/backup/
|
||||
command: ["/bin/sh", "-c", "crontab /etc/crontabs/root && crond -f"]
|
||||
Reference in New Issue
Block a user