| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- #!/usr/bin/env bash
- # ===========================================
- # PhotoPlaces — Удалённый деплой на тестовый сервер
- # ===========================================
- # Запуск на сервере 192.168.88.128:
- # curl -fsSL https://raw.githubusercontent.com/foxtime/photoplaces/main/deploy/deploy-remote.sh | bash
- # Или склонировав репо и запустив:
- # cd /home/foxtime/photoplaces && bash deploy/deploy-remote.sh
- # ===========================================
- set -euo pipefail
- # Цвета для вывода
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- BLUE='\033[0;34m'
- NC='\033[0m' # No Color
- log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
- log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
- log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
- log_err() { echo -e "${RED}[ERR]${NC} $*"; }
- # Конфигурация
- REPO_URL="http://192.168.88.96:10880/foxtime/photoplaces.git"
- PROJECT_DIR="/home/foxtime/photoplaces"
- BRANCH="main"
- ENV_FILE="$PROJECT_DIR/deploy/env.prod"
- log_info "=== PhotoPlaces Remote Deploy ==="
- log_info "Сервер: $(hostname) ($(hostname -I | awk '{print $1}'))"
- log_info "Пользователь: $(whoami)"
- log_info "Директория: $PROJECT_DIR"
- # 1. Проверка зависимостей
- check_deps() {
- log_info "Проверка зависимостей..."
- local missing=()
- for cmd in docker git curl openssl; do
- if ! command -v "$cmd" >/dev/null 2>&1; then
- missing+=("$cmd")
- fi
- done
- if ! docker compose version >/dev/null 2>&1; then
- missing+=("docker compose")
- fi
- if [ ${#missing[@]} -gt 0 ]; then
- log_err "Отсутствуют: ${missing[*]}"
- log_info "Установите: sudo apt update && sudo apt install -y docker.io docker-compose-plugin git curl openssl"
- exit 1
- fi
- log_ok "Все зависимости установлены"
- }
- # 2. Клонирование/обновление репозитория
- setup_repo() {
- log_info "Настройка репозитория..."
- if [ -d "$PROJECT_DIR/.git" ]; then
- log_info "Репозиторий существует, обновляю..."
- cd "$PROJECT_DIR"
- git fetch origin
- git reset --hard "origin/$BRANCH"
- git clean -fd
- else
- log_info "Клонирую репозиторий..."
- git clone --branch "$BRANCH" "$REPO_URL" "$PROJECT_DIR"
- cd "$PROJECT_DIR"
- fi
- log_ok "Репозиторий готов: $(git rev-parse --short HEAD)"
- }
- # 3. Настройка env.prod
- setup_env() {
- log_info "Настройка переменных окружения..."
- cd "$PROJECT_DIR"
- if [ ! -f "$ENV_FILE" ]; then
- cp deploy/env.prod.example "$ENV_FILE"
- log_info "Создан $ENV_FILE из шаблона"
- fi
- # Автогенерация секретов если пустые или CHANGE_ME
- generate_secret() {
- local var="$1"
- local current="${!var:-}"
- if [[ -z "$current" || "$current" == *"CHANGE_ME"* ]]; then
- local secret
- secret=$(openssl rand -hex 32)
- if [[ "$OSTYPE" == "darwin"* ]]; then
- sed -i '' "s/^${var}=.*/${var}=${secret}/" "$ENV_FILE"
- else
- sed -i "s/^${var}=.*/${var}=${secret}/" "$ENV_FILE"
- fi
- export "$var=$secret"
- log_ok "$var сгенерирован автоматически"
- fi
- }
- # Загружаем текущие значения
- set -a
- source "$ENV_FILE"
- set +a
- generate_secret "DB_PASSWORD"
- generate_secret "REDIS_PASSWORD"
- generate_secret "JWT_SECRET"
- 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
- if [ -z "${!var:-}" ]; then
- missing+=("$var")
- fi
- done
- if [ ${#missing[@]} -gt 0 ]; then
- log_warn "Требуют ручного заполнения в $ENV_FILE:"
- for var in "${missing[@]}"; do
- echo " - $var"
- done
- log_info "Откройте $ENV_FILE и заполните недостающие значения, затем запустите скрипт снова"
- exit 1
- fi
- log_ok "Все секреты настроены"
- }
- # 4. Создание Docker secrets (если Swarm)
- create_docker_secrets() {
- if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
- log_info "Swarm mode: создание Docker secrets..."
- 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 -
- 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 -
- 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 -
- 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 -
- 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 -
- log_ok "Docker secrets созданы"
- fi
- }
- # 5. Деплой через docker compose
- deploy() {
- log_info "Запуск docker compose..."
- cd "$PROJECT_DIR"
- docker compose -f deploy/docker-compose.prod.yml up -d --build --remove-orphans
- log_ok "Контейнеры запущены"
- }
- # 6. Health checks
- health_check() {
- log_info "Ожидание готовности сервисов (до 120 сек)..."
- local max_attempts=60
- local attempt=0
- 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
- # Проверка backend через Caddy (HTTP, SSL на Synology)
- if curl -sf "http://localhost/api/v1/health" >/dev/null 2>&1; then
- log_ok "Backend здоров"
- break
- fi
- fi
- if [ $attempt -eq $max_attempts ]; then
- log_err "Таймаут ожидания здоровья"
- docker compose -f deploy/docker-compose.prod.yml logs --tail=50 caddy backend
- exit 1
- fi
- sleep 2
- done
- # Финальная проверка через HTTPS (Synology)
- log_info "Проверка через HTTPS (Synology)..."
- if curl -sf "https://photoplaces.ru/api/v1/health" >/dev/null 2>&1; then
- log_ok "HTTPS health check пройден"
- else
- log_warn "HTTPS check не прошёл (проверьте настройки Synology Reverse Proxy)"
- fi
- }
- # 7. Вывод результатов
- show_result() {
- echo
- log_ok "=== ДЕПЛОЙ УСПЕШНО ЗАВЕРШЁН ==="
- echo
- echo " Фронтенд: https://photoplaces.ru"
- echo " API: https://api.photoplaces.ru/api/v1"
- echo " S3 API: https://api.photoplaces.ru/s3"
- echo " MinIO Console: https://api.photoplaces.ru/minio-console/"
- echo
- echo " Логи: cd $PROJECT_DIR && docker compose -f deploy/docker-compose.prod.yml logs -f"
- echo " Статус: cd $PROJECT_DIR && docker compose -f deploy/docker-compose.prod.yml ps"
- echo " Остановка: cd $PROJECT_DIR && docker compose -f deploy/docker-compose.prod.yml down"
- echo
- }
- # ===========================================
- # MAIN
- # ===========================================
- main() {
- check_deps
- setup_repo
- setup_env
- create_docker_secrets
- deploy
- health_check
- show_result
- }
- main "$@"
|