#!/usr/bin/env bash set -eo pipefail shopt -s nullglob export DOKKU_DISTRO=${DOKKU_DISTRO:="ubuntu"} export DOKKU_IMAGE=${DOKKU_IMAGE:="progrium/buildstep"} export DOKKU_ROOT=${DOKKU_ROOT:=~dokku} export PLUGIN_PATH=${PLUGIN_PATH:="/var/lib/dokku/plugins"} export DOKKU_NOT_IMPLEMENTED_EXIT=10 export DOKKU_VALID_EXIT=0 export DOKKU_LOGS_DIR=${DOKKU_LOGS_DIR:="/var/log/dokku"} export DOKKU_EVENTS_LOGFILE=${DOKKU_EVENTS_LOGFILE:="$DOKKU_LOGS_DIR/events.log"} source "$PLUGIN_PATH/common/functions" [[ -f $DOKKU_ROOT/dokkurc ]] && source $DOKKU_ROOT/dokkurc [[ -d $DOKKU_ROOT/.dokkurc ]] && for f in $DOKKU_ROOT/.dokkurc/*; do source $f; done [[ $DOKKU_TRACE ]] && set -x parse_args "$@" args=("$@") if [[ "${args[0]}" =~ ^--.* ]]; then for arg in "$@"; do if [[ "$arg" =~ ^--.* ]];then shift 1 else break fi done fi ! has_tty && DOKKU_QUIET_OUTPUT=1 if [[ $(id -un) != "dokku" && $1 != plugins-install* && $1 != "plugins-update" ]]; then sudo -u dokku -E -H $0 "$@" exit fi if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then export -n SSH_ORIGINAL_COMMAND if [[ $1 =~ config-* ]] || [[ $1 =~ docker-options* ]];then xargs $0 <<<$SSH_ORIGINAL_COMMAND exit $? else $0 $SSH_ORIGINAL_COMMAND exit $? fi fi case "$1" in receive) APP="$2"; IMAGE="dokku/$APP"; IMAGE_SOURCE_TYPE="$3"; TMP_WORK_DIR="$4" dokku_log_info1 "Cleaning up..." dokku cleanup dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE..." dokku build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR" dokku_log_info1 "Releasing $APP..." dokku release "$APP" "$IMAGE_SOURCE_TYPE" dokku_log_info1 "Deploying $APP..." dokku deploy "$APP" dokku_log_info2 "Application deployed:" dokku urls "$APP" | sed "s/^/ /" echo ;; deploy) [[ -z $2 ]] && dokku_log_fail "Please specify an app to deploy" APP="$2"; IMAGE="dokku/$APP" verify_app_name "$APP" pluginhook pre-deploy $APP is_image_buildstep_based "$IMAGE" && DOKKU_BUILDSTEP=true DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" oldids=$(get_app_container_ids $APP) while read line || [ -n "$line" ] do PROC_TYPE=${line%%=*} PROC_COUNT=${line#*=} CONTAINER_INDEX=1 while [[ $CONTAINER_INDEX -le $PROC_COUNT ]];do id=""; port=""; ipaddr="" DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX" DOKKU_IP_FILE="$DOKKU_ROOT/$APP/IP.$PROC_TYPE.$CONTAINER_INDEX" DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX" # start the app DOCKER_ARGS=$(: | pluginhook docker-args $APP deploy) DOCKER_ARGS+=" -e DYNO=$PROC_TYPE " DOCKER_ARGS+=$(: | pluginhook docker-args-deploy $APP) BIND_EXTERNAL=$(pluginhook bind-external-ip $APP) [[ -n "$DOKKU_BUILDSTEP" ]] && START_CMD="/start $PROC_TYPE" if [[ -z "$DOKKU_BUILDSTEP" ]];then DOKKU_DOCKERFILE_PORT=$(dokku config:get $APP DOKKU_DOCKERFILE_PORT || true) START_CMD=$(dokku config:get $APP DOKKU_DOCKERFILE_START_CMD || $START_CMD) fi if [[ "$PROC_TYPE" == "web" ]]; then port=${DOKKU_DOCKERFILE_PORT:=5000} if [[ "$BIND_EXTERNAL" = "true" ]];then id=$(docker run -d -p $port -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD) port=$(docker port $id $port | sed 's/[0-9.]*://') ipaddr=127.0.0.1 else id=$(docker run -d -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD) ipaddr=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $id) fi else id=$(docker run -d $DOCKER_ARGS $IMAGE $START_CMD) fi # if we can't post-deploy successfully, kill new container kill_new() { docker inspect $id &> /dev/null && docker stop $id > /dev/null && docker kill $id > /dev/null trap - INT TERM EXIT kill -9 $$ } DOKKU_APP_SKIP_ALL_CHECKS=$(dokku config:get $APP DOKKU_SKIP_ALL_CHECKS || true) DOKKU_APP_SKIP_DEFAULT_CHECKS=$(dokku config:get $APP DOKKU_SKIP_DEFAULT_CHECKS || true) DOKKU_GLOBAL_SKIP_ALL_CHECKS=$(dokku config:get --global DOKKU_SKIP_ALL_CHECKS || true) DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS=$(dokku config:get --global DOKKU_SKIP_DEFAULT_CHECKS || true) DOKKU_SKIP_ALL_CHECKS=${DOKKU_APP_SKIP_ALL_CHECKS:="$DOKKU_GLOBAL_SKIP_ALL_CHECKS"} DOKKU_SKIP_DEFAULT_CHECKS=${DOKKU_APP_SKIP_DEFAULT_CHECKS:="$DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS"} # run checks first, then post-deploy hooks, which switches Nginx traffic if [[ "$DOKKU_SKIP_ALL_CHECKS" = "true" ]]; then dokku_log_info1 "Skipping pre-flight checks" else trap kill_new INT TERM EXIT dokku_log_info1 "Running pre-flight checks" pluginhook check-deploy $APP $id $PROC_TYPE $port $ipaddr trap - INT TERM EXIT fi # now using the new container [[ -n "$id" ]] && echo $id > "$DOKKU_CONTAINER_ID_FILE" [[ -n "$ipaddr" ]] && echo $ipaddr > "$DOKKU_IP_FILE" [[ -n "$port" ]] && echo $port > "$DOKKU_PORT_FILE" [[ -n "$port" ]] && echo "http://$(< "$DOKKU_ROOT/HOSTNAME"):$port" > "$DOKKU_ROOT/$APP/URL" # cleanup pre-migration files rm -f $DOKKU_ROOT/$APP/CONTAINER $DOKKU_ROOT/$APP/IP $DOKKU_ROOT/$APP/PORT CONTAINER_INDEX=$(( CONTAINER_INDEX + 1 )) done # cleanup when we scale down if [[ "$PROC_COUNT" == 0 ]]; then CONTAINER_IDX_OFFSET=0 else CONTAINER_IDX_OFFSET=$((PROC_COUNT + 1)) fi for container_state_filetype in CONTAINER IP PORT; do cd $DOKKU_ROOT/$APP find . -maxdepth 1 -name "$container_state_filetype.$PROC_TYPE.*" -printf "%f\n" | sort -t . -k 3 -n | tail -n +$CONTAINER_IDX_OFFSET | xargs rm -f done done < "$DOKKU_SCALE_FILE" dokku_log_info1 "Running post-deploy" pluginhook post-deploy $APP $port $ipaddr # kill the old container if [[ -n "$oldids" ]]; then if [[ -z "$DOKKU_WAIT_TO_RETIRE" ]];then DOKKU_APP_DOKKU_WAIT_TO_RETIRE=$(dokku config:get $APP DOKKU_WAIT_TO_RETIRE || true) DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE=$(dokku config:get --global DOKKU_WAIT_TO_RETIRE || true) DOKKU_WAIT_TO_RETIRE=${DOKKU_APP_DOKKU_WAIT_TO_RETIRE:="$DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE"} fi # Let the old container finish processing requests, before terminating it WAIT="${DOKKU_WAIT_TO_RETIRE:-60}" dokku_log_info1 "Shutting down old containers in $WAIT seconds" for oldid in $oldids; do dokku_log_info2 "$oldid" done ( exec >/dev/null 2>/dev/null /dev/null docker kill $oldid &> /dev/null # force a kill as docker seems to not send SIGKILL as the docs would indicate done ) & disown -a # Use trap since disown/nohup don't seem to keep child alive # Give child process just enough time to set the traps sleep 0.1 fi ;; cleanup) # delete all non-running container # shellcheck disable=SC2046 docker rm $(docker ps -a -f 'status=exited' -q) &> /dev/null || true # delete unused images # shellcheck disable=SC2046 docker rmi $(docker images -f 'dangling=true' -q) &> /dev/null & ;; plugins) ls -1 -d $PLUGIN_PATH/*/ ;; plugins-install) pluginhook install ;; plugins-install-dependencies) pluginhook dependencies ;; plugins-update) pluginhook update ;; # DEPRECATED as of v0.3.14 deploy:all) echo "*DEPRECATED* in v0.3.14: deploy:all will be removed in future versions" dokku ps:restartall ;; help|'') echo "Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND [command-specific-options]" echo "" echo "Options:" cat<