콘텐츠로 이동

Current Setup Analysis

KV namespace 'DOMAIN_KV' not found for staging environment

발생 위치: verify-resources.sh 실행 중

근본 원인:

  1. 프로비저닝 실패: provision_kv_namespace 함수가 KV를 생성하지 못함
  2. ID 추출 실패: 생성은 성공했지만 ID 추출 로직이 실패
  3. 환경 불일치: wrangler.jsoncstaging_kv_namespace_id placeholder가 남아있음

에러 2: tmate Action 파라미터 오류

섹션 제목: “에러 2: tmate Action 파라미터 오류”
Unexpected input(s) 'limit-access-to-this-repository', 'timeout-minutes'

발생 위치: deploy.yml의 모든 tmate action

근본 원인: mxschmitt/action-tmate@v3에서 지원하지 않는 파라미터 사용


증상: Provision 단계에서 시간이 너무 오래 걸림

근본 원인:

  1. 순차적 리소스 생성 (D1 → KV → Queue)
  2. 재시도 로직으로 인한 추가 지연
  3. 각 리소스마다 여러 API 호출

"kv_namespaces": [
{
"binding": "DOMAIN_KV",
"id": "staging_kv_namespace_id", // ❌ Placeholder
"preview_id": "staging_kv_preview_id"
}
]

문제점:

  • ✅ D1 Database: 실제 ID 존재 (220e9fe1-9401-4297-8cf2-0eeb9ca39ee8)
  • ❌ KV Namespace: Placeholder만 존재 (staging_kv_namespace_id)
  • ❌ 실제 KV Namespace ID가 설정되지 않음

Terminal window
1. KV Namespace 리스트 조회
└─> wrangler kv namespace list --env staging
2. DOMAIN_KV 검색
└─> get_kv_id_from_list() 함수로 ID 추출
3. ID가 없으면 생성 시도
└─> create_kv_namespace() 함수 호출
4. 생성 ID 추출
└─> grep으로 32자 hex ID 추출
5. wrangler.jsonc 업데이트
└─> update_wrangler_config() 함수 호출

실패 지점 추정:

  • Step 1: 리스트 조회 실패 (인증 문제?)
  • Step 2: ID 추출 실패 (파싱 로직 문제?)
  • Step 3: 생성 실패 (권한 문제?)
  • Step 4: ID 추출 실패 (출력 형식 문제?)

Terminal window
# 로컬에서 사용
pnpm dev:local
# wrangler.jsonc의 dev 환경
"kv_namespaces": [
{
"binding": "DOMAIN_KV",
"id": "dev_kv_namespace_id", // Placeholder
"preview_id": "dev_kv_preview_id"
}
]

특징:

  • 로컬 모드에서는 placeholder로도 작동 가능
  • 실제 리소스는 로컬 시뮬레이션

Terminal window
# CI에서 사용
wrangler deploy --env staging
# wrangler.jsonc의 staging 환경
"kv_namespaces": [
{
"binding": "DOMAIN_KV",
"id": "staging_kv_namespace_id", // Placeholder
"preview_id": "staging_kv_preview_id"
}
]

문제점:

  • 실제 Cloudflare 리소스 필요
  • Placeholder로는 작동하지 않음
  • 프로비저닝이 실패하면 배포 불가

증상: verify-resources.sh에서 KV 부재 감지

가능한 원인:

원인 A: 생성 실패

  • API 토큰 권한 부족 (KV:Edit 권한 없음)
  • 네트워크 문제
  • Cloudflare API 일시적 장애

원인 B: ID 추출 실패

  • wrangler kv namespace create 출력 형식 변경
  • grep 패턴이 실제 출력과 불일치
  • 생성 후 전파 시간 부족

원인 C: 환경 불일치

  • --env staging 플래그가 올바르게 작동하지 않음
  • 다른 계정의 리소스를 확인

확인 방법:

Terminal window
# 수동으로 생성 시도
wrangler kv namespace create DOMAIN_KV --env staging
# 출력 확인
# 예상 출력 형식:
# { binding = "DOMAIN_KV", id = "abc123...", preview_id = "def456..." }

현재 코드:

