feat: add initial support for cloud native buildpacks

This change adds a new builder - builder-cnb - via the 'DOKKU_CNB_EXPERIMENTAL' environment variable. While support for customizing pack builds is not currently implemented and there may be other missing functionality, this initial implementation allows folks to start playing with CNB.

Future releases of Dokku will provide tighter CNB integration and eventually switch to CNB for default building, as well as allow users to better select builders needed for their applications.

All new code for CNB support should be considered experimental and subject to change as the support evolves over time.
This commit is contained in:
Jose Diaz-Gonzalez
2020-12-01 14:49:39 -05:00
parent 98f03c249b
commit 451abcf8f3
18 changed files with 240 additions and 17 deletions

View File

@@ -0,0 +1 @@
hook

View File

@@ -0,0 +1 @@
hook

View File

@@ -0,0 +1 @@
hook

View File

@@ -0,0 +1 @@
hook

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
trigger-builder-cnb-builder-build() {
declare desc="builder-cnb builder-build plugin trigger"
declare trigger="builder-build"
declare BUILDER_TYPE="$1" APP="$2" SOURCECODE_WORK_DIR="$3"
if [[ "$BUILDER_TYPE" != "cnb" ]]; then
return
fi
if ! command -v "pack" &>/dev/null; then
dokku_log_fail "Missing pack, install it"
fi
local IMAGE=$(get_app_image_name "$APP")
pushd "$SOURCECODE_WORK_DIR" &>/dev/null
local TMP_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
trap "rm -rf '$TMP_FILE' >/dev/null" RETURN INT TERM
config_export app "$APP" --format envfile --merged > "$TMP_FILE"
plugn trigger pre-build-cnb "$APP" "$SOURCECODE_WORK_DIR"
pack build "$IMAGE" --builder heroku/buildpacks --path "$SOURCECODE_WORK_DIR" --default-process web
echo "FROM $IMAGE" | suppress_output "$DOCKER_BIN" image build --label=com.dokku.image-stage=build --label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP --label=dokku -t "$IMAGE" -
plugn trigger post-build-cnb "$APP" "$SOURCECODE_WORK_DIR"
}
trigger-builder-cnb-builder-build "$@"

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
trigger-builder-cnb-builder-release() {
declare desc="builder-cnb builder-release plugin trigger"
declare trigger="builder-release"
declare BUILDER_TYPE="$1" APP="$2" IMAGE_TAG="$3"
if [[ "$BUILDER_TYPE" != "cnb" ]]; then
return
fi
plugn trigger pre-release-cnb "$APP" "$IMAGE_TAG"
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
echo "FROM $IMAGE" | suppress_output "$DOCKER_BIN" image build --label=com.dokku.image-stage=release --label=com.dokku.app-name=$APP --label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=dokku -t "$IMAGE" -
plugn trigger post-release-cnb "$APP" "$IMAGE_TAG"
}
trigger-builder-cnb-builder-release "$@"

View File

@@ -0,0 +1,4 @@
[plugin]
description = "dokku core builder-cnb plugin"
version = "0.21.4"
[plugin.config]

View File

@@ -12,7 +12,6 @@ trigger-builder-dockerfile-builder-release() {
return
fi
# buildstep plugins don't necessarily make sense for dockerfiles. call the new breed!!!
plugn trigger pre-release-dockerfile "$APP" "$IMAGE_TAG"
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")

View File

@@ -293,20 +293,41 @@ get_running_image_tag() {
echo "$RUNNING_IMAGE_TAG"
}
is_image_cnb_based() {
declare desc="returns true if app image is based on cnb"
declare IMAGE="$1"
if [[ -z "$IMAGE" ]]; then
return 1
fi
CNB_STACK_ID="$("$DOCKER_BIN" image inspect --format '{{ index .Config.Labels "io.buildpacks.stack.id" }}' "$IMAGE")"
if [[ -n "$CNB_STACK_ID" ]]; then
return 0
fi
return 1
}
is_image_herokuish_based() {
declare desc="returns true if app image is based on herokuish"
declare desc="returns true if app image is based on herokuish or a buildpack-like env"
declare IMAGE="$1" APP="$2"
local DOKKU_APP_USER
if [[ -n "$APP" ]]; then
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
fi
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
local USER_VALUE
if [[ -z "$IMAGE" ]]; then
return 1
fi
if is_image_cnb_based "$IMAGE"; then
return 0
fi
if [[ -n "$APP" ]]; then
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
fi
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
# due to how the build process works, all herokuish images have the Environment variable USER=$DOKKU_APP_USER
USER_VALUE="$("$DOCKER_BIN" image inspect --format '{{range .Config.Env}}{{if eq . "USER='"$DOKKU_APP_USER"'"}}{{println .}}{{end}}{{end}}' "$IMAGE")"
[[ "$USER_VALUE" == "" ]] && return 1
@@ -566,6 +587,11 @@ dokku_release() {
declare desc="release phase"
declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3"
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
if is_image_cnb_based "$IMAGE"; then
IMAGE_SOURCE_TYPE="cnb"
fi
plugn trigger builder-release "$IMAGE_SOURCE_TYPE" "$APP" "$IMAGE_TAG"
}
@@ -630,9 +656,17 @@ dokku_receive() {
local IMAGE=$(get_app_image_name "$APP")
local IMAGE_SOURCE_TYPE="$2"
local TMP_WORK_DIR="$3"
local DOKKU_SKIP_CLEANUP="$(config_get "$APP" DOKKU_SKIP_CLEANUP || true)"
docker_cleanup "$APP"
dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE..."
local DOKKU_CNB_EXPERIMENTAL="$(config_get "$APP" DOKKU_CNB_EXPERIMENTAL || true)"
if [[ "$DOKKU_CNB_EXPERIMENTAL" == "1" ]]; then
IMAGE_SOURCE_TYPE="cnb"
dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE (experimental)..."
else
dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE..."
fi
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_APP_TYPE="$IMAGE_SOURCE_TYPE"
dokku_build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR"
plugn trigger release-and-deploy "$APP"

View File

@@ -72,7 +72,8 @@ trigger-scheduler-docker-local-scheduler-enter() {
local EXEC_CMD=""
has_tty && local DOKKU_RUN_OPTS+=" -i -t"
local IMAGE="$("$DOCKER_BIN" container inspect --format '{{ .Config.Image }}' "$CONTAINER_ID")"
is_image_herokuish_based "$IMAGE" "$APP" && local EXEC_CMD="/exec"
is_image_herokuish_based "$IMAGE" "$APP" && EXEC_CMD="/exec"
is_image_cnb_based "$IMAGE" && EXEC_CMD="" && DOKKU_RUN_OPTS+=" -w /app"
# shellcheck disable=SC2086
"$DOCKER_BIN" container exec $DOKKU_RUN_OPTS "$CONTAINER_ID" $EXEC_CMD "${@:-$DOKKU_APP_SHELL}"
}