deploy-remote.sh 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env bash
  2. # ===========================================
  3. # PhotoPlaces — Удалённый деплой на тестовый сервер
  4. # ===========================================
  5. # Запуск на сервере 192.168.88.128:
  6. # curl -fsSL https://raw.githubusercontent.com/foxtime/photoplaces/main/deploy/deploy-remote.sh | bash
  7. # Или склонировав репо и запустив:
  8. # cd /home/foxtime/photoplaces && bash deploy/deploy-remote.sh
  9. # ===========================================
  10. set -euo pipefail
  11. # Цвета для вывода
  12. RED='\033[0;31m'
  13. GREEN='\033[0;32m'
  14. YELLOW='\033[1;33m'
  15. BLUE='\033[0;34m'
  16. NC='\033[0m' # No Color
  17. log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
  18. log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
  19. log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
  20. log_err() { echo -e "${RED}[ERR]${NC} $*"; }
  21. # Конфигурация
  22. REPO_URL="http://192.168.88.96:10880/foxtime/photoplaces.git"
  23. PROJECT_DIR="/home/foxtime/photoplaces"
  24. BRANCH="main"
  25. ENV_FILE="$PROJECT_DIR/deploy/env.prod"
  26. log_info "=== PhotoPlaces Remote Deploy ==="
  27. log_info "Сервер: $(hostname) ($(hostname -I | awk '{print $1}'))"
  28. log_info "Пользователь: $(whoami)"
  29. log_info "Директория: $PROJECT_DIR"
  30. # 1. Проверка зависимостей
  31. check_deps() {
  32. log_info "Проверка зависимостей..."
  33. local missing=()
  34. for cmd in docker git curl openssl; do
  35. if ! command -v "$cmd" >/dev/null 2>&1; then
  36. missing+=("$cmd")
  37. fi
  38. done
  39. if ! docker compose version >/dev/null 2>&1; then
  40. missing+=("docker compose")
  41. fi
  42. if [ ${#missing[@]} -gt 0 ]; then
  43. log_err "Отсутствуют: ${missing[*]}"
  44. log_info "Установите: sudo apt update && sudo apt install -y docker.io docker-compose-plugin git curl openssl"
  45. exit 1
  46. fi
  47. log_ok "Все зависимости установлены"
  48. }
  49. # 2. Клонирование/обновление репозитория
  50. setup_repo() {
  51. log_info "Настройка репозитория..."
  52. if [ -d "$PROJECT_DIR/.git" ]; then
  53. log_info "Репозиторий существует, обновляю..."
  54. cd "$PROJECT_DIR"
  55. git fetch origin
  56. git reset --hard "origin/$BRANCH"
  57. git clean -fd
  58. else
  59. log_info "Клонирую репозиторий..."
  60. git clone --branch "$BRANCH" "$REPO_URL" "$PROJECT_DIR"
  61. cd "$PROJECT_DIR"
  62. fi
  63. log_ok "Репозиторий готов: $(git rev-parse --short HEAD)"
  64. }
  65. # 3. Настройка env.prod
  66. setup_env() {
  67. log_info "Настройка переменных окружения..."
  68. cd "$PROJECT_DIR"
  69. if [ ! -f "$ENV_FILE" ]; then
  70. cp deploy/env.prod.example "$ENV_FILE"
  71. log_info "Создан $ENV_FILE из шаблона"
  72. fi
  73. # Автогенерация секретов если пустые или CHANGE_ME
  74. generate_secret() {
  75. local var="$1"
  76. local current="${!var:-}"
  77. if [[ -z "$current" || "$current" == *"CHANGE_ME"* ]]; then
  78. local secret
  79. secret=$(openssl rand -hex 32)
  80. if [[ "$OSTYPE" == "darwin"* ]]; then
  81. sed -i '' "s/^${var}=.*/${var}=${secret}/" "$ENV_FILE"
  82. else
  83. sed -i "s/^${var}=.*/${var}=${secret}/" "$ENV_FILE"
  84. fi
  85. export "$var=$secret"
  86. log_ok "$var сгенерирован автоматически"
  87. fi
  88. }
  89. # Загружаем текущие значения
  90. set -a
  91. source "$ENV_FILE"
  92. set +a
  93. generate_secret "DB_PASSWORD"
  94. generate_secret "REDIS_PASSWORD"
  95. generate_secret "JWT_SECRET"
  96. generate_secret "JWT_REFRESH_SECRET"
  97. generate_secret "S3_SECRET_KEY"
  98. # Проверка обязательных переменных
  99. local required=("DB_PASSWORD" "REDIS_PASSWORD" "JWT_SECRET" "JWT_REFRESH_SECRET" "S3_SECRET_KEY" "YANDEX_MAPS_API_KEY")
  100. local missing=()
  101. for var in "${required[@]}"; do
  102. if [ -z "${!var:-}" ]; then
  103. missing+=("$var")
  104. fi
  105. done
  106. if [ ${#missing[@]} -gt 0 ]; then
  107. log_warn "Требуют ручного заполнения в $ENV_FILE:"
  108. for var in "${missing[@]}"; do
  109. echo " - $var"
  110. done
  111. log_info "Откройте $ENV_FILE и заполните недостающие значения, затем запустите скрипт снова"
  112. exit 1
  113. fi
  114. log_ok "Все секреты настроены"
  115. }
  116. # 4. Создание Docker secrets (если Swarm)
  117. create_docker_secrets() {
  118. if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
  119. log_info "Swarm mode: создание Docker secrets..."
  120. printf "%s" "$DB_PASSWORD" | docker secret create db_password - 2>/dev/null || docker secret rm db_password && printf "%s" "$DB_PASSWORD" | docker secret create db_password -
  121. printf "%s" "$REDIS_PASSWORD" | docker secret create redis_password - 2>/dev/null || docker secret rm redis_password && printf "%s" "$REDIS_PASSWORD" | docker secret create redis_password -
  122. printf "%s" "$JWT_SECRET" | docker secret create jwt_secret - 2>/dev/null || docker secret rm jwt_secret && printf "%s" "$JWT_SECRET" | docker secret create jwt_secret -
  123. printf "%s" "$JWT_REFRESH_SECRET" | docker secret create jwt_refresh_secret - 2>/dev/null || docker secret rm jwt_refresh_secret && printf "%s" "$JWT_REFRESH_SECRET" | docker secret create jwt_refresh_secret -
  124. printf "%s" "$S3_SECRET_KEY" | docker secret create s3_secret_key - 2>/dev/null || docker secret rm s3_secret_key && printf "%s" "$S3_SECRET_KEY" | docker secret create s3_secret_key -
  125. log_ok "Docker secrets созданы"
  126. fi
  127. }
  128. # 5. Деплой через docker compose
  129. deploy() {
  130. log_info "Запуск docker compose..."
  131. cd "$PROJECT_DIR"
  132. docker compose -f deploy/docker-compose.prod.yml up -d --build --remove-orphans
  133. log_ok "Контейнеры запущены"
  134. }
  135. # 6. Health checks
  136. health_check() {
  137. log_info "Ожидание готовности сервисов (до 120 сек)..."
  138. local max_attempts=60
  139. local attempt=0
  140. while [ $attempt -lt $max_attempts ]; do
  141. attempt=$((attempt + 1))
  142. # Проверка Caddy (порт 2019 metrics)
  143. if docker compose -f deploy/docker-compose.prod.yml exec -T caddy wget -q --spider http://localhost:2019/metrics 2>/dev/null; then
  144. # Проверка backend через Caddy (HTTP, SSL на Synology)
  145. if curl -sf "http://localhost/api/v1/health" >/dev/null 2>&1; then
  146. log_ok "Backend здоров"
  147. break
  148. fi
  149. fi
  150. if [ $attempt -eq $max_attempts ]; then
  151. log_err "Таймаут ожидания здоровья"
  152. docker compose -f deploy/docker-compose.prod.yml logs --tail=50 caddy backend
  153. exit 1
  154. fi
  155. sleep 2
  156. done
  157. # Финальная проверка через HTTPS (Synology)
  158. log_info "Проверка через HTTPS (Synology)..."
  159. if curl -sf "https://photoplaces.ru/api/v1/health" >/dev/null 2>&1; then
  160. log_ok "HTTPS health check пройден"
  161. else
  162. log_warn "HTTPS check не прошёл (проверьте настройки Synology Reverse Proxy)"
  163. fi
  164. }
  165. # 7. Вывод результатов
  166. show_result() {
  167. echo
  168. log_ok "=== ДЕПЛОЙ УСПЕШНО ЗАВЕРШЁН ==="
  169. echo
  170. echo " Фронтенд: https://photoplaces.ru"
  171. echo " API: https://api.photoplaces.ru/api/v1"
  172. echo " S3 API: https://api.photoplaces.ru/s3"
  173. echo " MinIO Console: https://api.photoplaces.ru/minio-console/"
  174. echo
  175. echo " Логи: cd $PROJECT_DIR && docker compose -f deploy/docker-compose.prod.yml logs -f"
  176. echo " Статус: cd $PROJECT_DIR && docker compose -f deploy/docker-compose.prod.yml ps"
  177. echo " Остановка: cd $PROJECT_DIR && docker compose -f deploy/docker-compose.prod.yml down"
  178. echo
  179. }
  180. # ===========================================
  181. # MAIN
  182. # ===========================================
  183. main() {
  184. check_deps
  185. setup_repo
  186. setup_env
  187. create_docker_secrets
  188. deploy
  189. health_check
  190. show_result
  191. }
  192. main "$@"