diff --git a/README.md b/README.md index 11f2868f..1bb81d31 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ For a single-host prototype, use Docker Compose with the repo root [`docker-comp cp .env.example .env ./scripts/prototype-up.sh pnpm prototype:self-test +pnpm docker:clean ``` See [docs/PROTOTYPE_DEPLOYMENT.md](docs/PROTOTYPE_DEPLOYMENT.md) for the required environment variables and day-to-day commands. diff --git a/docs/PROTOTYPE_DEPLOYMENT.md b/docs/PROTOTYPE_DEPLOYMENT.md index d01ca606..e7564943 100644 --- a/docs/PROTOTYPE_DEPLOYMENT.md +++ b/docs/PROTOTYPE_DEPLOYMENT.md @@ -65,10 +65,13 @@ docker compose logs -f mailpit pnpm prototype:self-test ./scripts/prototype-self-test.sh docker compose down +pnpm docker:clean ``` `pnpm prototype:self-test` is the stable host-side smoke-test entrypoint. It runs the same end-to-end check as the underlying shell script, but gives ops a single repo-level command to remember. +`pnpm docker:clean` opens an interactive Docker cleanup menu. Use it for escalating cleanup levels from status-only and compose shutdown through repo volume cleanup, image pruning, and full Docker volume pruning. + The Cosmos Data Explorer is exposed on `http://localhost:1234`. Azurite Blob Storage is exposed on `http://localhost:10000`. Mailpit SMTP listens on `localhost:1025` and the Mailpit inbox UI is exposed on `http://localhost:8025`. diff --git a/package.json b/package.json index cc863741..a966a610 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md,yml,yaml}\"", "audit": "pnpm -r audit --audit-level moderate", "clean": "pnpm -r exec rm -rf dist", + "docker:clean": "./scripts/docker-clean.sh", "dns:godaddy:bytelyst": "./scripts/godaddy-sync-bytelyst-dns.sh", "prototype:self-test": "./scripts/prototype-self-test.sh", "release": "./scripts/gitea/release-packages.sh", diff --git a/scripts/docker-clean.sh b/scripts/docker-clean.sh new file mode 100755 index 00000000..af3095fa --- /dev/null +++ b/scripts/docker-clean.sh @@ -0,0 +1,300 @@ +#!/usr/bin/env bash +# docker-clean.sh - Interactive Docker cleanup for the ByteLyst platform prototype. +set -euo pipefail + +RED=$'\033[0;31m' +GREEN=$'\033[0;32m' +YELLOW=$'\033[1;33m' +CYAN=$'\033[0;36m' +BOLD=$'\033[1m' +DIM=$'\033[2m' +NC=$'\033[0m' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +log() { echo -e "${CYAN}[docker-clean]${NC} $*"; } +ok() { echo -e "${GREEN}OK:${NC} $*"; } +warn() { echo -e "${YELLOW}WARN:${NC} $*"; } +err() { echo -e "${RED}ERROR:${NC} $*" >&2; } + +require_docker() { + if ! command -v docker >/dev/null 2>&1; then + err "Docker CLI is not installed or not on PATH." + exit 1 + fi + + if ! docker info >/dev/null 2>&1; then + err "Docker daemon is not reachable. Start Docker Desktop or your Docker daemon and try again." + exit 1 + fi + + if ! docker compose version >/dev/null 2>&1; then + err "Docker Compose plugin is not available. Install/update Docker Desktop or the docker compose plugin." + exit 1 + fi +} + +run_cmd() { + echo -e "${DIM}$*${NC}" + "$@" +} + +confirm() { + local prompt="$1" + read -r -p "$(echo -e "${BOLD}${prompt}${NC} [y/N] ")" answer + case "${answer:-}" in + y|Y|yes|YES) return 0 ;; + * ) return 1 ;; + esac +} + +compose_status() { + log "Compose services in $REPO_ROOT" + cd "$REPO_ROOT" + run_cmd docker compose ps + echo "" + log "Docker disk usage" + run_cmd docker system df +} + +stop_compose() { + log "Stopping compose services" + cd "$REPO_ROOT" + run_cmd docker compose stop +} + +down_compose() { + log "Removing compose containers and networks" + cd "$REPO_ROOT" + run_cmd docker compose down --remove-orphans +} + +down_compose_with_volumes() { + cd "$REPO_ROOT" + run_cmd docker compose down --remove-orphans --volumes +} + +safe_prune() { + log "Pruning stopped containers, unused networks, dangling images, and build cache" + run_cmd docker container prune --force + run_cmd docker network prune --force + run_cmd docker image prune --force + run_cmd docker builder prune --force +} + +unused_image_prune() { + run_cmd docker image prune --all --force + run_cmd docker builder prune --all --force +} + +full_prune() { + run_cmd docker system prune --all --volumes --force +} + +builder_prune() { + log "Pruning Docker builder cache" + run_cmd docker builder prune --all --force +} + +show_menu() { + cat <