From d8f97ee2329cb75b013e60db898525926332afe6 Mon Sep 17 00:00:00 2001 From: lendry Date: Thu, 25 Jun 2026 09:19:47 +0300 Subject: [PATCH] add rebuild docker install sh --- install.sh | 170 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 153 insertions(+), 17 deletions(-) diff --git a/install.sh b/install.sh index 5f2b019..9836773 100644 --- a/install.sh +++ b/install.sh @@ -10,7 +10,7 @@ set -euo pipefail -SCRIPT_VERSION="2.2.3" +SCRIPT_VERSION="2.2.4" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$ROOT_DIR" @@ -31,6 +31,8 @@ INSTALL_LOCAL=0 INSTALL_INTRANET=0 OFFLINE="${OFFLINE:-0}" NGINX_MODE="${NGINX_MODE:-auto}" +SKIP_DOCKER_PRUNE="${SKIP_DOCKER_PRUNE:-0}" +DOCKER_PRUNE_AGGRESSIVE="${DOCKER_PRUNE_AGGRESSIVE:-0}" CLI_DOMAIN_API="" CLI_DOMAIN_FRONTEND="" @@ -64,6 +66,7 @@ ${BOLD}Lendry ID v${SCRIPT_VERSION}${NC} — установка и управл ./install.sh --configure-domains Изменить домены / Nginx / SSL ./install.sh --renew-ssl Обновить сертификаты Let's Encrypt ./install.sh --restart Перезапуск контейнеров + ./install.sh --docker-prune Только очистка Docker (без пересборки) ./install.sh --fix-proxy Исправить 502: host Nginx + порты 3000/3002/3003 ./install.sh --status Статус сервисов ./install.sh --reset-db Сброс PostgreSQL (новый пароль из .env, данные удалятся) @@ -93,6 +96,9 @@ ${BOLD}Прочие опции:${NC} ${BOLD}Переменные окружения:${NC} FORCE_ENV=1 Новые JWT-секреты (пароли БД/MinIO/RabbitMQ сохраняются если volume уже есть) OFFLINE=1 То же, что --offline + SKIP_DOCKER_PRUNE=1 Не очищать образы/кеш перед пересборкой + DOCKER_PRUNE_AGGRESSIVE=1 Глубже чистить неиспользуемые образы проекта + COMPOSE_PARALLEL_LIMIT=4 Параллельная сборка сервисов (по умолчанию 4) ${BOLD}Примеры:${NC} ./install.sh --intranet --install --yes \\ @@ -122,6 +128,9 @@ parse_args() { --configure-domains) ACTION="configure-domains"; shift ;; --renew-ssl) ACTION="renew-ssl"; shift ;; --restart) ACTION="restart"; shift ;; + --docker-prune) ACTION="docker-prune"; shift ;; + --skip-docker-prune) SKIP_DOCKER_PRUNE=1; shift ;; + --docker-prune-aggressive) DOCKER_PRUNE_AGGRESSIVE=1; shift ;; --fix-proxy) ACTION="fix-proxy"; shift ;; --status) ACTION="status"; shift ;; --reset-db) ACTION="reset-db"; shift ;; @@ -407,6 +416,134 @@ docker_cmd() { fi } +configure_docker_build_env() { + export DOCKER_BUILDKIT=1 + export COMPOSE_DOCKER_CLI_BUILD=1 + export BUILDKIT_PROGRESS="${BUILDKIT_PROGRESS:-auto}" + export COMPOSE_PARALLEL_LIMIT="${COMPOSE_PARALLEL_LIMIT:-4}" +} + +docker_disk_usage_brief() { + docker_cmd system df 2>/dev/null | sed 's/^/ /' || true +} + +docker_remove_stopped_project_containers() { + local project cid + project="$(compose_project_name)" + while IFS= read -r cid; do + [[ -z "$cid" ]] && continue + docker_cmd rm -f "$cid" 2>/dev/null || true + done < <(docker_cmd ps -aq --filter "label=com.docker.compose.project=${project}" --filter "status=exited" 2>/dev/null || true) +} + +docker_prune_stale_project_images() { + local project="$1" + local aggressive="${2:-0}" + local id repo + + while IFS= read -r id; do + [[ -z "$id" ]] && continue + if docker_cmd ps -a --filter "ancestor=${id}" -q 2>/dev/null | grep -q .; then + continue + fi + docker_cmd rmi -f "$id" 2>/dev/null || true + done < <(docker_cmd images --filter "label=com.docker.compose.project=${project}" -q 2>/dev/null | sort -u || true) + + if [[ "$aggressive" == "1" ]]; then + while IFS= read -r repo id; do + [[ -z "$id" || "$repo" == "" ]] && continue + case "$repo" in + lendry-id-* | idservice-* | "${project}"-*) + if ! docker_cmd ps -a --filter "ancestor=${id}" -q 2>/dev/null | grep -q .; then + docker_cmd rmi -f "$id" 2>/dev/null || true + fi + ;; + esac + done < <(docker_cmd images --format '{{.Repository}} {{.ID}}' 2>/dev/null || true) + fi +} + +docker_prune_before_rebuild() { + local aggressive="${1:-0}" + + log "Очистка Docker перед пересборкой (volumes данных не удаляются)..." + build_compose_stack_cmd + + if [[ "$aggressive" == "1" ]]; then + log " Режим aggressive: остановка стека и удаление orphan-контейнеров..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" down --remove-orphans 2>/dev/null || true + else + log " Удаление остановленных контейнеров проекта..." + docker_remove_stopped_project_containers + docker_cmd container prune -f --filter "until=24h" 2>/dev/null || true + fi + + log " Удаление dangling-образов и старого build cache..." + docker_cmd image prune -f 2>/dev/null || true + if docker_cmd builder prune --help 2>/dev/null | grep -q 'until='; then + docker_cmd builder prune -f --filter "until=168h" 2>/dev/null || \ + docker_cmd builder prune -f 2>/dev/null || true + else + docker_cmd builder prune -f 2>/dev/null || true + fi + + log " Удаление неиспользуемых образов проекта..." + docker_prune_stale_project_images "$(compose_project_name)" "$aggressive" + + ok "Docker очищен перед сборкой" + docker_disk_usage_brief +} + +docker_prune_after_rebuild() { + docker_cmd image prune -f 2>/dev/null || true +} + +compose_build_parallel_flags() { + COMPOSE_BUILD_PARALLEL=() + if docker_cmd compose build --help 2>/dev/null | grep -q -- '--parallel'; then + COMPOSE_BUILD_PARALLEL=(--parallel) + fi +} + +compose_build_and_up() { + local -a services=() + if [[ $# -gt 0 ]]; then + services=("$@") + fi + + configure_docker_build_env + build_compose_stack_cmd + compose_build_parallel_flags + + if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then + docker_prune_before_rebuild "${DOCKER_PRUNE_AGGRESSIVE:-0}" + fi + + if [[ ${#services[@]} -gt 0 ]]; then + log "Сборка сервисов: ${services[*]} (BuildKit, limit=${COMPOSE_PARALLEL_LIMIT})..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" build "${COMPOSE_BUILD_PARALLEL[@]}" "${services[@]}" + log "Запуск сервисов..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --remove-orphans "${services[@]}" + else + log "Сборка образов (BuildKit, параллельно, limit=${COMPOSE_PARALLEL_LIMIT})..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" build "${COMPOSE_BUILD_PARALLEL[@]}" + log "Запуск контейнеров..." + docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --remove-orphans + fi + + if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then + docker_prune_after_rebuild + fi +} + +action_docker_prune() { + load_env + prepare_compose_stack + SKIP_DOCKER_PRUNE=0 + docker_prune_before_rebuild "${DOCKER_PRUNE_AGGRESSIVE:-1}" + ok "Очистка Docker завершена" +} + install_nginx_host() { if has_cmd nginx; then ok "Nginx уже установлен" @@ -1819,16 +1956,11 @@ wait_for_service() { } deploy_stack() { - export DOCKER_BUILDKIT=1 - export COMPOSE_DOCKER_CLI_BUILD=1 - prepare_compose_stack verify_postgres_auth - build_compose_stack_cmd - log "Сборка и запуск контейнеров (10–20 минут при первом запуске)..." - docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --build + compose_build_and_up recreate_host_port_services ensure_host_upstreams @@ -1895,6 +2027,7 @@ print_summary() { echo -e " ${BOLD}Управление:${NC} ./install.sh" echo -e " ${BOLD}Смена доменов:${NC} ./install.sh --configure-domains" echo -e " ${BOLD}Логи:${NC} docker compose logs -f api-gateway nginx" + echo -e " ${BOLD}Очистка Docker:${NC} ./install.sh --docker-prune" echo "" echo " Первый зарегистрированный пользователь станет супер-администратором." echo " Секреты в .env — не коммитьте в git." @@ -1964,6 +2097,9 @@ show_status() { echo "" docker_cmd compose ps 2>/dev/null || warn "Контейнеры не запущены" echo "" + echo -e " ${BOLD}Docker disk:${NC}" + docker_disk_usage_brief + echo "" if docker_cmd ps -q -f name=lendry-id-nginx 2>/dev/null | grep -q .; then if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then warn "КОНФЛИКТ: контейнер lendry-id-nginx запущен при NGINX_MODE=host — выполните: ./install.sh --fix-proxy" @@ -2027,8 +2163,7 @@ apply_intranet_selfsigned_runtime() { env_set INTERNAL_WS_URL "http://media-ws:8085" log "Пересборка frontend (same-origin /idp-api)..." - build_compose_stack_cmd - docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --build frontend + compose_build_and_up frontend } action_renew_ssl() { @@ -2071,8 +2206,7 @@ action_fix_host_proxy() { write_compose_override log "Шаг 3/4: пересоздание api-gateway, frontend, docs, media-ws..." - build_compose_stack_cmd - docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --force-recreate "${HOST_EDGE_SERVICES[@]}" + compose_build_and_up "${HOST_EDGE_SERVICES[@]}" ensure_host_upstreams log "Шаг 4/4: конфиги системного Nginx..." @@ -2081,8 +2215,7 @@ action_fix_host_proxy() { apply_intranet_selfsigned_runtime log "Шаг 5/5: пересоздание ldap-auth и sso-core..." - build_compose_stack_cmd - docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --build --force-recreate ldap-auth sso-core + compose_build_and_up ldap-auth sso-core ok "Прокси исправлен — проверьте: curl -I http://127.0.0.1:3002" show_status @@ -2092,8 +2225,8 @@ action_restart() { load_env prepare_compose_stack refresh_host_nginx_configs - build_compose_stack_cmd - docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --build + log "Пересборка и перезапуск контейнеров..." + compose_build_and_up recreate_host_port_services ensure_host_upstreams ok "Контейнеры перезапущены" @@ -2111,15 +2244,16 @@ show_menu() { echo " 1) Полная установка / переустановка стека" echo " 2) Настроить / изменить домены и Nginx + SSL" echo " 3) Обновить SSL-сертификаты (selfsigned / Let's Encrypt)" - echo " 4) Перезапуск / пересборка контейнеров" + echo " 4) Перезапуск / пересборка контейнеров (+ очистка Docker)" echo " 5) Статус сервисов" echo " 6) Удалить конфиги Nginx IdP" echo " 7) Сброс PostgreSQL (если ошибка P1000 / пароль БД)" + echo " 8) Очистить Docker (образы/кеш, без пересборки)" echo " 0) Выход" echo "" local choice - read -r -p "Выберите пункт [0-7]: " choice + read -r -p "Выберите пункт [0-8]: " choice case "$choice" in 1) NON_INTERACTIVE=0; action_full_install ;; @@ -2129,6 +2263,7 @@ show_menu() { 5) show_status ;; 6) remove_nginx_configs; ok "Готово" ;; 7) action_reset_db; action_restart ;; + 8) action_docker_prune ;; 0) exit 0 ;; *) warn "Неверный пункт" ;; esac @@ -2148,6 +2283,7 @@ main() { configure-domains) action_configure_domains ;; renew-ssl) action_renew_ssl ;; restart) action_restart ;; + docker-prune) action_docker_prune ;; fix-proxy) action_fix_host_proxy ;; status) show_status ;; reset-db) action_reset_db ;;