Communitygithub.com

Bohdan-Meshcheriakov/deploy-data-clerk

이 앱이 Data Clerk 호스팅(Kubernetes 클러스터)에서 어떻게 빌드, 배포, 구성 및 유지되는지 설명합니다. 사용자가 앱을 배포, 게시, '라이브'로 전환하려 할 때, 환경 변수, API 키 또는 시크릿을 추가/변경하거나, secrets.env를 편집하거나, sops를 사용할 때, 이를 위한 도구를 설치할 때, 데이터베이스 테이블이나 마이그레이션을 추가할 때, 데이터베이스, 백업 또는 데이터 복원에 대해 질문할 때, 도메인이나 HTTPS에 대해 질문할 때, 사이트가 다운되었거나 푸시 후 업데이트되지 않은 이유에 대해 질문할 때, Dockerfile이나 Git 작업에 대해 질문할 때 이 스킬을 사용하세요.

deploy-data-clerk란 무엇인가요?

이 스킬은 Data Clerk 호스팅(관리형 Kubernetes 클러스터)에 배포된 애플리케이션의 배포, 구성 및 유지 관리를 자동화합니다. 주요 목표는 인프라 담당자가 아닌 사용자도 `main` 브랜치에 푸시하기만 하면 나머지는 클러스터가 처리하도록 만드는 것입니다. GitHub Actions를 통한 코드 배포, sops를 통한 암호화된 secrets.env 관리, 자동 데이터베이스 마이그레이션, 상태 확인, 롤링 업데이트 등을 지원합니다. 이 스킬은 Claude Code, Cursor, Codex와 같은 AI 에이전트에서 사용할 수 있으며, SKILL.md 문서를 기반으로 사용자에게 명확한 지침과 문제 해결 방법을 제공합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Bohdan-Meshcheriakov/data-clerk-skills/tree/HEAD/skills/deploy-data-clerk

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Data Clerk에 배포하기

이 앱은 Data Clerk에서 실행됩니다. Data Clerk은 운영자(PROJECT.md에 연락처 있음)가 운영하는 소규모 관리형 Kubernetes 클러스터입니다. 이 저장소의 소유자는 일반적으로 인프라 담당자가 아닙니다. 서버, Kubernetes 또는 클라우드 콘솔을 직접 다룰 필요가 없습니다. main에 푸시하면 나머지는 클러스터가 처리합니다. 당신의 역할은 그 상태를 유지하는 것입니다: 저장소 내에서 작업하고 아래 계약을 따르며, 정말로 클러스터 측 처리가 필요한 일이 있을 때는 즉흥적으로 처리하지 말고 운영자에게 명확한 요청을 작성하세요.

사용자에게 Kubernetes 용어가 아닌 일반 언어로 설명하십시오("사이트가 약 5분 후에 업데이트됩니다").

시작하기

  1. deploy-data-clerk/PROJECT.md를 읽으십시오. 이 파일에는 이 프로젝트의 값들(공개 URL, 배포 폴더, 이미지 이름, 포트, 마이그레이션 명령, 제한, 운영자 정보)이 포함되어 있습니다. 아래에서 "PROJECT.md에서"라고 표시된 모든 내용은 이 파일을 의미합니다. PROJECT.md의 폴더 이름이 deploy-data-clerk/와 다른 경우(이전 프로젝트는 deploy/ 사용), PROJECT.md에 명시된 것을 사용하십시오.
  2. PROJECT.md가 없거나 여전히 __PLACEHOLDER__ 값이 있습니까? 프로젝트가 아직 온보딩되지 않은 것입니다: references/new-project.md를 따르세요.
  3. Dockerfile을 작성/변경하거나, 앱 구조를 선택하거나, Node가 아닌 스택을 사용합니까? references/stacks.md를 읽으십시오(모든 언어, 풀 스택 대 별도 프론트엔드 + API, FastAPI, Go).
  4. 머신에서 첫 번째 시크릿 작업을 수행하기 전에 도구가 작동하는지 확인하십시오: sops --version 및 테스트 복호화(sops decrypt <deploy folder>/secrets.env > /dev/null). 둘 중 하나라도 실패하면 references/setup-tools.md를 따르세요.

