diff --git a/archive.sh b/archive.sh new file mode 100644 index 0000000..2950992 --- /dev/null +++ b/archive.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# ~/docker/ai-image-gen/archive.sh +# +# Run this once after `docker compose up -d` succeeds and you're happy +# with the setup. It: +# +# 1. Records the exact image digest (SHA256) for each container +# 2. Exports each image as a self-contained .tar file +# 3. Writes a restore.sh you can run on any machine to reload everything +# +# The .tar files are large (~8-15 GB total). Store them somewhere safe +# (external drive, NAS, etc). They never expire and need no internet to load. +# +# Usage: +# chmod +x archive.sh (once) +# ./archive.sh + +set -euo pipefail +cd "$(dirname "$0")" + +ARCHIVE_DIR="./archive" +mkdir -p "$ARCHIVE_DIR" + +SERVICES=("forge" "invokeai") + +echo "==> Recording image digests and exporting images..." +echo "" + +# Start restore script +RESTORE="$ARCHIVE_DIR/restore.sh" +cat > "$RESTORE" <<'HEADER' +#!/usr/bin/env bash +# Restore saved images to Docker on any machine. +# Run from the directory containing this script. +# Requires Docker to be installed (and NVIDIA Container Toolkit for GPU use). +# +# Usage: +# chmod +x restore.sh +# ./restore.sh +set -euo pipefail +cd "$(dirname "$0")" +HEADER + +for SERVICE in "${SERVICES[@]}"; do + # Get the image name from the running container + IMAGE=$(docker inspect --format='{{.Config.Image}}' "$(docker compose ps -q "$SERVICE")") + + # Get the resolved digest (immutable SHA256 — survives tag changes or deletions) + DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || \ + docker inspect --format='{{.Id}}' "$IMAGE") + + TARFILE="$ARCHIVE_DIR/${SERVICE}.tar" + + echo " Service: $SERVICE" + echo " Image: $IMAGE" + echo " Digest: $DIGEST" + echo " Saving → $TARFILE" + docker save "$IMAGE" -o "$TARFILE" + echo " Done." + echo "" + + # Append load step to restore script + cat >> "$RESTORE" < Loading $SERVICE image from ${SERVICE}.tar ..." +docker load -i "${SERVICE}.tar" +echo " Loaded: $IMAGE" +echo " Digest: $DIGEST" +ENTRY +done + +# Finish restore script +cat >> "$RESTORE" <<'FOOTER' + +echo "" +echo "==> All images loaded. Copy your docker-compose.yml and data/ directory" +echo " to this machine, then run: docker compose up -d" +FOOTER + +chmod +x "$RESTORE" + +# Write a digest record as a plain text reference +DIGEST_FILE="$ARCHIVE_DIR/digests.txt" +echo "# Image digests captured on $(date)" > "$DIGEST_FILE" +for SERVICE in "${SERVICES[@]}"; do + IMAGE=$(docker inspect --format='{{.Config.Image}}' "$(docker compose ps -q "$SERVICE")") + DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || \ + docker inspect --format='{{.Id}}' "$IMAGE") + echo "$SERVICE: $DIGEST" >> "$DIGEST_FILE" +done + +echo "==> Archive complete. Files written to $ARCHIVE_DIR/:" +ls -lh "$ARCHIVE_DIR/" +echo "" +echo " To restore on another machine:" +echo " 1. Copy the archive/ folder and docker-compose.yml to the new machine" +echo " 2. Copy data/ to the new machine (your models and outputs)" +echo " 3. Run: ./archive/restore.sh" +echo " 4. Run: docker compose up -d"