├── config ├── update.sh ├── LICENSE.md ├── readme.md └── tugboat /config: -------------------------------------------------------------------------------- 1 | * * * * * update test -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install depedencies for debian 4 | apt-get update && apt-get install -y \ 5 | rsync 6 | 7 | # Remove old stuff 8 | rm -r /opt/tugboat 9 | rm /usr/bin/tugboat 10 | 11 | # Create the log file and give permissions to write to it 12 | touch /var/log/tugboat && chmod 666 /var/log/tugboat 13 | 14 | mkdir -p /opt/tugboat 15 | 16 | # Clone tugboat source into /opt/tugboat and make a symlink so it can be executed conveniently 17 | curl https://raw.githubusercontent.com/teknowafel/Tugboat/main/tugboat > /opt/tugboat/tugboat 18 | chmod +x /opt/tugboat/tugboat 19 | ln -s /opt/tugboat/tugboat /usr/bin/tugboat -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 teknowafel 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 | # Tugboat 2 | *The easy way to keep it up to date* 3 | 4 | Tugboat helps you keep your docker apps up to date using the power of *docker compose* in conjunction with cron. 5 | 6 | ## Features 7 | * Update a stack 8 | * Start a stack 9 | * Stop a stack 10 | 11 | Tugboat installs as a command on your docker host and features simple syntax. 12 | 13 | ## Installation 14 | You'll need: 15 | * Debian Linux (tested on bullseye, should work on most previous versions) 16 | * Sudo privelleges 17 | * To be in the docker group (on any user where you'll be running a crontab) 18 | * The Docker container engine along with the docker compose plugin. 19 | 20 | Once you have all of that, it takes just one command to install Tugboat. 21 | ``` 22 | curl https://raw.githubusercontent.com/teknowafel/Tugboat/main/update.sh | sudo bash 23 | ``` 24 | *This command can be run again to update Tugboat should there be a new update* 25 | 26 | ## Setup 27 | Place your docker compose files for your stacks in the `~/.tugboat/stacks` directory, or in the `/share` directory of your configuration repository. Edit your user's crontab to automatically update/start/stop your stacks and (optionally) config. 28 | ``` 29 | #/etc/crontab 30 | 31 | 0 * * * * tugboat update-config git@github.com:teknowafel/tugboat-config.git 32 | 33 | * * * * * tugboat update test 34 | ``` 35 | *Editing /etc/crontab directly is not recommended* 36 | 37 | *Note: docker compose files must end in `.yml` and not `.yaml`* 38 | 39 | You're pretty much done now. To view Tugboat's logs, run `tugboat logs`. You can clear the logs using `tugboat logs clear`. 40 | 41 | ### Stacks 42 | Stacks are stored in ~/.tugboat/stacks, or optionally in a git repository in the /stacks directory. 43 | 44 | ### GitOps configuration (optional) 45 | Tugboat supports the use of a git repository for storing configuration, and if GitOps is enabled, Tugboat will automatically pull the configuration periodically. Git needs to be configured to have permission to pull from the configuration repository. The recommended method for ensuring this is using an ssh public key. For Tugboat to use your git repository for configuration, add a cronjob like this (when to update is for you to decide) 46 | 47 | ``` 48 | 0 * * * * tugboat update-config git@github.com:teknowafel/tugboat-config.git 49 | ``` 50 | `"git@github.com:teknowafel/tugboat-config.git"` can be replaced with the URL to your own configuration repo. 51 | 52 | *Note: if you are using an ssh key to clone the repository, you may need to run `tugboat update-config` once manually to verify the authenticity of `github.com`. This should be a one-time process.* 53 | 54 | ## Use 55 | Tugboat's primary use case is in a cronjob like so 56 | ``` 57 | * * * * * tugboat update test 58 | ``` 59 | This way, updates can be automatically run using Linux's most powerful scheduling tool available. Tugboat also features various other commands. 60 | 61 | ## Syntax 62 | ``` 63 | tugboat {start|stop|update|update-config|logs} {stack_name|repo_url(for update-config)|clear(for logs)} 64 | ``` 65 | Stacks are pulled from ~/.tugboat/stacks or the git repo where you store your configuration. -------------------------------------------------------------------------------- /tugboat: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # If the user chooses to update a stack(s) 4 | if [[ "$1" == "update" ]]; then 5 | update=false 6 | 7 | diff=$(diff -s ~/.tugboat/stacks/$2.yml /var/tmp/tugboat/$2/docker-compose.yml 2>&1) 8 | identical="are identical" 9 | nosuch="No such file or directory" 10 | if [[ ! $diff =~ $identical ]] ; then 11 | echo "" 12 | update=true 13 | echo "Config has changed, $2 will be updated" >> /var/log/tugboat 14 | echo "Config has changed, $2 will be updated" 15 | elif [[ $diff =~ $nosuch ]]; then 16 | echo "Config was not there in the first place, $2 will be updated" >> /var/log/tugboat 17 | echo "Config was not there in the first place, $2 will be updated" 18 | fi 19 | 20 | mkdir -p /var/tmp/tugboat/$2 21 | rsync ~/.tugboat/stacks/$2.yml /var/tmp/tugboat/$2/docker-compose.yml 22 | 23 | # Pull the images and store the result in a variable 24 | pull=$(cd /var/tmp/tugboat/$2/ && docker compose pull 2>&1) 25 | # Create a variable to check if the pull is complete 26 | complete='Pull complete' 27 | 28 | # Use the regular expression to check that it has been pulled 29 | if [[ $pull =~ $complete ]]; then 30 | # Log if the pull was successful 31 | echo "Pulled new images, $2 will be updated" >> /var/log/tugboat 32 | echo "Pulled new images, $2 will be updated" 33 | update=true 34 | else 35 | # In the case that the stack is up to date 36 | echo "$2's images are already up to date" >> /var/log/tugboat 37 | echo "$2's images are already up to date" 38 | fi 39 | 40 | if [[ $update ]]; then 41 | # Attempt to start/recreate the stack 42 | up=$(cd /var/tmp/tugboat/$2 && docker compose up -d 2>&1) 43 | started="Started" 44 | running="Running" 45 | if [[ $up =~ $started ]]; then 46 | echo "Successfully updated and started stack $2" >> /var/log/tugboat 47 | echo "Successfully updated and started stack $2" 48 | elif [[ $up =~ $running ]]; then 49 | echo "Stack $2 is running" >> /var/log/tugboat 50 | echo "Stack $2 is running" 51 | fi 52 | else 53 | # Start it in case it has not been started already 54 | up=$(cd /var/tmp/tugboat/$2 && docker compose up -d 2>&1) 55 | started="Started" 56 | running="Running" 57 | if [[ $up =~ $running ]]; then 58 | echo "Stack $2 is running" >> /var/log/tugboat 59 | echo "Stack $2 is running" 60 | fi 61 | fi 62 | 63 | # If the user chooses to start a stack(s) 64 | elif [[ "$1" == "start" ]]; then 65 | # Make a directory for the stack chosen 66 | mkdir -p /var/tmp/tugboat/$2 67 | rsync ~/.tugboat/stacks/$2.yml /var/tmp/tugboat/$2/docker-compose.yml 68 | # Attempt to start the stack 69 | up=$(cd /var/tmp/tugboat/$2 && docker compose up -d 2>&1) 70 | started="Started" 71 | running="Running" 72 | if [[ $up =~ $started ]]; then 73 | echo "Successfully started stack $2" >> /var/log/tugboat 74 | echo "Successfully started stack $2" 75 | elif [[ $up =~ $running ]]; then 76 | echo "Stack $2 is running" >> /var/log/tugboat 77 | echo "Stack $2 is running" 78 | else 79 | echo "Error starting stack $2, $up" >> /var/log/tugboat 80 | echo "Error starting stack $2, $up" 81 | fi 82 | 83 | # If the user chooses to stop a stack(s) 84 | elif [[ "$1" == "stop" ]]; then 85 | 86 | # Stop the chosen stack 87 | down=$(cd /var/tmp/tugboat/$2 && docker compose down 2>&1) 88 | removed="Removed" 89 | if [[ $down =~ $removed ]]; then 90 | echo "Successfully stopped stack $2" >> /var/log/tugboat 91 | echo "Successfully stopped stack $2" 92 | fi 93 | 94 | # If the user wishes to update configuration from a git repository 95 | elif [[ "$1" == "update-config" ]]; then 96 | clone=$(git clone $2 ~/.tugboat 2>&1) 97 | exists="already exists and is not an empty directory." 98 | done="done" 99 | cloning="Cloning into" 100 | if [[ $clone =~ $exists || $clone =~ $done || $clone =~ $cloning ]]; then 101 | pull=$(cd ~/.tugboat && git pull 2>&1) 102 | uptodate="Already up to date." 103 | if [[ ! $pull =~ $uptodate ]]; then 104 | echo "Updated config" >> /var/log/tugboat 105 | echo "Updated config" 106 | echo $pull >> /var/log/tugboat 107 | echo $pull 108 | fi 109 | else 110 | echo "Error updating config, $clone" >> /var/log/tugboat 111 | echo "Error updating config, $clone" 112 | fi 113 | 114 | # If the user wishes to view logs 115 | elif [[ "$1" == "logs" ]]; then 116 | if [[ "$2" == "clear" ]]; then 117 | echo "Logs have been cleared." > /var/log/tugboat 118 | echo "Logs have been cleared." 119 | else 120 | echo "You are now viewing the logs in real time, press CTRL+C to quit" 121 | echo 122 | tail -f /var/log/tugboat 123 | fi 124 | else 125 | echo "Invalid command" >> /var/log/tugboat 126 | echo "Invalid command" 127 | fi 128 | --------------------------------------------------------------------------------