변경 사항이 라이브 사이트에 도달하는 방법

변경 사항결과라이브까지 시간
코드 (main에 푸시)GitHub Actions가 Docker 이미지를 빌드 및 푸시하고, 클러스터가 새 이미지 태그를 감지하여 롤아웃합니다~3–7분 (빌드 시간 + ~1분)
secrets.env (main에 푸시)클러스터가 5분마다 배포 폴더를 다시 읽고, 복호화하며, 앱의 환경 변수를 업데이트하고 앱을 다시 시작합니다~5분
migrations/의 새 파일새 버전이 시작되기 전에 자동으로 실행됩니다코드 배포와 동시에
main 외부의 모든 것아무 일도 일어나지 않습니다. 브랜치와 PR은 배포되지 않습니다—

롤아웃은 신중하게 이루어집니다: 새 버전이 기존 버전 옆에서 시작되고, 마이그레이션이 먼저 실행되며, 새 버전이 상태 확인에 응답한 후에야 트래픽이 이동합니다. 빌드, 마이그레이션 또는 상태 확인이 실패하면 이전 버전이 계속 서비스를 제공하며 사이트가 유지됩니다. 배포 실패는 "변경 사항이 라이브가 아님"을 의미할 뿐, "사이트가 다운됨"을 의미하지 않습니다.

배포를 확인하려면: gh run list --workflow "Deploy to cluster" --limit 3 (또는 GitHub의 Actions 탭)을 실행한 다음 공개 URL을 여십시오. 코드 변경 없이 재배포하려면: gh workflow run "Deploy to cluster"를 실행합니다. 그러면 새 태그가 빌드되어 앱이 새 환경으로 다시 시작됩니다.

계약 (배포가 작동하도록 유지하는 규칙)

각 규칙은 위반 시 자동으로 실패하거나 데이터가 손실되기 때문에 존재합니다. 이를 준수하고, 사용자의 요청이 하나라도 위반할 경우 사용자에게 알리십시오.

  • $PORT에서 수신 대기 (PROJECT.md에 있는 포트, 클러스터가 설정함), 0.0.0.0에서, localhost가 아닙니다.
  • 이미지는 <deploy folder>/Dockerfile에서 linux/amd64용으로 빌드되며 루트가 아닌 사용자로 실행됩니다. 루트 없음, 1024 미만 포트 없음, 추가 Linux 기능 없음.
  • 이미지 태그는 YYYYMMDDHHMMSS-<shortsha> 형식입니다. 클러스터는 가장 높은 번호의 태그를 배포하고 이 형식이 아닌 태그는 자동으로 무시합니다. .github/workflows/deploy-cluster.yml의 태그 단계를 절대 변경하지 마십시오.
  • 컨테이너의 디스크는 배포 및 재시작할 때마다 초기화됩니다. 사용자 업로드, SQLite 파일 또는 중요한 데이터를 로컬 디스크에 절대 보관하지 마십시오. 데이터는 데이터베이스에 저장하고, 파일(사진, 비디오)의 경우 운영자에게 객체 스토리지를 요청하십시오.
  • 상태 확인: 클러스터는 PROJECT.md의 상태 경로(/healthz 권장)를 탐색합니다. 데이터베이스 호출이나 페이지 렌더링 없이 빠르게 200을 반환하도록 만드십시오. 그렇지 않으면 느린 DB로 인해 클러스터가 앱이 중단된 것으로 간주할 수 있습니다.
  • DATABASE_URL은 클러스터에서 제공됩니다. 절대 secrets.env에 넣지 마십시오(실제 값을 덮어씁니다). 이미지 빌드 시 설정하지 마십시오.
  • 런타임 대 빌드 시간. secrets.env는 런타임에만 앱에 도달합니다. 이미지는 GitHub Actions에서 secrets.env 없이 빌드됩니다. 빌드 시 프론트엔드에 인라인되는 모든 것(VITE_*, NEXT_PUBLIC_*, REACT_APP_*)은 secrets.env에서 가져올 수 없습니다. 이러한 값은 런타임에 서버에서 읽어 페이지에 전달하거나, (시크릿이 아닌 경우) 코드에 커밋하십시오.
  • 앱이 누락될 때 자체 생성하는 시크릿(인증/세션 시크릿, 암호화 솔트, 푸시 키)은 secrets.env에 설정하십시오. 그렇지 않으면 재시작할 때마다 새로 생성되어 사용자가 로그아웃되고, 푸시 구독이 중단되는 등의 문제가 발생합니다.
  • 마이그레이션은 이전 버전에 안전해야 합니다. 약 1분 동안 두 버전 모두 새 스키마에 대해 실행됩니다. 열과 테이블을 자유롭게 추가하십시오. 이름 변경 또는 삭제는 두 번의 배포로 수행하십시오: 먼저 사용을 중지한 다음 제거하십시오. 자세한 내용은 references/database.md를 참조하십시오.

