#!/usr/bin/env bash set -e export KUBECONFIG="${KUBECONFIG:-/home/chpark/.kube/config}" # root 실행 시엔 sudo 생략, 일반 유저면 비번으로 sudo if [ "$(id -u)" -eq 0 ]; then sudo_run() { bash -c "$1"; } else SUDO_PASS="${SUDO_PASS:-qlalfqjsgh11}" sudo_run() { echo "$SUDO_PASS" | sudo -S bash -c "$1"; } fi # CI(root) 환경에서 kubeconfig 없으면 k3s 것으로 대체 if [ ! -r "$KUBECONFIG" ]; then if [ -r /etc/rancher/k3s/k3s.yaml ]; then export KUBECONFIG=/etc/rancher/k3s/k3s.yaml fi fi cd /home/chpark if [ -d insurance/.git ]; then echo "[*] Updating insurance repo" cd insurance && git fetch origin && git reset --hard origin/master else rm -rf /home/chpark/insurance 2>/dev/null || true echo "[*] Cloning insurance repo" git clone https://git.junggomoa.com/chpark/insurance.git cd insurance fi # 빌드 전에 비밀값 로드 (EXPO_PUBLIC_* 포함) SECRETS_FILE=/home/chpark/.insurance-secrets if [ -r "$SECRETS_FILE" ]; then set -a; source "$SECRETS_FILE"; set +a fi echo "[*] Building web image (kakao key len=${#EXPO_PUBLIC_KAKAO_JS_KEY})" docker build \ --build-arg EXPO_PUBLIC_API_BASE=https://api.insurance.junggomoa.com \ --build-arg EXPO_PUBLIC_KAKAO_JS_KEY="${EXPO_PUBLIC_KAKAO_JS_KEY:-}" \ --build-arg EXPO_PUBLIC_NAVER_CLIENT_ID="${EXPO_PUBLIC_NAVER_CLIENT_ID:-}" \ -t localhost:5000/insurance/web:latest \ -f Dockerfile . echo "[*] Building api image" docker build -t localhost:5000/insurance/api:latest -f server/Dockerfile server echo "[*] Pushing to local registry" docker push localhost:5000/insurance/web:latest docker push localhost:5000/insurance/api:latest echo "[*] Applying Kubernetes manifests" kubectl apply -f deploy/k8s/namespace.yaml POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-$(openssl rand -hex 24)}" JWT_SECRET="${JWT_SECRET:-$(openssl rand -hex 32)}" # 기존 secret 파일의 다른 키들은 보존하고 이 두 값만 갱신 write_kv() { local key="$1" val="$2" file="$3" if [ -f "$file" ]; then grep -v "^${key}=" "$file" > "${file}.tmp" || true mv "${file}.tmp" "$file" fi echo "${key}=${val}" >> "$file" } touch "$SECRETS_FILE" write_kv POSTGRES_PASSWORD "$POSTGRES_PASSWORD" "$SECRETS_FILE" write_kv JWT_SECRET "$JWT_SECRET" "$SECRETS_FILE" chmod 600 "$SECRETS_FILE" kubectl -n insurance create secret generic postgres-credentials \ --from-literal=username=insurance \ --from-literal=password="$POSTGRES_PASSWORD" \ --dry-run=client -o yaml | kubectl apply -f - kubectl -n insurance create secret generic api-secrets \ --from-literal=jwtSecret="$JWT_SECRET" \ --from-literal=databaseUrl="postgresql://insurance:${POSTGRES_PASSWORD}@postgres:5432/insurance?schema=public" \ --from-literal=anthropicApiKey="${ANTHROPIC_API_KEY:-}" \ --from-literal=clovaOcrUrl="${CLOVA_OCR_URL:-}" \ --from-literal=clovaOcrSecret="${CLOVA_OCR_SECRET:-}" \ --from-literal=gcpVisionApiKey="${GCP_VISION_API_KEY:-}" \ --from-literal=solapiApiKey="${SOLAPI_API_KEY:-}" \ --from-literal=solapiApiSecret="${SOLAPI_API_SECRET:-}" \ --from-literal=solapiPfId="${SOLAPI_PFID:-}" \ --from-literal=solapiSenderKey="${SOLAPI_SENDER_KEY:-}" \ --from-literal=codefClientId="${CODEF_CLIENT_ID:-}" \ --from-literal=codefClientSecret="${CODEF_CLIENT_SECRET:-}" \ --from-literal=kakaoRestApiKey="${KAKAO_REST_API_KEY:-}" \ --from-literal=kakaoClientSecret="${KAKAO_CLIENT_SECRET:-}" \ --dry-run=client -o yaml | kubectl apply -f - kubectl apply -f deploy/k8s/postgres.yaml kubectl -n insurance rollout status statefulset/postgres --timeout=180s kubectl apply -f deploy/k8s/api.yaml kubectl -n insurance rollout restart deployment/insurance-api || true if ! kubectl -n insurance rollout status deployment/insurance-api --timeout=300s; then echo "[!] API rollout failed, printing logs" kubectl -n insurance logs -l app.kubernetes.io/name=insurance-api --tail=80 || true kubectl -n insurance describe pod -l app.kubernetes.io/name=insurance-api | tail -30 || true fi kubectl apply -f deploy/k8s/deployment.yaml kubectl apply -f deploy/k8s/service.yaml kubectl -n insurance rollout restart deployment/insurance-web || true kubectl -n insurance rollout status deployment/insurance-web --timeout=180s echo "[*] Installing Traefik dynamic routing" sudo_run "cp /home/chpark/insurance/deploy/traefik-dynamic.yml /opt/docker/traefik/dynamic/insurance.yml && chmod 644 /opt/docker/traefik/dynamic/insurance.yml && ls -la /opt/docker/traefik/dynamic/insurance.yml" echo "" echo "===== DEPLOY STATUS =====" kubectl -n insurance get pods,svc echo "" echo "--- NodePort health check ---" sleep 5 curl -fsS http://127.0.0.1:30200/health 2>&1 | head -3 || echo "[!] web 30200 not ready" curl -fsS http://127.0.0.1:30201/health 2>&1 | head -3 || echo "[!] api 30201 not ready" echo "" echo "🚀 Web: https://insurance.junggomoa.com" echo "🔌 API: https://api.insurance.junggomoa.com"