uses: mxschmitt/action-tmate@v3
with:
limit-access-to-this-repository: true # ❌
timeout-minutes: 30 # ❌

올바른 파라미터:

uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true # ✅
connect-timeout-seconds: 1800 # ✅ (30분 = 1800초)

현재 흐름:

D1 프로비저닝 (30초)
KV 프로비저닝 (30초)
Queue 프로비저닝 (60초)
총 시간: 120초+

개선 방안: 병렬 처리

D1 프로비저닝 (30초) ┐
KV 프로비저닝 (30초) ├→ 병렬 실행
Queue 프로비저닝 (60초) ← 순차 (의존성)
총 시간: 90초 (25% 단축)

미준수 사항:

  • ❌ 로컬 시뮬레이션: wrangler dev --remote 미사용
  • ❌ 실시간 로그: wrangler tail 통합 없음
  • ❌ 롤백 메커니즘: 없음
  • ❌ KISS 원칙: 복잡한 프로비저닝 로직

Phase 1: 즉시 수정 (Critical) - 1시간

섹션 제목: “Phase 1: 즉시 수정 (Critical) - 1시간”

파일: .github/workflows/deploy.yml

변경 전:

- name: Setup tmate session (on failure)
if: failure()
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-this-repository: true
timeout-minutes: 30

변경 후:

- name: Setup tmate session (on failure)
if: failure()
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
connect-timeout-seconds: 1800

위치: 4곳 (validate, provision, deploy, deploy-production)


파일: .github/scripts/lib/cloudflare-resources.sh

개선 사항:

A. 생성 후 즉시 검증

