├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── scripts ├── entrypoint.sh └── run.sh └── tests ├── docker-compose.yml └── geoserver_mock ├── Dockerfile └── change.py /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | 3 | MAINTAINER fvanderbiest "francois.vanderbiest@gmail.com" 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y git inotify-tools && \ 7 | rm -rf /var/lib/apt/lists/* /usr/share/doc/* /usr/share/man/* 8 | 9 | COPY scripts/*.sh / 10 | RUN chmod +x /entrypoint.sh 11 | 12 | VOLUME [ "/var/local/data" ] 13 | WORKDIR /var/local/data 14 | 15 | ENV REMOTE_BRANCH master 16 | 17 | ENTRYPOINT [ "/entrypoint.sh" ] 18 | CMD ["bash", "-l", "/run.sh"] 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 François Van Der Biest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | docker-build: 2 | docker pull debian:stretch 3 | docker build -t fvanderbiest/volume-git-backup:`date +%Y%m%d%H%M%S` . 4 | docker build -t fvanderbiest/volume-git-backup:latest . 5 | 6 | docker-push: 7 | docker push fvanderbiest/volume-git-backup 8 | 9 | all: docker-build 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automatic docker volume backup with git 2 | 3 | [![License](https://img.shields.io/dub/l/vibe-d.svg)](LICENSE) 4 | [![Pulls](https://img.shields.io/docker/pulls/fvanderbiest/volume-git-backup.svg)](https://hub.docker.com/r/fvanderbiest/volume-git-backup/) 5 | 6 | This repository is the source of the [fvanderbiest/volume-git-backup](https://hub.docker.com/r/fvanderbiest/volume-git-backup/) image on Docker Hub. 7 | The image provides an easy way to `git commit` a docker volume every time a file is updated. 8 | Feel free to use it if it suits your needs. Contributions welcomed. 9 | 10 | This image expects to find the volume mounted in `rw` mode on `/var/local/data`. 11 | 12 | The file to watch for changes should also be contained in this directory. 13 | Internally, we're using `inotifywait` to watch the file. 14 | 15 | When change is detected, the script performs the commit and optionally pushes to a remote repository. 16 | 17 | At startup, if a remote repository is configured a clone of this repository is 18 | done in the volume. If volume is not empty, you will need to set FORCE_CLONE var 19 | to 'yes' to force a cleanup of the volume. If the volume is already verionned 20 | (contains a `.git` folder) then git remote is updated and local repository is updated 21 | to the last commit of configured branch. 22 | 23 | Example usage: 24 | ```yaml 25 | sync: 26 | image: fvanderbiest/volume-git-backup 27 | environment: 28 | WATCH_FILE: global.xml 29 | GIT_COMMIT_MESSAGE: printf "updateSequence "; grep updateSequence global.xml|sed -e 's#.*ce>\(.*\) ~/.ssh/id_rsa 12 | fi 13 | if [ -n "$GIT_RSA_DEPLOY_KEY_FILE" ]; then 14 | echo "Installing rsa key from file" 15 | cp $GIT_RSA_DEPLOY_KEY_FILE ~/.ssh/id_rsa 16 | fi 17 | chmod -R go-rx ~/.ssh 18 | 19 | # Init ssh connection to git repo 20 | if [ -n "$REMOTE_NAME" ] && [ -n "$REMOTE_URL" ]; then 21 | git_hostname=`echo $REMOTE_URL | sed -e 's#.*\@\(.*\):.*#\1#'` 22 | ssh-keyscan -H $git_hostname >> ~/.ssh/known_hosts 23 | fi 24 | 25 | # test if local git repo already exists, if not clone or init 26 | if [ ! -d .git ]; then 27 | 28 | # clone remote repo if defined 29 | if [ -n "$REMOTE_NAME" ] && [ -n "$REMOTE_URL" ]; then 30 | 31 | # check if there is something in directory 32 | files_count=`ls -a | wc -l` 33 | if [ $files_count -gt 2 ]; then 34 | if [ -n "$FORCE_CLONE" ] && [ $FORCE_CLONE = "yes" ]; then 35 | rm -fr ./* 36 | rm -fr ./.* 37 | else 38 | echo "Directory not empty and FORCE_CLONE not set so stopping" 39 | exit 1 40 | fi 41 | fi 42 | 43 | echo "Cloning from $REMOTE_URL" 44 | git clone -b $REMOTE_BRANCH $REMOTE_URL . 45 | 46 | else 47 | echo "No remote configured, just init" 48 | git init 49 | fi 50 | 51 | fi 52 | 53 | # Fetch last commits of remote repo if defined 54 | if [ -n "$REMOTE_NAME" ] && [ -n "$REMOTE_URL" ]; then 55 | # set new url for remote 56 | echo "Setup remote $REMOTE_NAME to $REMOTE_URL" 57 | git remote rm $REMOTE_NAME &> /dev/null 58 | git remote add $REMOTE_NAME $REMOTE_URL 59 | 60 | echo "Fetch remote repo" 61 | git fetch $REMOTE_NAME 62 | echo "Reset to upstream state" 63 | git reset --hard $REMOTE_NAME/$REMOTE_BRANCH 64 | git clean -xdf 65 | fi 66 | 67 | # execute CMD 68 | exec "$@" 69 | -------------------------------------------------------------------------------- /scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | trap 'exit 0' SIGKILL SIGTERM SIGHUP SIGINT EXIT 4 | 5 | first=true 6 | 7 | while true 8 | do 9 | if [ ! -f $WATCH_FILE ]; then 10 | if $first; then 11 | printf "$WATCH_FILE does not exist (yet ?).." 12 | first=0 13 | fi 14 | printf "." 15 | sleep ${SLEEPING_TIME:-1} 16 | continue 17 | else 18 | echo "$WATCH_FILE exists" 19 | fi 20 | 21 | # set up watches: 22 | inotifywait -e modify $WATCH_FILE 23 | 24 | # commit all files from current dir: 25 | git add --all . 26 | 27 | # commit with custom message: 28 | msg=`eval $GIT_COMMIT_MESSAGE` 29 | git commit -m "${msg:-"no commit message"}" 30 | 31 | if [ $REMOTE_NAME ] && [ $REMOTE_URL ]; then 32 | # push to repository in the background 33 | git push $REMOTE_NAME $REMOTE_BRANCH & 34 | fi 35 | done 36 | -------------------------------------------------------------------------------- /tests/docker-compose.yml: -------------------------------------------------------------------------------- 1 | geoserver: 2 | build: ./geoserver_mock 3 | environment: 4 | DATADIR_PATH: /opt/geoserver_data_dir 5 | volumes: 6 | - geoserver_datadir:/opt/geoserver_data_dir:rw 7 | 8 | sync: 9 | image: fvanderbiest/volume-git-backup 10 | environment: 11 | WATCH_FILE: global.xml 12 | SLEEPING_TIME: 5 13 | GIT_COMMIT_MESSAGE: printf "updateSequence "; grep updateSequence global.xml|sed -e 's#.*ce>\(.*\)"+now+"\n") 40 | f.close() 41 | time.sleep(period) 42 | if killer.kill_now: 43 | break 44 | print "Killed. Exiting !" 45 | 46 | if __name__ == "__main__": 47 | main() 48 | --------------------------------------------------------------------------------