├── LICENSE ├── README.md ├── commands ├── docker-args ├── install ├── pre-delete ├── pre-deploy └── pre-release /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Stuart P. Bentley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dokku-rethinkdb-plugin 2 | 3 | This project provides a plugin for [Dokku][] to create linked [RethinkDB][] 4 | containers for apps. 5 | 6 | [Dokku]: https://github.com/progrium/dokku 7 | [RethinkDB]: http://www.rethinkdb.com/ 8 | 9 | ## Features 10 | 11 | - **No dependencies** (other than a recent development version of Dokku.) 12 | *Wow!* 13 | - **Deletes cleanly with apps.** *Oh my!* 14 | - **Survives reboots, cleanups, and redeploys.** *Holy cow!* 15 | - **Can add before or after pushing an app.** *Am I dreaming?* 16 | - **Allows access to admin ports through binding to host interfaces.** *Is this 17 | real life?* 18 | 19 | ![Vince McMahon reacts to dokku-rethinkdb-plugin](http://i.imgur.com/ef28TQS.gif) 20 | 21 | **dokku-rethinkdb-plugin**: The [Gary Strydom][] of Dokku datastore plugins. 22 | 23 | [Gary Strydom]: http://forum.bodybuilding.com/showthread.php?t=157841203&s=714b6c7c5685fc9feb106e0680a2fa1e&p=1155029043&viewfull=1#post1155029043 24 | 25 | ## Installation 26 | 27 | ```bash 28 | cd /var/lib/dokku/plugins 29 | git clone https://github.com/stuartpb/dokku-rethinkdb-plugin rethinkdb 30 | dokku plugins-install 31 | ``` 32 | 33 | ## Simple usage 34 | 35 | Create a new container for a named app: 36 | 37 | ``` 38 | $ dokku rethinkdb:create foo # or "ssh dokku@server -t" client-side 39 | 40 | -----> Creating new container: rethinkdb/foo 41 | ``` 42 | 43 | Deploy an app to that name (client side): 44 | 45 | ``` 46 | $ git remote add dokku dokku@server:foo 47 | $ git push dokku master 48 | Counting objects: 155, done. 49 | Delta compression using up to 4 threads. 50 | Compressing objects: 100% (70/70), done. 51 | Writing objects: 100% (155/155), 22.44 KiB | 0 bytes/s, done. 52 | Total 155 (delta 92), reused 131 (delta 80) 53 | remote: -----> Building foo ... 54 | remote: Ruby/Rack app detected 55 | remote: -----> Using Ruby version: ruby-2.0.0 56 | 57 | ... blah blah blah ... 58 | 59 | remote: -----> Deploying foo ... 60 | remote: -----> Starting linked container rethinkdb_foo ... 61 | remote: Container ID: 99797e35d7b9 62 | remote: Container IP: 172.16.0.104 63 | remote: -----> Deploy complete! 64 | remote: -----> Cleaning up ... 65 | remote: -----> Cleanup complete! 66 | remote: =====> Application deployed: 67 | remote: http://foo.server 68 | ``` 69 | 70 | These steps can be done in either order - if an app has been pushed to the 71 | server, "rethinkdb:create" will re-deploy it with the RethinkDB container 72 | linked. 73 | 74 | The container will be exposed in the config/app environment as `RETHINKDB_HOST` 75 | and `RETHINKDB_PORT`, as well as `RDB_HOST` and `RDB_PORT` (the names used by 76 | the RethinkDB example apps). 77 | 78 | ## Advanced usage 79 | 80 | *All of these commands are detailed when running `dokku help`.* 81 | 82 | Bind a port on the host to the Web Admin UI for a RethinkDB container: 83 | 84 | ``` 85 | dokku rethinkdb:bind-webui [host port] 86 | ``` 87 | 88 | Bind a port on the host to the cluster port (as used by the RethinkDB CLI) for 89 | a RethinkDB container: 90 | 91 | ``` 92 | dokku rethinkdb:bind-cluster [host port] 93 | ``` 94 | 95 | Release a RethinkDB container's bindings to host ports (does not affect links 96 | to the associated app): 97 | 98 | ``` 99 | dokku rethinkdb:unbind 100 | ``` 101 | 102 | Unlink and delete the RethinkDB container and data for an app: 103 | 104 | ``` 105 | dokku rethinkdb:delete 106 | ``` 107 | 108 | Read app RethinkDB container logs: 109 | 110 | ``` 111 | dokku rethinkdb:logs 112 | ``` 113 | 114 | Get RethinkDB container ID, IP, and any bound ports: 115 | 116 | ``` 117 | dokku rethinkdb:info 118 | ``` 119 | 120 | (Re)start a RethinkDB container independently of a running app: 121 | 122 | ``` 123 | dokku rethinkdb:start 124 | ``` 125 | 126 | Stop an app's running RethinkDB container: 127 | 128 | ``` 129 | dokku rethinkdb:stop 130 | ``` 131 | 132 | (Re)set environment variables to direct to a linked RethinkDB container: 133 | 134 | ``` 135 | dokku rethinkdb:link 136 | ``` 137 | -------------------------------------------------------------------------------- /commands: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x 3 | 4 | RETHINKDB_IMAGE=rethinkdb:1.16.3 5 | 6 | PENDING_DIR="$DOKKU_ROOT/.rethinkdb/pending-volumes" 7 | 8 | # Check if name is specified 9 | if [[ $1 == rethinkdb:* ]]; then 10 | if [[ -z $2 ]]; then 11 | echo "You must specify an app name" 12 | exit 1 13 | else 14 | APP="$2" 15 | if [[ -d "$DOKKU_ROOT/$APP" ]]; then 16 | APP_EXISTS=true 17 | else 18 | APP_EXISTS=false 19 | fi 20 | fi 21 | 22 | VOLUME_DIR="" 23 | if [[ -d "$DOKKU_ROOT/$APP/rethinkdb" ]]; then 24 | VOLUME_DIR="$DOKKU_ROOT/$APP/rethinkdb" 25 | elif [[ -d "$PENDING_DIR/$APP" ]]; then 26 | VOLUME_DIR="$PENDING_DIR/$APP" 27 | fi 28 | BIND_FILE="$VOLUME_DIR/PUBLISH" 29 | 30 | CONTAINER_NAME="rethinkdb_$APP" 31 | ENV_FILE="$DOKKU_ROOT/$APP/ENV" 32 | fi 33 | 34 | config_restart_app() { 35 | local APP="$1"; 36 | 37 | echo "-----> Releasing $APP ..." 38 | dokku release $APP 39 | echo "-----> Release complete!" 40 | echo "-----> Deploying $APP ..." 41 | dokku deploy $APP 42 | echo "-----> Deploy complete!" 43 | } 44 | 45 | docker_get_id() { 46 | local CID=`docker inspect '-f={{.Id}}' "$1" 2> /dev/null || true` 47 | if [[ "$CID" == "" ]]; then 48 | CID=`docker inspect '-f={{.ID}}' "$1" 2> /dev/null || true` 49 | fi 50 | echo "$CID" 51 | } 52 | 53 | docker_inspect_port() { 54 | local NAME PORT DUMP 55 | NAME="$1" 56 | PORT="$2" 57 | DUMP="{{(index (index .NetworkSettings.Ports \"$PORT/tcp\") 0).HostPort}}" 58 | docker inspect "-format=$DUMP" $NAME 2> /dev/null || true 59 | } 60 | 61 | bind_port() { 62 | local CONTAINER_PORT="$1" 63 | local HOST_PORT="$2" 64 | if [[ -z HOST_PORT ]]; then 65 | PORT_BINDING="$CONTAINER_PORT" 66 | else 67 | PORT_BINDING="$HOST_PORT:$CONTAINER_PORT" 68 | fi 69 | 70 | if [[ -f $BIND_FILE ]]; then 71 | sed -i "/$CONTAINER_PORT\$/ d" $BIND_FILE 72 | fi 73 | 74 | echo $PORT_BINDING >>"$BIND_FILE" 75 | } 76 | 77 | case "$1" in 78 | rethinkdb:create) 79 | 80 | # Check if an existing DB volume exists 81 | if [[ -d $VOLUME_DIR ]]; then 82 | echo "-----> Reusing $CONTAINER_NAME data" 83 | else 84 | echo "-----> Creating new RethinkDB volume for $APP" 85 | if $APP_EXISTS; then 86 | VOLUME_DIR="$DOKKU_ROOT/$APP/rethinkdb" 87 | else 88 | VOLUME_DIR="$PENDING_DIR/$APP" 89 | fi 90 | mkdir -p "$VOLUME_DIR" 91 | chown -R dokku:dokku "$VOLUME_DIR" 92 | # Container will be linked in pre-release hook 93 | fi 94 | 95 | if $APP_EXISTS; then 96 | # Container will be launched in pre-deploy hook 97 | dokku rethinkdb:link $APP 98 | config_restart_app $APP 99 | fi 100 | ;; 101 | 102 | rethinkdb:delete) 103 | # Stop the container 104 | ID=$(docker_get_id "$CONTAINER_NAME") 105 | if [[ ! -z $ID ]]; then 106 | docker kill $ID > /dev/null 107 | docker rm $ID > /dev/null 108 | fi 109 | 110 | # Remove persistent volume 111 | if [[ -d "$VOLUME_DIR" ]]; then 112 | rm -rf "$VOLUME_DIR" 113 | fi 114 | if [[ -d "$PENDING_DIR/$APP" ]]; then 115 | rm -rf "$PENDING_DIR/$APP" 116 | fi 117 | 118 | if [[ -f $ENV_FILE ]]; then 119 | sed -i '/^export (?:RETHINKDB|RDB)_HOST=$RETHINKDB_LINK_PORT_28015_TCP_ADDR$/ d' $ENV_FILE 120 | sed -i '/^export (?:RETHINKDB|RDB)_PORT=$RETHINKDB_LINK_PORT_28015_TCP_PORT$/ d' $ENV_FILE 121 | fi 122 | echo "-----> RethinkDB container deleted: $CONTAINER_NAME" 123 | if $APP_EXISTS; then 124 | config_restart_app $APP 125 | fi 126 | ;; 127 | 128 | rethinkdb:link) 129 | if $APP_EXISTS; then 130 | # Add aliases for RETHINKDB variables 131 | if [ -f $ENV_FILE ]; then 132 | sed -i "/^export (?:RETHINKDB|RDB)_(?:HOST|PORT)=/ d" $ENV_FILE 133 | fi 134 | cat >>$ENV_FILE <<"EOF" 135 | export RETHINKDB_HOST=$RETHINKDB_LINK_PORT_28015_TCP_ADDR 136 | export RETHINKDB_PORT=$RETHINKDB_LINK_PORT_28015_TCP_PORT 137 | export RDB_HOST=$RETHINKDB_LINK_PORT_28015_TCP_ADDR 138 | export RDB_PORT=$RETHINKDB_LINK_PORT_28015_TCP_PORT 139 | EOF 140 | else 141 | echo "Cannot link non-existing app" 142 | exit 1 143 | fi 144 | ;; 145 | 146 | rethinkdb:bind-webui) 147 | if [[ -z $VOLUME_DIR ]]; then 148 | echo "No RethinkDB volume found for $APP" 149 | exit 1 150 | fi 151 | bind_port 8080 "$3" 152 | if $APP_EXISTS; then 153 | dokku deploy $APP 154 | else 155 | dokku rethinkdb:start $app 156 | fi 157 | ;; 158 | 159 | rethinkdb:bind-cluster) 160 | if [[ -z $VOLUME_DIR ]]; then 161 | echo "No RethinkDB volume found for $APP" 162 | exit 1 163 | fi 164 | bind_port 29015 "$3" 165 | if $APP_EXISTS; then 166 | dokku deploy $APP 167 | else 168 | dokku rethinkdb:start $app 169 | fi 170 | ;; 171 | 172 | rethinkdb:unbind) 173 | if [[ -z $VOLUME_DIR ]]; then 174 | echo "No RethinkDB volume found for $APP" 175 | exit 1 176 | fi 177 | if [ -f $BIND_FILE ]; then 178 | rm $BIND_FILE 179 | fi 180 | if $APP_EXISTS; then 181 | dokku deploy $APP 182 | else 183 | dokku rethinkdb:start $app 184 | fi 185 | ;; 186 | 187 | rethinkdb:stop) 188 | ID=$(docker_get_id "$CONTAINER_NAME") 189 | if [[ ! -z "$ID" ]]; then 190 | docker stop $ID > /dev/null 191 | fi 192 | ;; 193 | 194 | rethinkdb:start) 195 | if [[ -z $VOLUME_DIR ]]; then 196 | echo "No RethinkDB volume found for $APP" 197 | exit 1 198 | fi 199 | 200 | dokku rethinkdb:stop $APP 201 | ID=$(docker_get_id "$CONTAINER_NAME") 202 | if [[ ! -z "$ID" ]]; then 203 | docker rm $ID > /dev/null 204 | fi 205 | 206 | PORTS=() 207 | DYNAMIC_PORTS=() 208 | if [[ -f "$BIND_FILE" ]]; then 209 | while read line; do 210 | PORTS+=("-p" "$line") 211 | if [[ ! "$line" =~ [0-9]+\:[0-9]+$ ]]; then 212 | DYNAMIC_PORTS+=("$line") 213 | fi 214 | done < $BIND_FILE 215 | fi 216 | 217 | VOLUME="$VOLUME_DIR:/rethinkdb" 218 | 219 | docker run -v $VOLUME --name=$CONTAINER_NAME \ 220 | ${PORTS[@]} -d $RETHINKDB_IMAGE 221 | 222 | # Save all dynamic port bindings as static bindings 223 | for port in "${DYNAMIC_PORTS[@]}"; do 224 | HOST_PORT=$(docker_inspect_port $CONTAINER_NAME $port) 225 | sed -i "s/^$port\$/$HOST_PORT:$port/" $BIND_FILE 226 | done 227 | 228 | dokku rethinkdb:info $APP 229 | ;; 230 | 231 | rethinkdb:info) 232 | ID=$(docker_get_id "$CONTAINER_NAME") 233 | if [[ -z "$ID" ]]; then 234 | echo "No container found for $APP" 235 | exit 1 236 | else 237 | IP=$(docker inspect -f '{{.NetworkSettings.IPAddress}}' $ID) 238 | echo " Container ID: ${ID:0:12}" 239 | echo " Container IP: ${IP}" 240 | WEBUI_PORT=$(docker_inspect_port $ID 8080) 241 | if [[ ! -z "$WEBUI_PORT" ]]; then 242 | echo " WebUI public port: $WEBUI_PORT" 243 | fi 244 | CLUSTER_PORT=$(docker_inspect_port $ID 29015) 245 | if [[ ! -z "$CLUSTER_PORT" ]]; then 246 | echo " Cluster public port: $CLUSTER_PORT" 247 | fi 248 | fi 249 | ;; 250 | 251 | rethinkdb:logs) 252 | ID=$(docker_get_id "$CONTAINER_NAME") 253 | docker logs $ID | tail -n 100 254 | ;; 255 | 256 | help) 257 | cat && cat< Create a RethinkDB container 259 | rethinkdb:delete Delete specified RethinkDB container 260 | rethinkdb:bind-webui [host port] Bind app's RethinkDB container WebUI to host port 261 | rethinkdb:bind-cluster [host port] Bind app's RethinkDB cluster port to host 262 | rethinkdb:unbind Unbind app RethinkDB container host port bindings 263 | rethinkdb:logs Display last logs from RethinkDB container 264 | rethinkdb:info Display RethinkDB container address and ports 265 | rethinkdb:link Set app config to link to RethinkDB container 266 | rethinkdb:start (Re)start app's RethinkDB container 267 | rethinkdb:stop Stop app's RethinkDB container 268 | EOF 269 | ;; 270 | 271 | esac 272 | -------------------------------------------------------------------------------- /docker-args: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x 3 | 4 | APP="$1" 5 | 6 | CONTAINER_NAME="rethinkdb_$APP" 7 | VOLUME_DIR="$DOKKU_ROOT/$APP/rethinkdb" 8 | 9 | cat 10 | 11 | if [[ -d "$VOLUME_DIR" ]]; then 12 | echo "--link $CONTAINER_NAME:rethinkdb_link" 13 | fi 14 | -------------------------------------------------------------------------------- /install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x 3 | 4 | RETHINKDB_IMAGE=rethinkdb:1.16.0 5 | 6 | PENDING_DIR="$DOKKU_ROOT/.rethinkdb/pending-volumes" 7 | 8 | mkdir -p "$PENDING_DIR" 9 | chown -R dokku:dokku "$PENDING_DIR" 10 | 11 | docker pull $RETHINKDB_IMAGE 12 | -------------------------------------------------------------------------------- /pre-delete: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x 3 | 4 | APP="$1" 5 | 6 | CONTAINER_NAME="rethinkdb_$APP" 7 | 8 | docker_get_id() { 9 | local CID=`docker inspect '-f={{.Id}}' "$1" 2> /dev/null || true` 10 | if [[ "$CID" == "" ]]; then 11 | CID=`docker inspect '-f={{.ID}}' "$1" 2> /dev/null || true` 12 | fi 13 | echo "$CID" 14 | } 15 | 16 | # Kill any existing RethinkDB container for this app 17 | ID=$(docker_get_id "$CONTAINER_NAME") 18 | if [[ ! -z $ID ]]; then 19 | docker kill $ID > /dev/null 20 | docker rm $ID > /dev/null 21 | fi 22 | 23 | # Any volume will be deleted with the app 24 | -------------------------------------------------------------------------------- /pre-deploy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x 3 | 4 | APP="$1" 5 | 6 | CONTAINER_NAME="rethinkdb_$APP" 7 | VOLUME_DIR="$DOKKU_ROOT/$APP/rethinkdb" 8 | 9 | if [[ -d "$VOLUME_DIR" ]]; then 10 | echo "-----> Starting linked container $CONTAINER_NAME ..." 11 | dokku rethinkdb:start $APP 12 | fi 13 | -------------------------------------------------------------------------------- /pre-release: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x 3 | 4 | APP="$1" 5 | 6 | PENDING_DIR="$DOKKU_ROOT/.rethinkdb/pending-volumes" 7 | VOLUME_DIR="$DOKKU_ROOT/$APP/rethinkdb" 8 | 9 | # Grant and link any pending volumes 10 | if [[ -d "$DOKKU_ROOT/$APP" && -d "$PENDING_DIR/$APP" ]]; then 11 | mv "$PENDING_DIR/$APP" "$VOLUME_DIR" 12 | dokku rethinkdb:link $APP 13 | fi 14 | --------------------------------------------------------------------------------