Plugin creation
A plugin can be a simple implementation of triggers or can implement a command structure of its own. Dokku has no restrictions on the language in which a plugin is implemented; it only cares that the plugin implements the appropriate commands or triggers for the API. NOTE: any file that implements triggers or uses the command API must be executable.
If you create your own plugin:
- Take a look at the plugins shipped with Dokku and hack away!
- Check out the list of triggers your plugin can implement
- Upload your plugin to GitHub with a repository name following the
dokku-<name>
convention (e.g.dokku-mariadb
) - Edit this page and add a link to your plugin
- Subscribe to the dokku development blog to be notified about API changes and releases
Compilable plugins (Golang, Java(?), C, etc.)
When developing a plugin, you must implement the install
trigger such that it outputs the built executable(s) using a directory structure that implements the plugin's desired command and/or triggers the API. See the smoke-test-plugin for an example.
Command API
There are 3 main integration points: commands
, subcommands/default
, and subcommands/<command-name>
.
commands
Primarily used to supply the plugin's usage/help output. (i.e. plugin help).
subcommands/default
Implements the plugin's default command behavior. (i.e. dokku plugin
).
subcommands/<command-name>
Implements the additional command interface and will translate to dokku plugin:cmd
on the command line. (i.e. dokku plugin:install
).
Sample plugin
The below plugin is a dummy dokku hello
plugin.
hello/subcommands/default
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
hello_main_cmd() {
declare desc="prints Hello \$APP"
local cmd="hello"
# Support --app/$DOKKU_APP_NAME flag
# Use the following lines to reorder args into "$cmd $DOKKU_APP_NAME $@""
local argv=("$@")
[[ ${argv[0]} == "$cmd" ]] && shift 1
[[ -n $DOKKU_APP_NAME ]] && set -- $DOKKU_APP_NAME $@
set -- $cmd $@
##
[[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on"
verify_app_name "$2"
local APP="$2";
echo "Hello $APP"
}
hello_main_cmd "$@"
hello/subcommands/world
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
hello_world_cmd() {
declare desc="prints Hello World"
local cmd="hello:world"
# Support --app/$DOKKU_APP_NAME flag
# Use the following lines to reorder args into "$cmd $DOKKU_APP_NAME $@""
local argv=("$@")
[[ ${argv[0]} == "$cmd" ]] && shift 1
[[ -n $DOKKU_APP_NAME ]] && set -- $DOKKU_APP_NAME $@
set -- $cmd $@
##
[[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on"
verify_app_name "$2"
local APP="$2";
echo "Hello world"
}
hello_world_cmd "$@"
hello/commands
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
case "$1" in
help | hello:help)
help_content_func () {
declare desc="return help_content string"
cat<<help_content
hello <app>, Says "Hello <app>"
hello:world, Says "Hello world"
help_content
}
if [[ $1 = "hello:help" ]] ; then
echo -e 'Usage: dokku hello[:world] [<app>]'
echo ''
echo 'Say Hello World.'
echo ''
echo 'Example:'
echo ''
echo '$ dokku hello:world'
echo 'Hello world'
echo ''
echo 'Additional commands:'
help_content_func | sort | column -c2 -t -s,
else
help_content_func
fi
;;
*)
exit $DOKKU_NOT_IMPLEMENTED_EXIT
;;
esac
Each plugin requires a plugin.toml
descriptor file with the following required fields:
A few notes:
- Remember to
chmod +x
your executable files - Always support
DOKKU_TRACE
as per the 2nd line of the above example - If your command depends on an application, include a check for whether that application exists (see the above example)
- You must implement a
help
command, though you may leave it empty. Also, you must use commas (,
) in the command syntax to support output in columns - Commands should be namespaced
- As of 0.3.3, a catch-all should be implemented that exits with a
DOKKU_NOT_IMPLEMENTED_EXIT
code. This allows Dokku to output acommand not found
message. -
Consider whether you want to include the
set -eo pipefail
option. Look at the following example :
If user/repo
doesn't exist, Dokku exits just before the awk
command and the dokku_log_fail
message will never go to STDOUT
. printed with echo. You would want to use set -e
in this case.
Here is the help
entry for set
:
help set
Options:
-e Exit immediately if a command exits with a non-zero status.
-o option-name
pipefail the return value of a pipeline is the status of
the last command to exit with a non-zero status,
or zero if no command exited with a non-zero status
dokku config:set --no-restart node-js-app KEY1=VALUE1 [KEY2=VALUE2 ...]
dokku config:unset --no-restart node-js-app KEY1 [KEY2 ...]
functions
file in your plugin for others to source
- You should consider all functions in that file to be publicly accessible by other plugins
- Any functions you want to keep private should reside in your plugin's trigger/
or commands/
directories
- As of 0.4.0, Dokku allows image tagging and deployment of tagged images
- This means hard-coding the $IMAGE
as dokku/$APP
is no longer sufficient
- You should now use get_running_image_tag()
and get_app_image_name()
as sourced from common/functions
(see the plugin triggers doc for examples). Note: This is only for plugins that are not pre/post-build-*
plugins
- As of 0.5.0, we use container labels to help cleanup intermediate containers with dokku cleanup
- This means that if you manually call
docker run, you should include
$DOKKU_GLOBAL_RUN_ARGSto ensure your intermediate containers are labeled correctly
- As of 0.6.0, you should not **not** call the
dokkubinary directly from within plugins because clients using the
--appargument are potentially broken when doing so (as well as other issues)
- You should instead source the
functions` file for a given plugin when attempting to call Dokku internal functions