fix: skip retiring images still in use by app containers

When ps:rebuild runs against an image-based deploy via git:from-image, the resulting image often shares the same SHA as the previous deployment, so retiring the old container's image would target the live image of the new container. The retirement is now skipped when another running container of the same app still references the image, and the cron retire loop self-heals previously stuck entries the next time it encounters them.
This commit is contained in:
Jose Diaz-Gonzalez
2026-04-29 05:36:04 -04:00
parent 9b6c32f39c
commit d88e8f137f
4 changed files with 90 additions and 2 deletions

View File

@@ -243,6 +243,11 @@ fn-scheduler-docker-local-retire-images() {
fi
if echo "$RM_OUTPUT" | grep -q "image is being used by running container"; then
if fn-scheduler-docker-local-image-in-use-by-app "$RETIRE_APP" "$IMAGE_ID" ""; then
dokku_log_warn "Image ${IMAGE_ID} is still in use by ${RETIRE_APP}, removing from retire list"
DEAD_IMAGES+=("$IMAGE_ID")
continue
fi
dokku_log_warn "Image ${IMAGE_ID} has running containers, skipping rm"
continue
fi
@@ -273,6 +278,39 @@ fn-scheduler-docker-local-register-retired() {
fi
}
fn-scheduler-docker-local-image-in-use-by-app() {
declare desc="returns 0 if IMAGE_ID is used by an app container that is not already pending retirement"
declare APP="$1" IMAGE_ID="$2" EXCLUDE_CONTAINER_ID="$3"
local DEAD_CONTAINER_FILE="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/dead-containers"
local cid exclude_full_id container_image short_cid
if [[ -z "$IMAGE_ID" ]]; then
return 1
fi
if [[ -n "$EXCLUDE_CONTAINER_ID" ]]; then
exclude_full_id="$("$DOCKER_BIN" container inspect "$EXCLUDE_CONTAINER_ID" --format '{{.Id}}' 2>/dev/null || true)"
fi
for cid in $("$DOCKER_BIN" container ls -q --no-trunc -f label=com.dokku.app-name="$APP" 2>/dev/null); do
[[ -z "$cid" ]] && continue
if [[ -n "$exclude_full_id" ]] && [[ "$cid" == "$exclude_full_id" ]]; then
continue
fi
short_cid="${cid:0:12}"
if [[ -f "$DEAD_CONTAINER_FILE" ]] && grep -q "$short_cid" "$DEAD_CONTAINER_FILE"; then
continue
fi
container_image="$("$DOCKER_BIN" container inspect "$cid" --format '{{.Image}}' 2>/dev/null | cut -d: -f2 || true)"
if [[ -n "$container_image" ]] && [[ "$container_image" == "$IMAGE_ID" ]]; then
return 0
fi
done
return 1
}
fn-scheduler-docker-local-start-app-container() {
declare desc="starts a single app container"
declare APP="$1"

View File

@@ -21,12 +21,17 @@ trigger-scheduler-docker-local-scheduler-register-retired() {
if [[ -n "$IMAGE_ID" ]] && [[ -z "$DOKKU_SKIP_IMAGE_CLEANUP_REGISTRATION" ]]; then
ALT_IMAGE_TAGS="$("$DOCKER_BIN" image inspect --format '{{ index .Config.Labels "com.dokku.docker-image-labeler/alternate-tags" }}' "$IMAGE_ID" 2>/dev/null || true)"
fn-scheduler-docker-local-register-retired "image" "$APP" "$IMAGE_ID" "$WAIT"
if ! fn-scheduler-docker-local-image-in-use-by-app "$APP" "$IMAGE_ID" "$CONTAINER_ID"; then
fn-scheduler-docker-local-register-retired "image" "$APP" "$IMAGE_ID" "$WAIT"
fi
if [[ -n "$ALT_IMAGE_TAGS" ]]; then
ALT_IMAGE_TAG="$(echo "$ALT_IMAGE_TAGS" | jq -r ".[]")"
if [[ "$(plugn trigger git-get-property "$APP" "source-image")" != "$ALT_IMAGE_TAG" ]]; then
ALT_IMAGE_ID="$("$DOCKER_BIN" image inspect --format '{{ .Id }}' "$ALT_IMAGE_TAG" 2>/dev/null || true)"
fn-scheduler-docker-local-register-retired "image" "$APP" "$(echo "$ALT_IMAGE_ID" | cut -d ':' -f2)" "$WAIT"
ALT_IMAGE_ID="$(echo "$ALT_IMAGE_ID" | cut -d ':' -f2)"
if [[ -n "$ALT_IMAGE_ID" ]] && ! fn-scheduler-docker-local-image-in-use-by-app "$APP" "$ALT_IMAGE_ID" "$CONTAINER_ID"; then
fn-scheduler-docker-local-register-retired "image" "$APP" "$ALT_IMAGE_ID" "$WAIT"
fi
fi
fi
fi