`docker ps -f name=<app>` is a SUBSTRING match, and instance slugs are <type>_<id> — so the base app's name is a prefix of every instance of it. `name=bookstack` also selected bookstack_home, bookstack_test and their -db containers, which meant start, stop, restart and remove all silently operated on every instance of an app instead of the one named. Worst of the four is remove: `libreportal app remove bookstack` ran `docker rm` against its instances' containers too. Multi-instance made this reachable — the naming scheme it introduced is exactly what turns the base name into a prefix. Each app and instance is already its own compose project, named for its directory, so the project label addresses exactly the containers belonging to that app. app_install.sh's own post-install check already used this label; the lifecycle operations did not. Found while tracing the IP allocation problem: bookstack_work had vanished, and checking how uninstall selects containers turned this up. To be clear about attribution — this bug does NOT explain that disappearance. The log shows an explicit uninstall of bookstack_work, including its own install folder and log, which container-level over-matching cannot do. I could not attribute that removal to a specific command and am not going to guess; the instance has been recreated. Verified: with the fix, `libreportal app stop bookstack` stops bookstack and bookstack-db and leaves bookstack_home and bookstack_test running. Before it, all six went down. All four Bookstack apps and Stoat serve 200 afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
27 lines
1.3 KiB
Bash
Executable File
27 lines
1.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
dockerRemoveApp()
|
|
{
|
|
local app_name="$1"
|
|
|
|
if [[ -z "$app_name" ]]; then
|
|
isNotice "No app name provided. Unable to stop and remove containers."
|
|
fi
|
|
|
|
isNotice "Stopping and removing Docker containers for '$app_name'. Please wait..."
|
|
|
|
# Stop and remove containers in one go
|
|
# Scope by compose project, NOT by name. `docker ps -f name=<app>` is a
|
|
# SUBSTRING match, so with multi-instance apps the base app's name is a prefix
|
|
# of every instance of it: `name=bookstack` also matched bookstack_home and
|
|
# bookstack_test (and their -db containers), so an operation aimed at one app
|
|
# silently hit all of its instances. Each app and instance is its own compose
|
|
# project (named for its directory), so the project label addresses exactly
|
|
# the containers that belong to this app and nothing else.
|
|
local result; result=$(dockerCommandRun "docker ps -aq --filter label=com.docker.compose.project=$app_name | xargs -r docker stop" >/dev/null 2>&1)
|
|
checkSuccess "Stopped Docker containers matching '$app_name'"
|
|
|
|
local result; result=$(dockerCommandRun "docker ps -aq --filter label=com.docker.compose.project=$app_name | xargs -r docker rm" >/dev/null 2>&1)
|
|
checkSuccess "Removed Docker containers matching '$app_name'"
|
|
}
|