|
|
@@ -3,10 +3,12 @@
|
|
|
# PhotoPlaces — Удалённый деплой на тестовый сервер
|
|
|
# ===========================================
|
|
|
# Запуск на сервере 192.168.88.128:
|
|
|
-# curl -fsSL https://raw.githubusercontent.com/foxtime/photoplaces/main/deploy/deploy-remote.sh | bash
|
|
|
+# curl -fsSL http://192.168.88.96:10880/foxtime/photoplaces/raw/main/deploy/deploy-remote.sh | bash
|
|
|
# Или склонировав репо и запустив:
|
|
|
# cd /home/foxtime/photoplaces && bash deploy/deploy-remote.sh
|
|
|
# ===========================================
|
|
|
+# ВНИМАНИЕ: Если репозиторий приватный, нужен токен доступа:
|
|
|
+# git clone http://TOKEN@192.168.88.96:10880/foxtime/photoplaces.git
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
@@ -65,7 +67,12 @@ setup_repo() {
|
|
|
git clean -fd
|
|
|
else
|
|
|
log_info "Клонирую репозиторий..."
|
|
|
- git clone --branch "$BRANCH" "$REPO_URL" "$PROJECT_DIR"
|
|
|
+ if ! git clone --branch "$BRANCH" "$REPO_URL" "$PROJECT_DIR" 2>&1; then
|
|
|
+ log_err "Не удалось клонировать репозиторий. Возможно, он приватный."
|
|
|
+ log_info "Создайте токен доступа в Gitea (Settings → Applications → Generate Token)"
|
|
|
+ log_info "И запустите: git clone http://TOKEN@192.168.88.96:10880/foxtime/photoplaces.git $PROJECT_DIR"
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
cd "$PROJECT_DIR"
|
|
|
fi
|
|
|
log_ok "Репозиторий готов: $(git rev-parse --short HEAD)"
|
|
|
@@ -109,7 +116,7 @@ setup_env() {
|
|
|
generate_secret "JWT_REFRESH_SECRET"
|
|
|
generate_secret "S3_SECRET_KEY"
|
|
|
|
|
|
- # Проверка обязательных переменных с интерактивным вводом
|
|
|
+ # Проверка обязательных переменных
|
|
|
local required=("DB_PASSWORD" "REDIS_PASSWORD" "JWT_SECRET" "JWT_REFRESH_SECRET" "S3_SECRET_KEY" "YANDEX_MAPS_API_KEY")
|
|
|
local missing=()
|
|
|
for var in "${required[@]}"; do
|
|
|
@@ -119,83 +126,17 @@ setup_env() {
|
|
|
done
|
|
|
|
|
|
if [ ${#missing[@]} -gt 0 ]; then
|
|
|
- log_warn "Необходимо заполнить обязательные переменные:"
|
|
|
+ log_warn "Требуют ручного заполнения в $ENV_FILE:"
|
|
|
for var in "${missing[@]}"; do
|
|
|
- prompt_for_var "$var"
|
|
|
+ echo " - $var"
|
|
|
done
|
|
|
- # Перезагружаем env после ввода
|
|
|
- set -a
|
|
|
- source "$ENV_FILE"
|
|
|
- set +a
|
|
|
+ log_info "Откройте $ENV_FILE и заполните недостающие значения, затем запустите скрипт снова"
|
|
|
+ exit 1
|
|
|
fi
|
|
|
|
|
|
- # Опциональные переменные (интерактивно, можно пропустить Enter)
|
|
|
- prompt_optional "CLOUDPAYMENTS_PUBLIC_ID" "CloudPayments Public ID (для платежей, Enter для пропуска)"
|
|
|
- prompt_optional "CLOUDPAYMENTS_API_SECRET" "CloudPayments API Secret (для платежей, Enter для пропуска)"
|
|
|
-
|
|
|
log_ok "Все секреты настроены"
|
|
|
}
|
|
|
|
|
|
-# Интерактивный запрос обязательной переменной
|
|
|
-prompt_for_var() {
|
|
|
- local var="$1"
|
|
|
- local current="${!var:-}"
|
|
|
- while [ -z "${!var:-}" ]; do
|
|
|
- if [ -n "$current" ]; then
|
|
|
- echo -ne "${YELLOW}$var${NC} (текущее: $current): "
|
|
|
- else
|
|
|
- echo -ne "${YELLOW}$var${NC}: "
|
|
|
- fi
|
|
|
- read -r input
|
|
|
- if [ -n "$input" ]; then
|
|
|
- # Экранируем спецсимволы для sed
|
|
|
- local escaped
|
|
|
- escaped=$(printf '%s\n' "$input" | sed 's/[&/\]/\\&/g')
|
|
|
- if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
|
- sed -i '' "s/^${var}=.*/${var}=${escaped}/" "$ENV_FILE"
|
|
|
- else
|
|
|
- sed -i "s/^${var}=.*/${var}=${escaped}/" "$ENV_FILE"
|
|
|
- fi
|
|
|
- export "$var=$input"
|
|
|
- log_ok "$var сохранено"
|
|
|
- elif [ -n "$current" ]; then
|
|
|
- export "$var=$current"
|
|
|
- log_ok "$var оставлено как есть"
|
|
|
- else
|
|
|
- log_err "Значение не может быть пустым!"
|
|
|
- fi
|
|
|
- done
|
|
|
-}
|
|
|
-
|
|
|
-# Интерактивный запрос опциональной переменной
|
|
|
-prompt_optional() {
|
|
|
- local var="$1"
|
|
|
- local prompt="$2"
|
|
|
- local current="${!var:-}"
|
|
|
- echo -ne "${BLUE}$prompt${NC} "
|
|
|
- if [ -n "$current" ]; then
|
|
|
- echo -ne "[$current]: "
|
|
|
- else
|
|
|
- echo -n ": "
|
|
|
- fi
|
|
|
- read -r input
|
|
|
- if [ -n "$input" ]; then
|
|
|
- local escaped
|
|
|
- escaped=$(printf '%s\n' "$input" | sed 's/[&/\]/\\&/g')
|
|
|
- if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
|
- sed -i '' "s/^${var}=.*/${var}=${escaped}/" "$ENV_FILE"
|
|
|
- else
|
|
|
- sed -i "s/^${var}=.*/${var}=${escaped}/" "$ENV_FILE"
|
|
|
- fi
|
|
|
- export "$var=$input"
|
|
|
- log_ok "$var сохранено"
|
|
|
- elif [ -n "$current" ]; then
|
|
|
- log_ok "$var оставлено как есть"
|
|
|
- else
|
|
|
- log_info "$var пропущено"
|
|
|
- fi
|
|
|
-}
|
|
|
-
|
|
|
# 4. Создание Docker secrets (если Swarm)
|
|
|
create_docker_secrets() {
|
|
|
if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
|
|
|
@@ -226,8 +167,8 @@ health_check() {
|
|
|
while [ $attempt -lt $max_attempts ]; do
|
|
|
attempt=$((attempt + 1))
|
|
|
|
|
|
- # Проверка Caddy (порт 2019 metrics)
|
|
|
- if docker compose -f deploy/docker-compose.prod.yml exec -T caddy wget -q --spider http://localhost:2019/metrics 2>/dev/null; then
|
|
|
+ # Проверка Caddy (порт 2019 metrics) — curl есть в alpine
|
|
|
+ if docker compose -f deploy/docker-compose.prod.yml exec -T caddy curl -sf http://localhost:2019/metrics >/dev/null 2>&1; then
|
|
|
# Проверка backend через Caddy (HTTP, SSL на Synology)
|
|
|
if curl -sf "http://localhost/api/v1/health" >/dev/null 2>&1; then
|
|
|
log_ok "Backend здоров"
|