Compare commits
2 Commits
b9d9d88552
...
728830f74d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
728830f74d | ||
|
|
2b77c8dfdd |
58
scripts/docker/command/stranded_containers.sh
Normal file
58
scripts/docker/command/stranded_containers.sh
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# A containers-root wipe (fresh install, or a relocation of the containers root)
|
||||||
|
# removes an app's project directory but NOT the container the daemon still holds
|
||||||
|
# in its own state. Those containers are stranded: their compose file, config and
|
||||||
|
# bind-mount sources are gone, so they can never start correctly again.
|
||||||
|
#
|
||||||
|
# They are not inert. `restart: unless-stopped` makes the daemon retry them on
|
||||||
|
# every restart, and Docker materialises each missing bind-mount source before
|
||||||
|
# handing off to runc — creating an empty DIRECTORY even where the mount is a
|
||||||
|
# file. That is how a fresh install ends up with <app>.config as a directory: the
|
||||||
|
# install restarts the rootless daemon, the daemon resurrects the previous
|
||||||
|
# install's container, and the stubs it leaves behind collide with the install's
|
||||||
|
# own file copies moments later.
|
||||||
|
#
|
||||||
|
# Sweep them once the daemon is up, so the next restart has nothing to resurrect.
|
||||||
|
# Scoped to containers whose project directory sits under the LibrePortal
|
||||||
|
# containers root — unrelated containers on the host are never touched.
|
||||||
|
dockerRemoveStrandedContainers()
|
||||||
|
{
|
||||||
|
local silent_flag="${1:-silent}"
|
||||||
|
|
||||||
|
[[ -d "$containers_dir" ]] || return 0
|
||||||
|
|
||||||
|
# `systemctl restart` returns once the unit is active, which can be before
|
||||||
|
# dockerd finishes initialising. Give the socket a bounded moment to answer.
|
||||||
|
local attempt=0
|
||||||
|
until runFileOp docker info >/dev/null 2>&1; do
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
if [[ "$attempt" -ge 15 ]]; then
|
||||||
|
[[ "$silent_flag" == "loud" ]] && isNotice "Docker not responding — skipping stranded container sweep."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
local listing
|
||||||
|
listing=$(runFileOp docker ps -a --format '{{.Names}} {{.Label "com.docker.compose.project.working_dir"}}' 2>/dev/null)
|
||||||
|
[[ -z "$listing" ]] && return 0
|
||||||
|
|
||||||
|
local removed=0 name work_dir
|
||||||
|
while IFS=$'\t' read -r name work_dir; do
|
||||||
|
[[ -z "$name" || -z "$work_dir" ]] && continue
|
||||||
|
# Only LibrePortal's own container tree, and only when the project
|
||||||
|
# directory is provably gone.
|
||||||
|
[[ "$work_dir" == "$containers_dir"* ]] || continue
|
||||||
|
[[ -d "$work_dir" ]] && continue
|
||||||
|
|
||||||
|
if runFileOp docker rm -f "$name" >/dev/null 2>&1; then
|
||||||
|
removed=$((removed + 1))
|
||||||
|
[[ "$silent_flag" == "loud" ]] && isNotice "Removed stranded container '$name' (project dir $work_dir is gone)."
|
||||||
|
fi
|
||||||
|
done <<< "$listing"
|
||||||
|
|
||||||
|
if [[ "$removed" -gt 0 ]]; then
|
||||||
|
isSuccessful "Removed $removed stranded container(s) left without a project directory"
|
||||||
|
fi
|
||||||
|
}
|
||||||
@ -183,6 +183,12 @@ EOL"
|
|||||||
local result; result=$(dockerCommandRunInstallUser "systemctl --user restart docker")
|
local result; result=$(dockerCommandRunInstallUser "systemctl --user restart docker")
|
||||||
checkSuccess "Reload the systemd user docker service"
|
checkSuccess "Reload the systemd user docker service"
|
||||||
|
|
||||||
|
# The restart above runs the daemon's container-restore pass, which
|
||||||
|
# resurrects containers left over from a previous install whose project
|
||||||
|
# directory this install already wiped. Clear them now so the next
|
||||||
|
# restart can't re-create their bind-mount sources as stub directories.
|
||||||
|
dockerRemoveStrandedContainers "loud"
|
||||||
|
|
||||||
local result; result=$(sudo cp $sysctl $sysctl.bak)
|
local result; result=$(sudo cp $sysctl $sysctl.bak)
|
||||||
checkSuccess "Backing up sysctl file"
|
checkSuccess "Backing up sysctl file"
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@ docker_scripts=(
|
|||||||
"docker/command/docker_run_install.sh"
|
"docker/command/docker_run_install.sh"
|
||||||
"docker/command/docker_run.sh"
|
"docker/command/docker_run.sh"
|
||||||
"docker/command/run_privileged.sh"
|
"docker/command/run_privileged.sh"
|
||||||
|
"docker/command/stranded_containers.sh"
|
||||||
"docker/compose/copy_build_context.sh"
|
"docker/compose/copy_build_context.sh"
|
||||||
"docker/compose/restart_after_update.sh"
|
"docker/compose/restart_after_update.sh"
|
||||||
"docker/compose/setup_compose_yml.sh"
|
"docker/compose/setup_compose_yml.sh"
|
||||||
|
|||||||
@ -411,6 +411,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[dockerPruneAppNetworks]="docker/network/network_prune.sh"
|
[dockerPruneAppNetworks]="docker/network/network_prune.sh"
|
||||||
[dockerRemoveApp]="docker/app/docker/remove_app.sh"
|
[dockerRemoveApp]="docker/app/docker/remove_app.sh"
|
||||||
[dockerRemoveAppImages]="docker/app/uninstall/remove_images.sh"
|
[dockerRemoveAppImages]="docker/app/uninstall/remove_images.sh"
|
||||||
|
[dockerRemoveStrandedContainers]="docker/command/stranded_containers.sh"
|
||||||
[dockerRestartApp]="docker/app/docker/restart_app.sh"
|
[dockerRestartApp]="docker/app/docker/restart_app.sh"
|
||||||
[dockerRestartAppViaInstall]="docker/app/functions/function_restart_app.sh"
|
[dockerRestartAppViaInstall]="docker/app/functions/function_restart_app.sh"
|
||||||
[dockerServiceStart]="docker/service/start_docker.sh"
|
[dockerServiceStart]="docker/service/start_docker.sh"
|
||||||
@ -1416,6 +1417,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[dockerPruneAppNetworks]="scripts"
|
[dockerPruneAppNetworks]="scripts"
|
||||||
[dockerRemoveApp]="scripts"
|
[dockerRemoveApp]="scripts"
|
||||||
[dockerRemoveAppImages]="scripts"
|
[dockerRemoveAppImages]="scripts"
|
||||||
|
[dockerRemoveStrandedContainers]="scripts"
|
||||||
[dockerRestartApp]="scripts"
|
[dockerRestartApp]="scripts"
|
||||||
[dockerRestartAppViaInstall]="scripts"
|
[dockerRestartAppViaInstall]="scripts"
|
||||||
[dockerServiceStart]="scripts"
|
[dockerServiceStart]="scripts"
|
||||||
@ -2454,6 +2456,7 @@ dockerInstallApp() { unset -f dockerInstallApp; __lpAutoload "${install_scripts_
|
|||||||
dockerPruneAppNetworks() { unset -f dockerPruneAppNetworks; __lpAutoload "${install_scripts_dir}docker/network/network_prune.sh"; dockerPruneAppNetworks "$@"; }
|
dockerPruneAppNetworks() { unset -f dockerPruneAppNetworks; __lpAutoload "${install_scripts_dir}docker/network/network_prune.sh"; dockerPruneAppNetworks "$@"; }
|
||||||
dockerRemoveApp() { unset -f dockerRemoveApp; __lpAutoload "${install_scripts_dir}docker/app/docker/remove_app.sh"; dockerRemoveApp "$@"; }
|
dockerRemoveApp() { unset -f dockerRemoveApp; __lpAutoload "${install_scripts_dir}docker/app/docker/remove_app.sh"; dockerRemoveApp "$@"; }
|
||||||
dockerRemoveAppImages() { unset -f dockerRemoveAppImages; __lpAutoload "${install_scripts_dir}docker/app/uninstall/remove_images.sh"; dockerRemoveAppImages "$@"; }
|
dockerRemoveAppImages() { unset -f dockerRemoveAppImages; __lpAutoload "${install_scripts_dir}docker/app/uninstall/remove_images.sh"; dockerRemoveAppImages "$@"; }
|
||||||
|
dockerRemoveStrandedContainers() { unset -f dockerRemoveStrandedContainers; __lpAutoload "${install_scripts_dir}docker/command/stranded_containers.sh"; dockerRemoveStrandedContainers "$@"; }
|
||||||
dockerRestartApp() { unset -f dockerRestartApp; __lpAutoload "${install_scripts_dir}docker/app/docker/restart_app.sh"; dockerRestartApp "$@"; }
|
dockerRestartApp() { unset -f dockerRestartApp; __lpAutoload "${install_scripts_dir}docker/app/docker/restart_app.sh"; dockerRestartApp "$@"; }
|
||||||
dockerRestartAppViaInstall() { unset -f dockerRestartAppViaInstall; __lpAutoload "${install_scripts_dir}docker/app/functions/function_restart_app.sh"; dockerRestartAppViaInstall "$@"; }
|
dockerRestartAppViaInstall() { unset -f dockerRestartAppViaInstall; __lpAutoload "${install_scripts_dir}docker/app/functions/function_restart_app.sh"; dockerRestartAppViaInstall "$@"; }
|
||||||
dockerServiceStart() { unset -f dockerServiceStart; __lpAutoload "${install_scripts_dir}docker/service/start_docker.sh"; dockerServiceStart "$@"; }
|
dockerServiceStart() { unset -f dockerServiceStart; __lpAutoload "${install_scripts_dir}docker/service/start_docker.sh"; dockerServiceStart "$@"; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user