| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- #!/usr/bin/env bash
- set -euo pipefail
- cd "$(dirname "$0")/.."
- ENV_FILE="${1:-deploy/env.prod}"
- echo "=== PhotoPlaces — деплой ==="
- # 1. Load secrets from external source if configured
- # Supported: 1password (op), hashicorp vault, aws secretsmanager, or local file
- load_secrets() {
- if command -v op >/dev/null 2>&1 && [ -n "${OP_VAULT:-}" ] && [ -n "${OP_ITEM:-}" ]; then
- echo ">>> Loading secrets from 1Password..."
- eval $(op read "op://${OP_VAULT}/${OP_ITEM}" --format=env 2>/dev/null || true)
- elif command -v vault >/dev/null 2>&1 && [ -n "${VAULT_ADDR:-}" ] && [ -n "${VAULT_TOKEN:-}" ] && [ -n "${VAULT_PATH:-}" ]; then
- echo ">>> Loading secrets from HashiCorp Vault..."
- vault kv get -format=json "${VAULT_PATH}" | jq -r '.data.data | to_entries[] | "export \(.key)=\(.value)"' > /tmp/vault_env.sh
- source /tmp/vault_env.sh
- rm -f /tmp/vault_env.sh
- elif command -v aws >/dev/null 2>&1 && [ -n "${AWS_SECRETS_NAME:-}" ]; then
- echo ">>> Loading secrets from AWS Secrets Manager..."
- aws secretsmanager get-secret-value --secret-id "${AWS_SECRETS_NAME}" --query SecretString --output text | jq -r 'to_entries[] | "export \(.key)=\(.value)"' > /tmp/aws_env.sh
- source /tmp/aws_env.sh
- rm -f /tmp/aws_env.sh
- elif [ -f "$ENV_FILE" ]; then
- echo ">>> Loading secrets from $ENV_FILE..."
- else
- echo "Ошибка: ни один источник секретов не настроен"
- echo " - 1Password: export OP_VAULT=... OP_ITEM=..."
- echo " - Vault: export VAULT_ADDR=... VAULT_TOKEN=... VAULT_PATH=..."
- echo " - AWS: export AWS_SECRETS_NAME=..."
- echo " - Local: создайте $ENV_FILE из deploy/env.prod.example"
- exit 1
- fi
- }
- load_secrets
- # 2. If using local file, check for CHANGE_ME placeholders and offer to generate
- if [ -f "$ENV_FILE" ]; then
- set -a
- source "$ENV_FILE"
- set +a
- check_secret() {
- local var=$1
- local val="${!var:-}"
- if [[ "$val" == *"CHANGE_ME"* ]] || [[ -z "$val" ]]; then
- echo "!!! $var не настроен. Сгенерировать случайный? [y/N]"
- read -r answer
- if [[ "$answer" == "y" ]]; 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
- echo "✓ $var сгенерирован"
- export "$var=$secret"
- else
- echo "Пропущено. Не забудьте настроить вручную!"
- fi
- fi
- }
- check_secret "DB_PASSWORD"
- check_secret "REDIS_PASSWORD"
- check_secret "JWT_SECRET"
- check_secret "JWT_REFRESH_SECRET"
- check_secret "S3_SECRET_KEY"
- fi
- # 3. Validate required secrets
- required_vars=("DB_PASSWORD" "REDIS_PASSWORD" "JWT_SECRET" "JWT_REFRESH_SECRET" "S3_SECRET_KEY" "S3_PUBLIC_ENDPOINT" "NEXT_PUBLIC_API_URL" "ALLOWED_ORIGINS")
- missing=()
- for var in "${required_vars[@]}"; do
- if [ -z "${!var:-}" ]; then
- missing+=("$var")
- fi
- done
- if [ ${#missing[@]} -gt 0 ]; then
- echo "Ошибка: отсутствуют обязательные переменные:"
- printf ' %s\n' "${missing[@]}"
- exit 1
- fi
- # 4. Create Docker secrets if in Swarm mode
- create_docker_secrets() {
- if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
- echo ">>> Swarm mode detected, creating 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 -
- fi
- }
- create_docker_secrets
- # 5. Build and deploy
- echo ">>> Собираю и запускаю контейнеры..."
- docker compose -f deploy/docker-compose.prod.yml up -d --build
- # 5. Health check (migrations run in entrypoint)
- echo ">>> Проверяю здоровье (ждём миграции + старт)..."
- for i in $(seq 1 30); do
- HEALTH=$(curl -sf http://localhost:8080/api/v1/health 2>/dev/null || echo '{"status":"fail"}')
- if echo "$HEALTH" | grep -q '"ok"'; then
- break
- fi
- if [ $i -eq 30 ]; then
- echo "✗ Таймаут ожидания здоровья API"
- docker compose -f deploy/docker-compose.prod.yml logs --tail=30 backend
- exit 1
- fi
- sleep 2
- done
- echo "✓ Деплой успешен!"
- echo "API: ${NEXT_PUBLIC_API_URL}"
- echo "Фронтенд: http://localhost:3000"
- echo "MinIO консоль: ${S3_PUBLIC_ENDPOINT}:9001"
|