#!/usr/bin/env bash # ============================================================================= # Changemaker Lite V2 — Mirror Third-Party Images to Gitea Registry # Pulls infrastructure images from Docker Hub and re-pushes to the Gitea # container registry, protecting against Docker Hub rate limits. # # Usage: # ./scripts/mirror-images.sh [OPTIONS] # # Options: # --all Also mirror heavy optional images (Rocket.Chat, MongoDB, n8n, # Gitea, Jitsi x4) in addition to core images # --dry-run Print commands without executing # --registry Override registry (default: gitea.bnkops.com/admin) # --help Show this help # # Prerequisites: # docker login gitea.bnkops.com # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # --- Defaults --- REGISTRY="${GITEA_REGISTRY:-gitea.bnkops.com/admin}" INCLUDE_ALL=false DRY_RUN=false # --- Colors --- if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' else RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC='' fi info() { echo -e "${BLUE}[INFO]${NC} $*"; } success() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } run() { if [[ "$DRY_RUN" == "true" ]]; then echo -e "${CYAN}[DRY-RUN]${NC} $*"; else eval "$@"; fi; } # --- Arg parser --- while [[ $# -gt 0 ]]; do case "$1" in --all) INCLUDE_ALL=true; shift ;; --dry-run) DRY_RUN=true; shift ;; --registry) REGISTRY="$2"; shift 2 ;; --help|-h) sed -n '2,30p' "$0" | grep '^#' | sed 's/^# \?//' exit 0 ;; *) error "Unknown option: $1"; exit 1 ;; esac done # --- Core images (always mirrored) --- CORE_IMAGES=( "postgres:16-alpine" "postgres:17-alpine" "redis:7-alpine" "nocodb/nocodb:0.301.3" "listmonk/listmonk:v6.0.0" "mailhog/mailhog:v1.0.1" "prom/prometheus:v3.10.0" "grafana/grafana:12.3.0" "prom/alertmanager:v0.31.1" "oliver006/redis_exporter:v1.81.0" "gcr.io/cadvisor/cadvisor:v0.52.1" "prom/node-exporter:v1.9.1" "alpine:3" ) # --- Heavy optional images (--all flag) --- OPTIONAL_IMAGES=( "gitea/gitea:1.23" "n8nio/n8n:1.83.2" "rocket.chat:7.4.0" "mongo:6.0" "jitsi/web:stable-10168" "jitsi/prosody:stable-10168" "jitsi/jicofo:stable-10168" "jitsi/jvb:stable-10168" "gotify/server:2.6.1" ) mirror_image() { local source="$1" # Get short name: last path segment + tag local name_tag="${source##*/}" local dest="${REGISTRY}/${name_tag}" info "Mirroring ${source} → ${dest}..." run docker pull "${source}" run docker tag "${source}" "${dest}" run docker push "${dest}" success "Mirrored ${name_tag}" } echo -e "${BOLD}Changemaker Lite — Mirror Images${NC}" echo " Registry: $REGISTRY" echo " All: $INCLUDE_ALL" echo "" IMAGES=("${CORE_IMAGES[@]}") if [[ "$INCLUDE_ALL" == "true" ]]; then IMAGES+=("${OPTIONAL_IMAGES[@]}") warn "Including heavy optional images — this will take a while" fi FAILED=() for img in "${IMAGES[@]}"; do if ! mirror_image "$img"; then FAILED+=("$img") warn "Failed to mirror: $img (continuing...)" fi done echo "" if [[ ${#FAILED[@]} -eq 0 ]]; then success "All ${#IMAGES[@]} images mirrored to ${REGISTRY}" else warn "Mirrored $((${#IMAGES[@]} - ${#FAILED[@]}))/${#IMAGES[@]} images" error "Failed: ${FAILED[*]}" exit 1 fi