├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── install.sh ├── package.json ├── pnpm-lock.yaml └── toolkit.sh /.gitignore: -------------------------------------------------------------------------------- 1 | ### JetBrains template 2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 3 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 4 | 5 | # User-specific stuff 6 | .idea/**/workspace.xml 7 | .idea/**/tasks.xml 8 | .idea/**/usage.statistics.xml 9 | .idea/**/dictionaries 10 | .idea/**/shelf 11 | 12 | # AWS User-specific 13 | .idea/**/aws.xml 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/artifacts 36 | # .idea/compiler.xml 37 | # .idea/jarRepositories.xml 38 | # .idea/modules.xml 39 | # .idea/*.iml 40 | # .idea/modules 41 | # *.iml 42 | # *.ipr 43 | 44 | # CMake 45 | cmake-build-*/ 46 | 47 | # Mongo Explorer plugin 48 | .idea/**/mongoSettings.xml 49 | 50 | # File-based project format 51 | *.iws 52 | 53 | # IntelliJ 54 | out/ 55 | 56 | # mpeltonen/sbt-idea plugin 57 | .idea_modules/ 58 | 59 | # JIRA plugin 60 | atlassian-ide-plugin.xml 61 | 62 | # Cursive Clojure plugin 63 | .idea/replstate.xml 64 | 65 | # SonarLint plugin 66 | .idea/sonarlint/ 67 | 68 | # Crashlytics plugin (for Android Studio and IntelliJ) 69 | com_crashlytics_export_strings.xml 70 | crashlytics.properties 71 | crashlytics-build.properties 72 | fabric.properties 73 | 74 | # Editor-based Rest Client 75 | .idea/httpRequests 76 | 77 | # Android studio 3.1+ serialized cache file 78 | .idea/caches/build_file_checksums.ser 79 | 80 | ### Node template 81 | # Logs 82 | logs 83 | *.log 84 | npm-debug.log* 85 | yarn-debug.log* 86 | yarn-error.log* 87 | lerna-debug.log* 88 | .pnpm-debug.log* 89 | 90 | # Diagnostic reports (https://nodejs.org/api/report.html) 91 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 92 | 93 | # Runtime data 94 | pids 95 | *.pid 96 | *.seed 97 | *.pid.lock 98 | 99 | # Directory for instrumented libs generated by jscoverage/JSCover 100 | lib-cov 101 | 102 | # Coverage directory used by tools like istanbul 103 | coverage 104 | *.lcov 105 | 106 | # nyc test coverage 107 | .nyc_output 108 | 109 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 110 | .grunt 111 | 112 | # Bower dependency directory (https://bower.io/) 113 | bower_components 114 | 115 | # node-waf configuration 116 | .lock-wscript 117 | 118 | # Compiled binary addons (https://nodejs.org/api/addons.html) 119 | build/Release 120 | 121 | # Dependency directories 122 | node_modules/ 123 | jspm_packages/ 124 | 125 | # Snowpack dependency directory (https://snowpack.dev/) 126 | web_modules/ 127 | 128 | # TypeScript cache 129 | *.tsbuildinfo 130 | 131 | # Optional npm cache directory 132 | .npm 133 | 134 | # Optional eslint cache 135 | .eslintcache 136 | 137 | # Optional stylelint cache 138 | .stylelintcache 139 | 140 | # Microbundle cache 141 | .rpt2_cache/ 142 | .rts2_cache_cjs/ 143 | .rts2_cache_es/ 144 | .rts2_cache_umd/ 145 | 146 | # Optional REPL history 147 | .node_repl_history 148 | 149 | # Output of 'npm pack' 150 | *.tgz 151 | 152 | # Yarn Integrity file 153 | .yarn-integrity 154 | 155 | # dotenv environment variable files 156 | .env 157 | .env.development.local 158 | .env.test.local 159 | .env.production.local 160 | .env.local 161 | 162 | # parcel-bundler cache (https://parceljs.org/) 163 | .cache 164 | .parcel-cache 165 | 166 | # Next.js build output 167 | .next 168 | out 169 | 170 | # Nuxt.js build / generate output 171 | .nuxt 172 | dist 173 | 174 | # Gatsby files 175 | .cache/ 176 | # Comment in the public line in if your project uses Gatsby and not Next.js 177 | # https://nextjs.org/blog/next-9-1#public-directory-support 178 | # public 179 | 180 | # vuepress build output 181 | .vuepress/dist 182 | 183 | # vuepress v2.x temp and cache directory 184 | .temp 185 | .cache 186 | 187 | # Docusaurus cache and generated files 188 | .docusaurus 189 | 190 | # Serverless directories 191 | .serverless/ 192 | 193 | # FuseBox cache 194 | .fusebox/ 195 | 196 | # DynamoDB Local files 197 | .dynamodb/ 198 | 199 | # TernJS port file 200 | .tern-port 201 | 202 | # Stores VSCode versions used for testing VSCode extensions 203 | .vscode-test 204 | 205 | # yarn v2 206 | .yarn/cache 207 | .yarn/unplugged 208 | .yarn/build-state.yml 209 | .yarn/install-state.gz 210 | .pnp.* 211 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .env.* 4 | !.env.example 5 | 6 | # Ignore files for PNPM, NPM and YARN 7 | pnpm-lock.yaml 8 | package-lock.json 9 | yarn.lock 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "useTabs": false, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "es5", 7 | "printWidth": 100, 8 | "overrides": [ 9 | { 10 | "files": "*.md", 11 | "options": { 12 | "parser": "markdown", 13 | "printWidth": 79 14 | } 15 | } 16 | ], 17 | "plugins": ["prettier-plugin-sh"] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Shahrad Elahi 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-backup-toolkit 2 | 3 | --- 4 | 5 | - [Installation](#-installation) 6 | - [Usage](#-usage) 7 | - [backup](#backup) 8 | - [restore](#restore) 9 | - [Contributing](#-contributing) 10 | - [License](#license) 11 | 12 | ## 📦 Installation 13 | 14 | ##### Prerequisites 15 | 16 | - [docker](https://docs.docker.com/get-docker/) 17 | - [bash](https://www.gnu.org/software/bash/) 18 | 19 | ```bash 20 | # Work in progress 21 | ``` 22 | 23 | ## 📖 Usage 24 | 25 | ```text 26 | Usage: toolkit.sh [options] [command] 27 | 28 | Docker volume backup and restore utility 29 | Author: @shahradelahi, https://github.com/shahradelahi 30 | 31 | Options: 32 | -V, --version output the version number 33 | -h, --help display help for command 34 | 35 | Commands: 36 | backup [options] backup from volume or volumes of a container 37 | restore [options] restore backup to volume 38 | help [command] display help for command 39 | ``` 40 | 41 | ### backup 42 | 43 | This command is used for backup a container or volume to a tar file. 44 | 45 | #### Options 46 | 47 | ```txt 48 | Usage: toolkit.sh backup [options] 49 | 50 | backup from volume or volumes of a container 51 | 52 | Options: 53 | -c, --container backup all volumes of a container 54 | -v, --volume backup a single volume 55 | -h, --help display help for command 56 | ``` 57 | 58 | ###### Examples 59 | 60 | ```bash 61 | # Backup from all volumes of a container 62 | ./toolkit.sh backup --container my-container 63 | 64 | # Backup from a single volume 65 | ./toolkit.sh backup --volume my-volume 66 | ``` 67 | 68 | ### restore 69 | 70 | ```text 71 | Not implemented yet 72 | ``` 73 | 74 | ## 🤝 Contributing 75 | 76 | Want to contribute? Awesome! To show your support is to star the project, or to raise issues on [GitHub](https://github.com/shahradelahi/docker-backup-toolkit). 77 | 78 | Thanks again for your support, it is much appreciated! 79 | 80 | ### License 81 | 82 | [MIT](LICENSE) © [Shahrad Elahi](https://github.com/shahradelahi) 83 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Not implemented yet" 4 | exit 1 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-backup-toolkit", 3 | "description": "Docker volume backup and restore utility", 4 | "version": "0.0.0", 5 | "private": true, 6 | "author": "Shahrad Elahi (https://github.com/shahradelahi)", 7 | "license": "MIT", 8 | "packageManager": "pnpm@9.10.0", 9 | "scripts": { 10 | "format": "prettier --write .", 11 | "format:check": "prettier --check ." 12 | }, 13 | "devDependencies": { 14 | "prettier": "^3.3.3", 15 | "prettier-plugin-sh": "^0.14.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | prettier: 12 | specifier: ^3.3.3 13 | version: 3.3.3 14 | prettier-plugin-sh: 15 | specifier: ^0.14.0 16 | version: 0.14.0(prettier@3.3.3) 17 | 18 | packages: 19 | 20 | mvdan-sh@0.10.1: 21 | resolution: {integrity: sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg==} 22 | 23 | prettier-plugin-sh@0.14.0: 24 | resolution: {integrity: sha512-hfXulj5+zEl/ulrO5kMuuTPKmXvOg0bnLHY1hKFNN/N+/903iZbNp8NyZBTsgI8dtkSgFfAEIQq0IQTyP1ZVFQ==} 25 | engines: {node: '>=16.0.0'} 26 | peerDependencies: 27 | prettier: ^3.0.3 28 | 29 | prettier@3.3.3: 30 | resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} 31 | engines: {node: '>=14'} 32 | hasBin: true 33 | 34 | sh-syntax@0.4.2: 35 | resolution: {integrity: sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg==} 36 | engines: {node: '>=16.0.0'} 37 | 38 | tslib@2.7.0: 39 | resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} 40 | 41 | snapshots: 42 | 43 | mvdan-sh@0.10.1: {} 44 | 45 | prettier-plugin-sh@0.14.0(prettier@3.3.3): 46 | dependencies: 47 | mvdan-sh: 0.10.1 48 | prettier: 3.3.3 49 | sh-syntax: 0.4.2 50 | 51 | prettier@3.3.3: {} 52 | 53 | sh-syntax@0.4.2: 54 | dependencies: 55 | tslib: 2.7.0 56 | 57 | tslib@2.7.0: {} 58 | -------------------------------------------------------------------------------- /toolkit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | has_args() { [[ "$1" == *=* ]] && [[ -n "${1#*=}" ]] || [[ ! -z "$2" && "$2" != -* ]]; } 6 | 7 | arg_exists() { 8 | for arg in $2; do 9 | if [ "$arg" == "$1" ]; then 10 | return 0 11 | fi 12 | done 13 | return 1 14 | } 15 | 16 | read_arg() { 17 | IFS='|' read -ra FS <<< "$1" 18 | shift 19 | while (("$#")); do 20 | if [[ " ${FS[*]} " =~ " $1 " ]]; then 21 | echo "$2" 22 | break 23 | fi 24 | shift 25 | done 26 | } 27 | 28 | log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"; } 29 | 30 | usage() { 31 | case $1 in 32 | backup) 33 | echo "Usage: $(basename "$0") backup [options]" 34 | echo "" 35 | echo "backup from volume or volumes of a container" 36 | echo "" 37 | echo "Options:" 38 | echo " -c, --container backup all volumes of a container" 39 | echo " -v, --volume backup a single volume" 40 | echo " -h, --help display help for command" 41 | ;; 42 | *) 43 | echo "Usage: $(basename "$0") [options] [command]" 44 | echo "" 45 | echo "Docker volume backup and restore utility" 46 | echo "Author: @shahradelahi, https://github.com/shahradelahi" 47 | echo "" 48 | echo "Options:" 49 | echo " -V, --version output the version number" 50 | echo " -h, --help display help for command" 51 | echo "" 52 | echo "Commands:" 53 | echo " backup [options] backup from volume or volumes of a container" 54 | echo " restore [options] restore backup to volume" 55 | echo " help [command] display help for command" 56 | ;; 57 | esac 58 | } 59 | 60 | if arg_exists "--help" "$@" || arg_exists "-h" "$@"; then 61 | usage 62 | exit 0 63 | fi 64 | 65 | check_volume() { 66 | VOLUME=$1 67 | if [ -z "$VOLUME" ]; then 68 | log "ERR: Volume name is required" 69 | exit 1 70 | fi 71 | LIST=$(sudo docker volume ls -q --filter name="$VOLUME") 72 | if [ -z "$LIST" ]; then 73 | log "ERR: Volume $VOLUME not found" 74 | exit 1 75 | fi 76 | } 77 | 78 | backup_volume() { 79 | local VOLUME=$1 80 | check_volume "$VOLUME" 81 | local NOW="$(date +%Y%m%d%H%M%S)" 82 | local BACKUP="backup-$NOW" 83 | local TAR_FILE="$VOLUME-$NOW.tar.gz" 84 | sudo docker run --name "$BACKUP" -v "$VOLUME:/backup" ubuntu:latest \ 85 | tar -C /backup -czvf "$TAR_FILE" . 86 | sudo docker cp "$BACKUP:/$TAR_FILE" . 87 | sudo docker rm -f "$BACKUP" 88 | } 89 | 90 | list_volumes() { 91 | CONTAINER_NAME=$1 92 | sudo docker inspect -f '{{ range .Mounts }}{{ printf "\n" }}{{ .Type }} {{ if eq .Type "bind" }}{{ .Source }}{{ end }}{{ .Name }} => {{ .Destination }}{{ end }}{{ printf "\n" }}' "$CONTAINER_NAME" | grep volume 93 | } 94 | 95 | check_container() { 96 | LIST=$(sudo docker ps -a -q --filter name="$CONTAINER_NAME") 97 | if [ -z "$LIST" ]; then 98 | log "ERR: Container $CONTAINER_NAME not found" 99 | exit 1 100 | fi 101 | } 102 | 103 | case $1 in 104 | backup) 105 | if arg_exists "--volume" "$*" || arg_exists "-v" "$*"; then 106 | _VOLUME_NAME=$(read_arg "-v|--volume" $*) 107 | backup_volume "$_VOLUME_NAME" 108 | exit 0 109 | fi 110 | 111 | if arg_exists "--container" "$*" || arg_exists "-c" "$*"; then 112 | CONTAINER_NAME=$(read_arg "-c|--container" $*) 113 | else 114 | read -r -p "Container name: " CONTAINER_NAME 115 | fi 116 | 117 | check_container 118 | 119 | for VOLUME in $(list_volumes "$CONTAINER_NAME" | awk '{print $2}'); do 120 | if [ -z "$VOLUME" ]; then 121 | log "ERR: Volume name is required" 122 | continue 123 | fi 124 | backup_volume "$VOLUME" 125 | done 126 | ;; 127 | stop) 128 | log "ERR: Not implemented yet" 129 | exit 1 130 | ;; 131 | help) 132 | usage "$2" 133 | ;; 134 | *) 135 | usage 136 | exit 1 137 | ;; 138 | esac 139 | 140 | exit 0 141 | --------------------------------------------------------------------------------