환경 변수 및 시크릿

모든 런타임 구성은 <deploy folder>/secrets.env에 있으며, sops로 암호화되어 커밋됩니다. 값만 암호화되고 키 이름은 읽을 수 있습니다. sops 자체를 사용하여 변경하십시오. 커밋할 수 있는 파일로 복호화하지 말고, 비밀 값을 채팅이나 로그에 출력하지 마십시오.

sops set deploy-data-clerk/secrets.env '["STRIPE_SECRET_KEY"]' '"sk_live_..."'
sops unset deploy-data-clerk/secrets.env '["OLD_KEY"]'
sops decrypt deploy-data-clerk/secrets.env | cut -d= -f1

그런 다음 커밋하고 main에 푸시하면 약 5분 후에 라이브가 됩니다. 사용자가 값(예: 대시보드의 API 키)을 제공해야 하는 경우, 사용자가 직접 sops set 명령을 실행하거나 값만 자신의 터미널에 붙여넣도록 하십시오. 전체 가이드(키, 위치, 순환, 주의 사항)는 references/secrets.md에 있습니다.

데이터베이스

Postgres 18, 운영자가 관리합니다. 앱은 DATABASE_URL을 통해 자체 데이터베이스와 사용자를 얻습니다. 스키마 변경은 배포 시 자동으로 적용되는 마이그레이션 파일입니다(references/database.md).

백업: 매일 03:00 UTC에 전체 백업이 수행되고 모든 변경 사항의 지속적인 로그가 Google Cloud Storage에 서버 외부에 저장됩니다. 운영자는 지난 7일 이내의 어떤 시점으로든 데이터베이스를 복원할 수 있습니다. 따라서 데이터가 삭제되거나 마이그레이션이 잘못되어도 당황하지 말고 손으로 직접 수정하려고 하지 마십시오. 발생한 시간을 기록하고 운영자에게 복원을 요청하십시오(references/troubleshooting.md의 템플릿 참조). 복원은 전체 데이터베이스를 되감기 때문에 해당 시점 이후의 변경 사항은 손실됩니다.