Terminal window
create_kv_namespace() {
local env="$1"
local namespace="DOMAIN_KV"
# 생성 시도
local create_output
create_output=$(npx wrangler kv namespace create "$namespace" --env "$env" 2>&1)
# 생성 성공 확인
if echo "$create_output" | grep -qiE "created|success|id\s*="; then
# 생성 전파 대기 (Cloudflare API 전파 시간)
echo "⏳ Waiting for namespace propagation..." >&2
sleep 3
# 즉시 리스트하여 ID 추출
local kv_list
local retry_count=0
local max_retries=5
while [[ $retry_count -lt $max_retries ]]; do
kv_list=$(npx wrangler kv namespace list --env "$env" 2>&1)
local kv_id
kv_id=$(get_kv_id_from_list "$env" "$kv_list")
if [[ -n "$kv_id" ]] && [[ ${#kv_id} -eq 32 ]]; then
echo "✅ KV namespace created and verified: $kv_id" >&2
echo "$kv_id"
return 0
fi
retry_count=$((retry_count + 1))
echo "⏳ Retry $retry_count/$max_retries..." >&2
sleep 2
done
echo "❌ Failed to extract KV namespace ID after creation" >&2
echo "Create output: $create_output" >&2
echo "List output: $kv_list" >&2
return 1
fi
# 생성 실패
echo "❌ Failed to create KV namespace" >&2
echo "Output: $create_output" >&2
return 1
}

B. 에러 메시지 개선

Terminal window
# 더 명확한 에러 메시지
if [[ -z "$kv_id" ]]; then
echo "::error::KV namespace '${KV_NAMESPACE}' not found for ${ENV} environment" >&2
echo "::error::Available namespaces:" >&2
echo "$KV_LIST" | head -20 >&2
echo "::error::To create: wrangler kv namespace create ${KV_NAMESPACE} --env ${ENV}" >&2
exit 1
fi

1.3 wrangler.jsonc Placeholder 검증 강화

섹션 제목: “1.3 wrangler.jsonc Placeholder 검증 강화”

파일: .github/scripts/lib/wrangler-config.sh

개선: Placeholder가 남아있으면 명확한 에러

Terminal window
validate_wrangler_config() {
local env="$1"
# Placeholder 확인
if grep -q "\"id\": \"${env}_kv_namespace_id\"" wrangler.jsonc; then
echo "::error::KV namespace ID is still a placeholder for ${env}" >&2
echo "::error::Run provision-resources.sh to update it" >&2
return 1
fi
# ... 기존 검증
}

파일: .github/scripts/steps/provision-resources.sh

개선 후:

Terminal window
# D1과 KV를 병렬로 프로비저닝
provision_resources_parallel() {
local env="$1"
echo "🚀 Provisioning resources in parallel..." >&2
# D1 프로비저닝 (백그라운드)
provision_d1_database "$env" > /tmp/d1-output.txt 2>&1 &
local d1_pid=$!
# KV 프로비저닝 (백그라운드)
provision_kv_namespace "$env" > /tmp/kv-output.txt 2>&1 &
local kv_pid=$!
# 대기 및 결과 확인
local d1_exit=0
local kv_exit=0
wait $d1_pid || d1_exit=$?
wait $kv_pid || kv_exit=$?
# 결과 확인
if [[ $d1_exit -ne 0 ]]; then
echo "❌ D1 provisioning failed" >&2
cat /tmp/d1-output.txt >&2
return 1
fi
if [[ $kv_exit -ne 0 ]]; then
echo "❌ KV provisioning failed" >&2
cat /tmp/kv-output.txt >&2
return 1
fi
# ID 추출
local d1_id
d1_id=$(cat /tmp/d1-output.txt | tail -1)
local kv_id
kv_id=$(cat /tmp/kv-output.txt | tail -1)
# wrangler.jsonc 업데이트
update_wrangler_config "$env" "$d1_id" "$kv_id"
# Queue는 순차적으로 (의존성 없음이지만 안전을 위해)
provision_queues "$env"
}

예상 시간 절약: 120초 → 90초 (25% 단축)


Phase 3: Cloudflare 가이드 준수 (Medium) - 3시간

섹션 제목: “Phase 3: Cloudflare 가이드 준수 (Medium) - 3시간”

파일: package.json

추가 스크립트:

{
"scripts": {
"dev:remote:staging": "wrangler dev --remote --env staging",
"dev:remote:production": "wrangler dev --remote --env production"
}
}

사용법:

Terminal window
# Staging 환경과 동일한 리소스로 로컬 테스트
pnpm dev:remote:staging
# Production 환경과 동일한 리소스로 로컬 테스트
pnpm dev:remote:production

장점:

  • ✅ 로컬에서 실제 Cloudflare 리소스 사용
  • ✅ CI 환경과 100% 동일한 환경 재현
  • ✅ 배포 전 문제 발견 가능

파일: .github/workflows/deploy.yml

배포 후 로그 확인 추가:

- name: Post-deployment Log Check
if: success()
run: |
echo "📊 Checking deployment logs..."
timeout 30 wrangler tail --env "${{ steps.env.outputs.environment }}" --format pretty | head -50 || true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

파일: scripts/rollback.sh (신규)

#!/usr/bin/env bash
# Rollback to previous deployment
set -euxo pipefail
ENV="${1:-staging}"
echo "🔄 Rolling back ${ENV} environment..."
# 이전 배포 확인
PREVIOUS=$(wrangler deployments list --env "$ENV" 2>&1 | grep -v "Version" | head -2 | tail -1 | awk '{print $1}')
if [[ -z "$PREVIOUS" ]]; then
echo "❌ No previous deployment found"
exit 1
fi
echo "📋 Previous version: $PREVIOUS"
# 롤백 실행
wrangler rollback --env "$ENV" --message "Rollback to $PREVIOUS via script"
echo "✅ Rolled back to version: $PREVIOUS"

package.json에 추가:

{
"scripts": {
"rollback:staging": "bash scripts/rollback.sh staging",
"rollback:production": "bash scripts/rollback.sh production"
}
}

Phase 4: KISS 원칙 적용 (Simplification) - 2시간

섹션 제목: “Phase 4: KISS 원칙 적용 (Simplification) - 2시간”

4.1 환경별 리소스 사전 생성 스크립트

섹션 제목: “4.1 환경별 리소스 사전 생성 스크립트”

파일: scripts/setup-cloudflare-resources.sh (신규)

#!/usr/bin/env bash
# One-time setup: Create all Cloudflare resources for all environments
# Run this once manually, then CI only verifies
set -euxo pipefail
ENVIRONMENTS=("dev" "staging" "production")
echo "🔧 Setting up Cloudflare resources for all environments..."
echo "⚠️ This script should be run ONCE manually"
echo ""
for env in "${ENVIRONMENTS[@]}"; do
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Environment: $env"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# D1 Database
echo "🗄️ D1 Database..."
wrangler d1 create "newsfork-metadata-${env}" 2>&1 | grep -v "already exists" || echo " (already exists)"
# KV Namespace
echo "🔑 KV Namespace..."
wrangler kv namespace create DOMAIN_KV --env "$env" 2>&1 | grep -v "already exists" || echo " (already exists)"
# Queues
echo "📬 Queues..."
for queue in research contract liveness seed domain; do
wrangler queues create "newsfork-${queue}-${env}" 2>&1 | grep -v "already exists" || echo " (already exists)"
done
# DLQ
echo "📮 Dead Letter Queues..."
wrangler queues create "newsfork-dlq-${env}" 2>&1 | grep -v "already exists" || echo " (already exists)"
wrangler queues create "newsfork-seed-dlq-${env}" 2>&1 | grep -v "already exists" || echo " (already exists)"
wrangler queues create "newsfork-domain-dlq-${env}" 2>&1 | grep -v "already exists" || echo " (already exists)"
echo ""
done
echo "✅ Resource setup completed"
echo ""
echo "📝 Next steps:"
echo " 1. Update wrangler.jsonc with actual resource IDs"
echo " 2. Run: pnpm run provision:update-config"

장점:

  • ✅ 한 번만 실행
  • ✅ CI에서는 검증만 수행 (빠름)
  • ✅ KISS 원칙 준수

현재: 복잡한 재시도 및 에러 처리

개선: 단순한 “존재 확인 → 없으면 생성 → 검증”

Terminal window
# 단순화된 프로비저닝
provision_resource_simple() {
local resource_type="$1" # "d1", "kv", "queue"
local resource_name="$2"
local env="$3"
# 존재 확인
if resource_exists "$resource_type" "$resource_name" "$env"; then
echo "$resource_name already exists"
return 0
fi
# 생성
echo "🔨 Creating $resource_name..."
if create_resource "$resource_type" "$resource_name" "$env"; then
echo "$resource_name created"
return 0
else
echo "❌ Failed to create $resource_name"
return 1
fi
}

❌ KV Namespace 부재 → 배포 실패
❌ tmate Action 오류 → 디버깅 불가
❌ 프로비저닝 시간: 120초+
❌ 로컬-CI 환경 불일치
❌ 롤백 불가
✅ KV Namespace 자동 생성 및 검증
✅ tmate Action 정상 동작
✅ 프로비저닝 시간: 90초 (25% 단축)
✅ 로컬-CI 환경 일치 (wrangler dev --remote)
✅ 롤백 메커니즘 추가
✅ 실시간 로그 모니터링
✅ KISS 원칙 준수

Phase 1: 즉시 수정 (Critical) - 1시간

섹션 제목: “Phase 1: 즉시 수정 (Critical) - 1시간”
  1. ✅ tmate Action 파라미터 수정 (4곳)
  2. ✅ KV Namespace 생성 로직 개선
  3. ✅ 에러 메시지 명확화
  1. ✅ 병렬 리소스 프로비저닝
  2. ✅ 리소스 존재 확인 최적화

Phase 3: 가이드 준수 (Medium) - 3시간

섹션 제목: “Phase 3: 가이드 준수 (Medium) - 3시간”
  1. ✅ 로컬 시뮬레이션 강화 (wrangler dev --remote)
  2. ✅ 실시간 로그 모니터링 통합
  3. ✅ 롤백 메커니즘 추가
  1. ✅ 프로비저닝 로직 단순화
  2. ✅ 환경별 리소스 사전 생성 스크립트

  • tmate Action 파라미터 수정 (4곳)
  • KV Namespace 생성 로직 개선
  • 에러 메시지 명확화
  • Placeholder 검증 강화
  • 병렬 리소스 프로비저닝
  • 리소스 존재 확인 최적화
  • wrangler dev --remote 스크립트 추가
  • 실시간 로그 모니터링 통합
  • 롤백 메커니즘 추가
  • 프로비저닝 로직 단순화
  • 환경별 리소스 사전 생성 스크립트

작성 일시: 2026-01-28
우선순위: Critical
예상 소요 시간: 8시간 (단계별 구현)