TM Taeyang Moon
Demo · 아키텍처 해설

moontaeyang.com 학습 포털

AI가 매일/매주 콘텐츠를 자동 생성하는 서버리스 정적 포털

Static Web AppsContainer Apps JobAzure OpenAI(키리스)Storage $web소셜 로그인
🔗
라이브 사이트moontaeyang.com
사이트 열기 →

이 문서는 이 사이트(moontaeyang.com) 자체를 하나의 Azure 데모로 보고, 어떤 서비스로 어떻게 구성했는지, 왜 그렇게 설계했는지를 직접 구축하려는 엔지니어 관점에서 설명합니다.


한눈에 보기

moontaeyang.com은 매일/매주 AI가 콘텐츠를 자동 생성해 올리는 개인 학습 포털입니다. 정적 웹 호스팅 한 개(Static Web Apps) 위에, 두 개의 예약 실행 AI 에이전트(Container Apps Job)가 콘텐츠를 만들어 붙입니다. 핵심 키워드는 서버리스 · 키리스(시크릿 없음) · 스케줄 기반 · 정적 우선입니다.


아키텍처

                                  ┌──────────────────────────────────────┐
   사용자(브라우저) ──HTTPS──▶     │   Azure Static Web Apps (Standard)    │
   moontaeyang.com               │   - 글로벌 CDN + 무료 TLS 인증서        │
                                  │   - 커스텀 도메인(moontaeyang.com, www)│
   소셜 로그인 ──/.auth/*──▶      │   - 내장 인증(Google·GitHub·Kakao OIDC)│
                                  │   - 정적 파일 서빙 + SPA fallback       │
                                  └───────────────▲──────────────────────┘
                                                  │ swa deploy(전체 포털 재조립)
                 ┌────────────────────────────────┴────────────────────────────────┐
                 │                                                                  │
   ┌─────────────┴─────────────┐                                  ┌─────────────────┴───────────────┐
   │ Container Apps Job         │  매일 06:00 KST                   │ Container Apps Job              │  매주 월 06:00 KST
   │ engitdaily-job             │  (cron 0 21 * * *)                │ azwhatsnew-job                  │  (cron 0 21 * * 0)
   │  1) HN/RSS 수집            │                                  │  1) Azure 업데이트 RSS 수집      │
   │  2) Azure OpenAI 요약/생성 │◀── Managed Identity(키리스) ──▶  │  2) Azure OpenAI 요약           │
   │  3) Storage $web 에 누적   │                                  │  3) Storage $web 에 누적         │
   │  4) 포털 전체 재조립→배포  │                                  │  4) 포털 전체 재조립→배포        │
   │  5) Telegram 알림          │                                  │  5) Telegram 알림               │
   └─────────────┬─────────────┘                                  └─────────────────┬───────────────┘
                 │                                                                  │
   ┌─────────────▼─────────────┐                                  ┌─────────────────▼───────────────┐
   │ Storage(engit) $web        │  과거 일자 페이지 누적            │ Storage(azwn) $web              │  과거 주차 페이지 누적
   │ engitdailyst…              │  (영구 "창고")                   │ azwhatsnewst…                   │  (영구 "창고")
   └────────────────────────────┘                                  └─────────────────────────────────┘

   공통: 각 에이전트는 전용 ACR(이미지) · User-Assigned Managed Identity(UAMI) · Container Apps Environment 보유.
   정적 섹션(/labs, /demos)은 저장소 HTML → 포털 셸에 포함되어 매 배포 시 함께 게시.

사용된 Azure 서비스 (역할별)

서비스 역할 비고
Azure Static Web Apps (Standard) 공개 웹 서빙, 커스텀 도메인, TLS, 소셜 로그인 커스텀 인증·OIDC는 Standard 필수
Azure Container Apps Job 예약(cron) 배치로 콘텐츠 생성 평소 0개 인스턴스 → 실행 시에만 과금(서버리스)
Azure OpenAI (gpt-5.4) 기사/요약/단어 생성 키리스: Managed Identity + RBAC로 호출
Azure Storage(Blob, $web) 생성된 페이지 누적 보관(창고) + md 이력 정적 웹사이트 컨테이너 $web 활용
Azure Container Registry(ACR) 에이전트 컨테이너 이미지 저장 az acr build로 클라우드 빌드
User-Assigned Managed Identity ACR pull · Storage 읽기/쓰기 · OpenAI 호출 권한 시크릿 0개 운영의 핵심
Telegram Bot API(외부) 게시 완료 알림 토큰은 Job 환경변수(시크릿)로만

Microsoft Entra ID(앱 등록)는 소셜 로그인 중 GitHub/Google/Kakao OAuth 앱과 SWA 인증 연동에 사용됩니다.


핵심 설계 포인트 (왜 이렇게 했나)

1. 왜 Static Web Apps인가

2. 왜 Standard 플랜인가

3. 콘텐츠 "누적"과 클로버링 문제 (가장 중요)

4. 정적 섹션 vs 동적 섹션

5. 키리스(Keyless) 운영

6. 스케줄(cron)은 UTC 기준

7. 보안 가드레일


데이터 흐름

(A) 사용자 요청 흐름 1. 브라우저가 moontaeyang.com 요청 → SWA가 글로벌 CDN에서 정적 파일 응답(TLS 자동). 2. 로그인 클릭 → /.auth/login/<provider> → 공급자(Google/Kakao/GitHub) 인증 → 콜백 → 세션 쿠키. 3. SPA fallback: 매칭 안 되는 경로는 셸 index.html로(단, /engit-daily/*,/azure-daily/*,/labs/*,/demos/*,/.auth/*는 제외).

(B) 콘텐츠 생성 흐름(에이전트, 하루/주 1회) 1. cron이 Job 실행 → 컨테이너 시작(이미지는 ACR에서 pull). 2. 소스 수집(Hacker News API / Azure 업데이트 RSS). 3. Azure OpenAI(키리스) 로 기사·요약·단어 생성. 4. 결과를 Storage $web 에 누적(오늘/이번주 페이지 + 섹션 index 갱신), md 이력은 Blob에 보관. 5. 포털 재조립: 셸(+정적 섹션 labs/demos) 복사 + 두 동적 섹션을 각 $web에서 미러링 → swa deploy. 6. Telegram으로 "게시 완료 + 링크" 알림.


비용 개요 (대략, 개인 트래픽 기준)


엔지니어용 구축 순서 (요약)

  1. SWA(Standard) 생성 + 커스텀 도메인(moontaeyang.com, www) 연결 + DNS(A/ALIAS, TXT 검증).
  2. 소셜 로그인: Google/GitHub/Kakao OAuth 앱 등록 → SWA staticwebapp.config.jsonauth 블록(+Kakao는 customOIDC) → client-id/secret을 SWA 앱 설정에 주입(없으면 /.auth/* 404).
  3. 에이전트 인프라(각 1세트, Bicep): ACR + UAMI + Container Apps Environment + Job(cron) + Storage($web 정적 웹 활성화) + Azure OpenAI(배포 gpt-5.4).
  4. RBAC: UAMI에 AcrPull · Cognitive Services OpenAI User · 자기 Storage Blob Data Contributor · 상대 Storage Blob Data Reader(미러).
  5. 이미지 빌드/배포: az acr build로 이미지 → Job 업데이트(환경변수: PORTAL_SECTIONS, PORTAL_BASE_URL, SWA_DEPLOY_TOKEN(시크릿) 등).
  6. 배포 로직: 컨테이너가 런타임에 셸+정적 섹션 복사 + 동적 섹션 미러 + swa deploy.
  7. 알림: Telegram Bot 토큰/chat-id를 Job 환경변수로.
  8. 정적 섹션 추가: /labs, /demos는 마크다운→HTML로 빌드해 포털 셸에 포함.

자주 막히는 점 / 교훈


참고 자료

← 데모 목록학습 포털 홈