fix: keep previous image restartable after failed deploy

When a deploy failed, the old containers kept serving while `dokku/<app>:latest` still pointed at the failed image, so `ps:restart`, `ps:start`, and `ps:restore` would redeploy the broken release or fail with `App image not found` once that image was retired. The running image is now kept available during a build and deploy, the `latest` tag is restored to it when the build, release, or deploy fails, and `ps:retire` no longer removes the image an app's `latest` tag points at. Failed containers are also now registered for retirement under the correct app so they and their images are cleaned up.
This commit is contained in:
Jose Diaz-Gonzalez
2026-09-30 01:25:13 -04:00
parent 0e1b8b4793
commit f29fdae409
7 changed files with 338 additions and 8 deletions

View File

@@ -83,7 +83,7 @@ main() {
kill_new() {
declare desc="wrapper function to kill newly started app container"
declare CID="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3"
declare APP="$1" CID="$2" PROC_TYPE="$3" CONTAINER_INDEX="$4"
plugn trigger scheduler-register-retired "$APP" "$CID" "$DOKKU_WAIT_TO_RETIRE"
mkdir -p "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP"
@@ -98,7 +98,7 @@ main() {
}
# run checks first, then post-deploy hooks, which switches proxy traffic
trap "kill_new $cid $PROC_TYPE $CONTAINER_INDEX" INT TERM EXIT
trap "kill_new $APP $cid $PROC_TYPE $CONTAINER_INDEX" INT TERM EXIT
if [[ "$DOKKU_CHECKS_DISABLED" == "false" ]]; then
dokku_log_verbose "Attempting pre-flight checks ($PROC_TYPE.$CONTAINER_INDEX)"
plugn trigger check-deploy "$APP" "$cid" "$PROC_TYPE" "$DOKKU_PORT" "$ipaddr" "$CONTAINER_INDEX"

View File

@@ -224,6 +224,11 @@ fn-scheduler-docker-local-retire-images() {
continue
fi
if fn-scheduler-docker-local-image-is-app-latest "$RETIRE_APP" "$STATE"; then
dokku_log_warn "Image ${IMAGE_ID} is the current image for ${RETIRE_APP}, skipping rm"
continue
fi
dokku_log_verbose_quiet "Attempting to retire $RETIRE_APP image $IMAGE_ID"
if RM_OUTPUT="$("$DOCKER_BIN" image remove "$IMAGE_ID" 2>&1)"; then
DEAD_IMAGES+=("$IMAGE_ID")
@@ -262,6 +267,15 @@ fn-scheduler-docker-local-retire-images() {
sort -o "$DEAD_IMAGE_FILE" -r "$DEAD_IMAGE_FILE"
}
fn-scheduler-docker-local-image-is-app-latest() {
declare desc="returns 0 if IMAGE_ID is the image currently tagged as the app's latest image"
declare APP="$1" IMAGE_ID="$2"
local LATEST_IMAGE_ID
LATEST_IMAGE_ID="$("$DOCKER_BIN" image inspect --format "{{ .Id }}" "$(get_app_image_repo "$APP"):latest" 2>/dev/null || true)"
[[ -n "$LATEST_IMAGE_ID" ]] && [[ "$LATEST_IMAGE_ID" == "$IMAGE_ID" ]]
}
fn-scheduler-docker-local-register-retired() {
declare TYPE="$1" APP="$2" DOCKER_ID="$3" WAIT="$4"
local DEAD_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/dead-containers"