코드에서 필요할 수 있는 네트워크 정보

  • 트래픽 경로: 방문자 → Cloudflare → Traefik (클러스터 인그레스) → 앱. HTTPS 인증서는 자동입니다. 앱 자체는 $PORT에서 일반 HTTP를 사용합니다. X-Forwarded-Proto: https는 원래 요청이 HTTPS였음을 나타냅니다. 프록시 헤더를 신뢰하고 앱에서 HTTPS로 리디렉션하지 마십시오(루프가 발생함).
  • 실제 방문자 IP: CF-Connecting-IP 헤더를 읽으십시오. X-Forwarded-For에는 Cloudflare 주소가 포함되어 있으므로 이를 기준으로 속도 제한을 설정하면 모든 방문자가 하나의 버킷에 포함됩니다.
  • Traefik은 다음 헤더를 추가합니다: HSTS(2년, preload), X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN (사이트를 다른 도메인의 iframe에 삽입할 수 없음). 추가 헤더(CSP, SharedArrayBuffer용 COOP/COEP, iframe 허용)는 요청 시 운영자가 설정합니다.
  • 인그레스는 응답을 압축하지 않습니다. Cloudflare가 일반적인 텍스트 유형을 압축합니다. 완전한 제어를 위해서는 앱에서 압축하거나 사전 압축된 자산을 제공하십시오.
  • 긴 연결(SSE, 웹소켓)은 괜찮지만, Cloudflare는 약 100초 동안 유휴 상태인 연결을 끊습니다. 약 30초마다 하트비트를 보내고 클라이언트에서 다시 연결하십시오.
  • 아웃바운드: 앱은 모든 포트의 모든 공개 인터넷 엔드포인트를 호출할 수 있습니다. 여기에는 LLM API, Stripe, 이메일, S3 및 관리형 데이터베이스 또는 Redis(Neon, Supabase, Atlas, Upstash)의 공개 엔드포인트가 포함됩니다. 개인 네트워크(VPC 피어링, PrivateLink, 개인 IP) 또는 클러스터의 다른 프로젝트에 도달할 수 없습니다. 인바운드 트래픽은 공개 URL을 통해서만 들어옵니다.
  • 타사 서비스: 해당 키와 URL을 secrets.env에 넣으십시오. 서비스에 IP 허용 목록이 필요한 경우, 클러스터에는 하나의 고정 아웃바운드 IP가 있습니다: 운영자에게 문의하십시오(공개되지 않음). 그리고 클러스터의 다른 프로젝트와 공유된다고 사용자에게 알리십시오. 서버는 미국 중부에 있으므로 외부 데이터베이스에는 미국 중부/미국 동부 지역을 선호하십시오(유럽 데이터베이스는 쿼리당 약 100ms가 추가됩니다). 외부 데이터베이스는 사용자의 책임입니다. Data Clerk의 백업은 이를 포함하지 않습니다. 느린 LLM 호출의 경우 응답을 스트리밍하거나 백그라운드 작업으로 실행하십시오. 약 100초 이상 기다리는 브라우저 요청은 중단됩니다.
  • 리소스는 제한됩니다(PROJECT.md의 메모리/CPU). 메모리 제한을 초과하면 앱이 종료되고 다시 시작됩니다. 이런 경우 코드로 해결하려고 하지 말고 운영자에게 더 많은 공간을 요청하십시오.
  • 앱의 복사본 하나가 실행됩니다(하나의 복제본). 배포 후에도 지속되는 인메모리 상태에 의존하지 말고 세션을 DB나 서명된 쿠키에 유지하십시오.

운영자만 할 수 있는 작업

사용자는 클러스터에 접근할 수 없습니다. 이는 의도된 설계입니다. 다음에 대해 운영자에게 짧은 요청을 작성하십시오(references/troubleshooting.md의 템플릿 참조):

새 도메인 또는 서브도메인 · 더 많은 메모리/CPU · 파일/객체 스토리지 · 데이터베이스 복원 · 앱 로그 또는 충돌 원인 · 변경된 보안 헤더 · 마이그레이션 또는 시작 명령, 포트 또는 상태 경로 변경 · 예약된 작업(cron) · 추가 서비스(Redis, 큐) · 동일한 프로젝트의 두 번째 앱 · 새 저장소 온보딩.

더 자세한 내용

  • references/stacks.md: 모든 언어에 대한 범용 계약; 풀 스택 대 SPA + API 대 정적; Node, Python FastAPI, Go 및 기타 스택.
  • references/new-project.md: 저장소 온보딩(추가할 파일, 운영자에게 요청할 사항, 스택별 Dockerfile).
  • references/secrets.md: sops 심층 설명, 키 파일, 순환, 빌드 시간 변수.
  • references/database.md: 마이그레이션, 연결 문자열, 백업, 데이터 수정.
  • references/setup-tools.md: macOS, Linux 및 Windows에서 sops/git/gh를 안전하게 설치. scripts/install-tools.sh 또는 scripts/install-tools.ps1을 실행하십시오.
  • references/troubleshooting.md: "내 변경 사항이 라이브가 아닙니다", "사이트가 다운됨", 일반적인 오류, 운영자 요청 템플릿.
  • assets/: Dockerfile 템플릿(Node, Python, Go) 및 배포 워크플로우, kustomization.yaml, .sops.yaml, .gitattributes 및 PROJECT.md용 템플릿.

관련 스킬