feat(deploy): установщик, docker-скелет, шаблоны Caddy/LiveKit и CLI

- deploy/install.sh: идемпотентная установка, режимы встроенного и внешнего
  прокси (§10.13), --dry-run/--skip-tls/--reconfigure, auto-детект профиля (§10.10)
- deploy/compose.yaml.tpl: app, livekit, caddy с лимитами, healthcheck,
  ротацией логов, cap_drop и no-new-privileges (§4.3)
- deploy/caddy: Caddyfile.tpl (встроенный) и external-proxy.conf.tpl (наш стенд)
- deploy/livekit: конфиг с TURN, dynacast и лимитами комнат (§10.6)
- deploy/backup.sh + restore.sh: sqlite .backup, tar, age-шифрование (§10.8)
- deploy/update.sh: бэкап → pull/сборка → up → миграции → smoke (§9.3)
- deploy/smoke.sh: проверки §10.9 (healthz/readyz/meta, порты, UFW, fail2ban, бэкап)
- deploy/security-check.sh: аудит SSH, UFW, fail2ban, прав .env и ключей
- deploy/ufw-docker.sh, nftables и fail2ban-конфиги (sshd, glchat-auth, recidive)
- deploy/glchat-cli.sh: команды §10.7, systemd-юнит glchat.service
- scripts/test-install.sh: прогон установщика в чистом Ubuntu 24.04 (systemd-контейнер)
- Dockerfile: multi-stage (node → golang CGO → debian-slim), non-root, healthcheck
- Makefile: lint/test/build/dev/generate/security/smoke и фиксация версий инструментов
This commit is contained in:
2026-09-19 18:21:02 +03:00
parent 642d0f720e
commit 4bd1770cb5
22 changed files with 2808 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
# glchat: обновление стека (AGENT.md 9.3, 10.11).
set -euo pipefail
GLCHAT_ETC_DIR="${GLCHAT_ETC_DIR:-/opt/glchat}"
ENV_FILE="${GLCHAT_ETC_DIR}/.env"
COMPOSE_FILE="${GLCHAT_ETC_DIR}/compose.yaml"
REPO_DIR_DEFAULT="${GLCHAT_REPO_DIR:-/opt/glchat-src}"
log() { printf '[update] %s\n' "$*"; }
die() {
printf '[update] ошибка: %s\n' "$*" >&2
exit 1
}
TARGET_VERSION=""
CHANNEL=""
while [ "$#" -gt 0 ]; do
case "$1" in
--version) TARGET_VERSION="${2:?}"; shift 2 ;;
--channel) CHANNEL="${2:?}"; shift 2 ;;
*) die "неизвестный аргумент: $1" ;;
esac
done
[ -f "$ENV_FILE" ] || die "не найден ${ENV_FILE}"
[ -f "$COMPOSE_FILE" ] || die "не найден ${COMPOSE_FILE}"
# shellcheck disable=SC1090
set -a && . "$ENV_FILE" && set +a
CURRENT="${APP_VERSION:-unknown}"
TARGET="${TARGET_VERSION:-$CURRENT}"
[ -n "$CHANNEL" ] && TARGET_CHANNEL="$CHANNEL" || TARGET_CHANNEL="${CHANNEL_NAME:-stable}"
log "текущая версия: ${CURRENT} → целевая: ${TARGET} (канал ${TARGET_CHANNEL})"
if [ "$CURRENT" = "$TARGET" ] && [ -z "${GLCHAT_FORCE_UPDATE:-}" ]; then
log "версия не изменилась; для принудительного обновления задайте GLCHAT_FORCE_UPDATE=1"
fi
log "бэкап перед обновлением (обязательно)"
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/backup.sh" || die "бэкап не удался; обновление остановлено"
compose_args=(-f "$COMPOSE_FILE")
[ "${PROXY_MODE:-embedded}" = "embedded" ] && compose_args+=(--profile embedded-proxy)
if [ "$APP_IMAGE" = "glchat:local" ] || [ -z "${APP_IMAGE:-}" ]; then
REPO_DIR="${GLCHAT_REPO_DIR:-$REPO_DIR_DEFAULT}"
if [ -d "${REPO_DIR}/.git" ]; then
log "обновляем исходники в ${REPO_DIR}"
git -C "$REPO_DIR" fetch --tags --depth 1 origin
if [ -n "$TARGET_VERSION" ]; then
git -C "$REPO_DIR" checkout "$TARGET_VERSION"
else
git -C "$REPO_DIR" pull --ff-only
fi
log "пересобираем образ"
docker build -t "${APP_IMAGE:-glchat:local}" \
--build-arg "VERSION=${TARGET}" \
--build-arg "COMMIT=$(git -C "$REPO_DIR" rev-parse --short HEAD)" \
--build-arg "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
"$REPO_DIR" || die "сборка не удалась"
else
die "каталог исходников ${REPO_DIR} не найден; выполните git clone или задайте GLCHAT_REPO_DIR"
fi
else
log "скачиваем образ ${APP_IMAGE}"
docker pull "$APP_IMAGE" || die "не удалось скачать образ"
fi
log "применяем новую версию"
(cd "$GLCHAT_ETC_DIR" && docker compose "${compose_args[@]}" up -d --remove-orphans) || die "не удалось поднять стек"
log "ожидаем готовности (миграции выполняются на старте приложения)"
for _ in $(seq 1 45); do
if curl -fsS "http://127.0.0.1:${APP_PORT:-8080}/readyz" >/dev/null 2>&1; then
log "приложение готово"
break
fi
sleep 2
done
if ! curl -fsS "http://127.0.0.1:${APP_PORT:-8080}/readyz" >/dev/null 2>&1; then
die "приложение не поднялось; откат: glchat restore <бэкап>, затем docker compose up -d"
fi
if command -v sed >/dev/null 2>&1; then
sed -i "s/^APP_VERSION=.*/APP_VERSION=${TARGET}/" "$ENV_FILE"
sed -i "s/^CHANNEL_NAME=.*/CHANNEL_NAME=${TARGET_CHANNEL}/" "$ENV_FILE" 2>/dev/null || printf 'CHANNEL_NAME=%s\n' "$TARGET_CHANNEL" >>"$ENV_FILE"
fi
GLCHAT_ETC_DIR="$GLCHAT_ETC_DIR" bash "${GLCHAT_ETC_DIR}/smoke.sh" || log "smoke-тест с замечаниями"
log "обновление завершено: ${TARGET}"