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:
Executable
+94
@@ -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}"
|
||||
Reference in New Issue
Block a user