feat: add manual production deployment pipeline
Deploy EG-BIM QA Gateway / deploy (push) Failing after 7s
Deploy EG-BIM QA Gateway / deploy (push) Failing after 7s
This commit is contained in:
1 parent
1808f14cc6
commit
0755155368
13 files changed
+1391
-5
No files matched your search
@@ -0,0 +1,108 @@
|
||||
# Q&A 운영 배포 체크리스트
|
||||
|
||||
대상 도메인: `https://qa.baroncs.co.kr`
|
||||
정리일: 2026-10-28
|
||||
|
||||
## 현재 저장소에서 확인한 상태
|
||||
|
||||
- 스테이징은 `baron-qa-gateway-test`, `qa-test.baroncs.co.kr`, `baron-qa-pages`를 사용한다.
|
||||
- 운영 Worker `baron-qa-gateway-prod`, custom domain `qa.baroncs.co.kr`, R2 버킷 `baron-qa-write` 생성과 연결을 사용자가 완료했다.
|
||||
- 운영 전용 `wrangler.production.toml`과 수동 배포 workflow `Deploy EG-BIM QA Production`을 추가했다.
|
||||
- 운영 등록값과 실행 방법은 [production 파이프라인 안내](qa-production-pipeline.md)를 따른다. 실제 운영 배포는 아직 수행하지 않았다.
|
||||
|
||||
## 내가 준비·확정할 항목
|
||||
|
||||
### 1. DNS와 Cloudflare
|
||||
|
||||
- [x] `baroncs.co.kr` zone이 운영 Cloudflare 계정에 있는지 확인했다.
|
||||
- [x] `qa.baroncs.co.kr`을 운영 Worker custom domain으로 연결했다.
|
||||
- [x] 스테이징과 같은 Cloudflare 계정에 운영 Worker와 버킷을 생성했다.
|
||||
- [x] 운영 정적 파일용 R2 버킷을 생성했다: `baron-qa-write`. 스테이징 `baron-qa-pages`와 분리해 사용한다.
|
||||
- [x] 배포용 Cloudflare API token에 계정 범위의 Workers Scripts Read/Write, Workers R2 Storage Read/Write, Account Settings Read 권한을 부여하고 `PROD_CLOUDFLARE_API_TOKEN` Secret에 등록했다. 사용자 등록 완료 보고 기준이며 실제 token 인증은 배포 실행 시 검증한다. 도메인 연결은 대시보드에서 완료했다. [권한 상세](qa-production-pipeline.md)
|
||||
|
||||
### 2. SSO 운영 등록
|
||||
|
||||
- [x] 운영 callback URI를 SSO에 등록했다: `https://qa.baroncs.co.kr/auth/callback`. 사용자 완료 보고 기준이다.
|
||||
- [x] 로그아웃 후 이동 URI를 SSO에 등록했다: `https://qa.baroncs.co.kr/`. 사용자 완료 보고 기준이다.
|
||||
- [x] 운영 SSO 설정에 맞는 `PROD_AUTH_CLIENT_ID` 등 관련 변수 등록을 완료했다. 실제 로그인 동작 확인은 운영 배포 후 수행한다.
|
||||
- [ ] 운영 도메인에서 실제 사내 사용자로 로그인·로그아웃할 수 있는지 확인한다.
|
||||
|
||||
### 3. ABC UserFeedback 운영 대상
|
||||
|
||||
- [ ] **보류 — 관리페이지 서버 확정 후 진행:** 운영 API 주소를 확정하고 `PROD_ABC_API_BASE_URL`에 등록한다.
|
||||
- [ ] **보류 — 관리페이지 서버 확정 후 진행:** 운영 project ID와 channel ID를 확정하고 `PROD_ABC_PROJECT_ID`, `PROD_ABC_CHANNEL_ID`에 등록한다. 현재 저장소의 ID를 운영에서 재사용해도 되는지 확인한다.
|
||||
- [ ] **보류 — 관리페이지 서버 확정 후 진행:** 운영 project/channel에 문의 생성, 첨부, 댓글 조회·등록·수정·삭제 권한이 있는 API key를 준비하고 Gitea Secret `PROD_ABC_API_KEY`에 등록한다. 이 키가 등록될 때까지 첫 운영 배포는 진행하지 않는다.
|
||||
- [ ] `requester_affiliation`, `requester_department` 필드가 운영 channel에서 허용되는지 확인한다.
|
||||
- [ ] 운영 문의를 스테이징 데이터와 분리할지 결정한다. 기존 데이터 이전이 필요하면 별도 이관 범위와 실행 계획을 정한다.
|
||||
- [ ] 운영 source namespace와 idempotency consumer를 스테이징과 구분할 값을 정한다.
|
||||
|
||||
### 4. 조직 컨텍스트 API
|
||||
|
||||
- [ ] 운영에서 조회할 기준 tenant UUID를 확정한다. 여러 개면 JSON 배열로 제공한다.
|
||||
- [ ] 운영용 `ORG_CONTEXT_KEY_ID`와 `ORG_CONTEXT_KEY_SECRET`을 준비한다. 스테이징 키 재사용이 허용되는지 API 소유자에게 확인한다.
|
||||
- [ ] 운영 키가 해당 기준 tenant에 대해 `SCOPED` / `identifiers` 조회 권한을 갖는지 확인한다.
|
||||
- [ ] 운영 설정으로 org API 사전 검증을 통과시킨다. 키와 조직 원문이 빌드 로그에 출력되지 않는지 확인한다.
|
||||
|
||||
### 5. 운영 배포 값 등록
|
||||
|
||||
스테이징에 등록한 `STAGING_*` 값은 운영 배포에 자동 적용되지 않는다. [production 파이프라인 안내의 확정된 `PROD_*` 등록 목록](qa-production-pipeline.md)을 사용해 Gitea **Actions Variables / Secrets**에 등록한다. 아래는 운영 대상 값의 요약이다.
|
||||
|
||||
- [x] 사용자 보고 기준, 관리페이지 연동 `PROD_ABC_*` 4개를 제외한 운영 Secrets와 Variables 등록을 완료했다. 실제 연결·권한은 배포 전에 검증한다.
|
||||
|
||||
**운영 설정**
|
||||
|
||||
| 설정 | 운영 값 |
|
||||
|---|---|
|
||||
| Worker 이름 | `baron-qa-gateway-prod` |
|
||||
| Worker custom domain | `qa.baroncs.co.kr` |
|
||||
| AUTH redirect URI | `https://qa.baroncs.co.kr/auth/callback` |
|
||||
| AUTH post logout URI | `https://qa.baroncs.co.kr/` |
|
||||
| AUTH client ID | 운영 SSO client ID |
|
||||
| ABC API base URL | `https://feedback.hmac.kr` 또는 운영 API 주소 |
|
||||
| ABC project ID / channel ID | 운영 대상 ID |
|
||||
| ABC source namespace / idempotency consumer | 스테이징과 구별되는 운영 값 |
|
||||
| R2 bucket | `baron-qa-write` |
|
||||
| ORG_CONTEXT_ENABLED | `true` |
|
||||
| ORG_CONTEXT_API_URL | `https://sadmin.hmac.kr/api/v1/integrations/org-context` |
|
||||
| ORG_CONTEXT_SCOPE_MODE / EXPOSURE | `SCOPED` / `identifiers` |
|
||||
| ORG_CONTEXT_TENANT_IDS | 운영 기준 tenant UUID JSON 배열 |
|
||||
| ORG_CONTEXT_CACHE_TTL_SECONDS | `300` 권장 |
|
||||
|
||||
**운영 Secrets 용도**
|
||||
|
||||
| Secret | 용도 |
|
||||
|---|---|
|
||||
| Cloudflare API token | 운영 Worker와 정적 파일 배포 |
|
||||
| `SESSION_SECRET` | 운영 세션 서명용. 스테이징과 별도 값 |
|
||||
| `ABC_API_KEY` | 운영 ABC project/channel API 접근 |
|
||||
| `ORG_CONTEXT_KEY_ID` | 조직 컨텍스트 연동 Key ID |
|
||||
| `ORG_CONTEXT_KEY_SECRET` | 조직 컨텍스트 연동 Key Secret |
|
||||
|
||||
Secret 원문은 소스, Markdown, 채팅, workflow 로그에 넣지 않는다.
|
||||
|
||||
## 개발 측에서 필요한 변경
|
||||
|
||||
- [x] 스테이징 설정을 보존하면서 production 전용 Wrangler 설정을 추가했다.
|
||||
- [x] Worker 이름, domain, OAuth URL, R2 bucket, ABC 대상, 조직 API 값을 환경별로 분리했다.
|
||||
- [x] 별도 운영 배포 스크립트를 추가하고, 운영 배포 전에 `npm run org:verify`를 수행하도록 연결했다.
|
||||
- [x] production 수동 배포 workflow에 `PROD_*` 매핑과 필수값 검증을 추가했다.
|
||||
- [x] 운영 정적 파일을 운영 버킷의 커밋별 release 경로에 업로드하도록 연결했다.
|
||||
- [ ] 배포 실행 전에 변경 범위와 대상 도메인을 검토하고, staging 배포와 product 배포가 섞이지 않도록 확인한다.
|
||||
|
||||
## 운영 배포 후 확인
|
||||
|
||||
- [ ] `https://qa.baroncs.co.kr`의 TLS 인증서와 정적 페이지 응답을 확인한다.
|
||||
- [ ] SSO 로그인·로그아웃 및 세션 쿠키 동작을 확인한다.
|
||||
- [ ] 회사·부서가 조직 API 기준 정보와 일치하는지 확인한다.
|
||||
- [ ] 텍스트 문의와 이미지 첨부 문의를 각각 1건 등록하고, 운영 ABC 화면의 requester 정보·회사·부서 값을 확인한다.
|
||||
- [ ] 목록, 상세, 댓글 조회·등록을 확인하고 댓글 수정·삭제 권한을 작성자 기준으로 확인한다.
|
||||
- [ ] 브라우저 Network 탭과 Cloudflare Worker logs에 API key, 연동 secret, 사용자 전화번호 원문이 노출되지 않는지 확인한다.
|
||||
- [ ] 오류 시 이전 Worker 버전으로 되돌리는 방법과 담당자를 기록한다.
|
||||
|
||||
## 진행 순서
|
||||
|
||||
1. 사용자가 DNS/SSO/ABC/Cloudflare 운영 값과 데이터 분리 방침을 확정한다.
|
||||
2. 개발 측에서 production 설정·workflow를 분리하고, 운영 변수·secret 이름을 확정해 공유한다.
|
||||
3. 사용자가 운영용 Gitea Variables/Secrets를 등록한다.
|
||||
4. production 조직 API 사전 검증과 배포 전 점검을 통과시킨다.
|
||||
5. production 배포 승인 후 `qa.baroncs.co.kr`에서 위 운영 확인 항목을 완료한다.
|
||||
@@ -0,0 +1,117 @@
|
||||
# Q&A production 배포 파이프라인
|
||||
|
||||
## 배포 대상과 실행 방식
|
||||
|
||||
| 항목 | 운영 값 |
|
||||
|---|---|
|
||||
| Workflow | `.gitea/workflows/deploy-production.yml` |
|
||||
| Actions 표시 이름 | `Deploy EG-BIM QA Production` |
|
||||
| 실행 | Gitea Actions에서 `main`을 선택해 수동 실행 |
|
||||
| Worker | `baron-qa-gateway-prod` |
|
||||
| Custom Domain | `https://qa.baroncs.co.kr` |
|
||||
| Cloudflare account ID | `81fa2d48964d31dd0da9558f9ce601d1` |
|
||||
| 정적 파일 R2 bucket | `baron-qa-write` |
|
||||
| R2 binding 이름 | `QA_BUCKET` |
|
||||
| 정적 파일 저장 경로 | `releases/<전체 커밋 SHA>/egbim/...`, `releases/<전체 커밋 SHA>/assets/...` |
|
||||
|
||||
운영 Worker와 도메인 연결, 버킷 생성은 사용자가 Cloudflare 대시보드에서 완료했다. 실제 Q&A 코드 배포는 이 workflow로 수행한다. `main` push는 기존 스테이징 workflow를 실행하며, 운영 workflow는 수동 실행만 지원한다. 운영 실행도 `main`의 선택된 커밋과 checkout 결과가 같아야 진행한다.
|
||||
|
||||
배포 파일은 `wrangler.production.toml`을 사용한다. 운영 세션 쿠키·source namespace는 별도로 지정했고 `workers.dev`와 preview URL은 비활성화한다. 운영 접속 주소는 `qa.baroncs.co.kr`이다. 이미 연결한 custom domain은 Cloudflare 대시보드에서 관리한다. Wrangler 설정에는 `route`와 `routes`를 지정하지 않아 배포 시 기존 도메인 연결을 유지하며 zone 라우팅을 변경하지 않는다.
|
||||
|
||||
## Gitea에 등록할 Secrets
|
||||
|
||||
저장소 **Settings → Actions → Secrets**에 등록한다. 기존 기본 Secret이나 `STAGING_*` 값을 자동으로 가져오지 않는다. 기존 키가 운영 리소스에도 권한이 있다면 값은 재사용할 수 있지만, 아래 운영 설정 이름으로 등록해야 한다. `SESSION_SECRET`은 운영 전용 값을 사용한다.
|
||||
|
||||
| 이름 | 값 |
|
||||
|---|---|
|
||||
| `PROD_CLOUDFLARE_API_TOKEN` | 기존 운영 Worker를 배포하고 R2 파일을 업로드할 수 있는 Cloudflare token |
|
||||
| `PROD_SESSION_SECRET` | 최소 32자 운영 세션 서명키. 예: `openssl rand -hex 32`로 생성한 값 |
|
||||
| `PROD_ABC_API_KEY` | **등록 보류:** 관리페이지 서버 확정 후 운영 ABC project/channel API key 등록 |
|
||||
| `PROD_ORG_CONTEXT_KEY_ID` | 운영 조직 컨텍스트 연동 Key ID |
|
||||
| `PROD_ORG_CONTEXT_KEY_SECRET` | 운영 조직 컨텍스트 연동 Key Secret |
|
||||
|
||||
Cloudflare 프로필 **API Tokens → Create Token → Create Custom Token**에서 운영 배포 token을 생성하거나 기존 token의 권한을 확인한다.
|
||||
|
||||
| 범위 | 권한 | 수준 | 용도 |
|
||||
|---|---|---|---|
|
||||
| Account / Workers product | Workers | Editor | 기존 Worker 코드·Secret·binding 배포. 레거시 Workers Scripts Edit도 허용 |
|
||||
| Account | Workers R2 Storage | Edit / Write | 정적 파일을 R2에 업로드 |
|
||||
| Account | Account Settings | Read | Wrangler 계정 정보 조회 |
|
||||
|
||||
**Account Resources**는 `바른기술개발센터` 계정으로 지정한다. 생성한 token 값은 `PROD_CLOUDFLARE_API_TOKEN` Secret에 넣는다. 도메인 연결은 대시보드에서 이미 완료했으므로 운영 배포 token에는 Workers Routes Write와 Zone Read를 요구하지 않는다. 현재 파이프라인은 Wrangler의 Cloudflare REST API를 사용하므로 R2 S3 Access Key ID / Secret Access Key는 필요하지 않다.
|
||||
|
||||
R2 권한은 계정 범위의 **Workers R2 Storage Write/Edit**를 선택한다. `R2 → baron-qa-write` 범위의 **Workers R2 Storage Bucket Item Read/Write**는 S3 객체 접근용이므로 현재 Wrangler REST 업로드에 필요한 권한을 대신하지 않는다. 운영 배포에는 Zone Write 정책도 필요하지 않다.
|
||||
|
||||
근거: [Workers 권한](https://developers.cloudflare.com/workers/authorization/workers/), [R2 token 권한](https://developers.cloudflare.com/r2/api/tokens/), [대시보드에서 route를 관리하는 Wrangler 설정](https://developers.cloudflare.com/workers/wrangler/configuration/#source-of-truth).
|
||||
|
||||
## Gitea에 등록할 Variables
|
||||
|
||||
저장소 **Settings → Actions → Variables**에 등록한다.
|
||||
|
||||
| 이름 | 필수 | 값 |
|
||||
|---|---|---|
|
||||
| `PROD_AUTH_CLIENT_ID` | 필수 | 운영 callback URI가 허용된 SSO client ID |
|
||||
| `PROD_ABC_API_BASE_URL` | 필수 / 등록 보류 | 관리페이지 서버 확정 후 운영 ABC HTTPS origin 등록. `/api` 경로를 붙이지 않는다. |
|
||||
| `PROD_ABC_PROJECT_ID` | 필수 / 등록 보류 | 관리페이지 서버 확정 후 운영 ABC project UUID 등록 |
|
||||
| `PROD_ABC_CHANNEL_ID` | 필수 / 등록 보류 | 관리페이지 서버 확정 후 운영 ABC channel UUID 등록 |
|
||||
| `PROD_ORG_CONTEXT_ENABLED` | 필수 | `true` |
|
||||
| `PROD_ORG_CONTEXT_TENANT_IDS` | 필수 | 기준 tenant UUID JSON 배열. 예: `["tenant-UUID"]` |
|
||||
| `PROD_ORG_CONTEXT_API_URL` | 선택 | 기본 `https://sadmin.hmac.kr/api/v1/integrations/org-context` |
|
||||
| `PROD_ORG_CONTEXT_SCOPE_MODE` | 선택 | 기본 `SCOPED` |
|
||||
| `PROD_ORG_CONTEXT_EXPOSURE` | 선택 | 기본 `identifiers` |
|
||||
| `PROD_ORG_CONTEXT_CACHE_TTL_SECONDS` | 선택 | 기본 `300`, 허용 범위 1~3600 |
|
||||
|
||||
SSO에는 `https://qa.baroncs.co.kr/auth/callback`을 허용하고, 로그아웃 후 이동 URI로 `https://qa.baroncs.co.kr/`을 확인한다. 등록된 SSO client나 ABC project/channel이 운영 대상인지 확정한 후 배포한다.
|
||||
|
||||
지금 준비할 Variables는 `PROD_AUTH_CLIENT_ID`와 `PROD_ORG_CONTEXT_*` 6개다. `PROD_AUTH_CLIENT_ID`의 참고값은 기존 스테이징 client `e16898a7-acd2-420a-a224-cdcd89ff66cd`이며, 이 client에 운영 callback이 허용된 경우에만 운영에서도 재사용한다. 별도 운영 client를 만들었다면 그 ID를 등록한다. 기준 tenant UUID와 조직 연동 키는 실제 발급받은 값을 사용한다. 기존 `STAGING_*` 등록은 `PROD_*` 등록으로 간주하지 않는다.
|
||||
|
||||
회사·부서 조회용 sadmin 조직 컨텍스트 API 설정은 ABC 관리페이지 연동 설정과 별개다. 조직 API 주소·기준 tenant·키의 운영 사용이 확정된 경우 미리 등록할 수 있다. Secret 값이나 테스트 fixture UUID를 실제 설정값으로 문서에 기록하지 않는다.
|
||||
|
||||
Worker runtime에는 `PROD_`를 제거한 이름으로 주입한다. `DEPLOY_COMMIT_SHA`는 workflow가 선택된 커밋에서 자동으로 전달하므로 Gitea에 따로 등록하지 않는다.
|
||||
|
||||
## Workflow 순서
|
||||
|
||||
1. 소스를 checkout하고 `main` 브랜치·커밋 일치를 확인한다.
|
||||
2. 운영 필수 설정, UUID, 조직 API 설정과 세션 서명키 길이를 검사한다. 누락 시 배포 전에 중단한다.
|
||||
3. `npm ci`로 고정된 의존성을 설치한다.
|
||||
4. `npm run check`와 `npm test`를 실행한다.
|
||||
5. `npm run org:verify`로 실제 운영 조직 API의 인증·범위·구성원 응답을 검증한다.
|
||||
6. `npm run deploy:production -- --dry-run`으로 Worker 번들을 만든다. 이 단계는 Cloudflare 리소스를 변경하지 않는다.
|
||||
7. 해당 커밋의 정적 파일을 `baron-qa-write/releases/<SHA>/...`에 올린다.
|
||||
8. `npm run deploy:production`으로 코드·runtime 변수·Secret을 같은 Worker 배포에 반영한다.
|
||||
9. `npm run production:verify`로 익명 세션, CSS 응답·커밋 일치, 비로그인 글쓰기 redirect를 확인한다. 전파 지연에 대비해 최대 5회 확인한다.
|
||||
|
||||
Secret 파일은 임시 디렉터리에 접근 권한 `0600`으로 만들고 배포 명령 종료 후 삭제한다. Secret 값은 CLI 인자나 로그로 출력하지 않는다.
|
||||
|
||||
## 첫 운영 배포 실행
|
||||
|
||||
현재 `PROD_ABC_API_KEY`, `PROD_ABC_API_BASE_URL`, `PROD_ABC_PROJECT_ID`, `PROD_ABC_CHANNEL_ID` 등록은 관리페이지 서버 확정까지 보류한다. 이 값들이 없으면 필수 설정 검증에서 배포를 중단한다. SSO·조직 컨텍스트·Cloudflare·세션 서명키 설정은 먼저 준비할 수 있다.
|
||||
|
||||
- [x] 관리페이지 연동 `PROD_ABC_*` 4개를 제외한 운영 Secrets와 Variables 등록을 완료했다. 사용자 보고 기준이며 실제 값·권한 검증은 아직 수행하지 않았다.
|
||||
- [ ] 관리페이지 서버 확정 후 `PROD_ABC_API_KEY`, `PROD_ABC_API_BASE_URL`, `PROD_ABC_PROJECT_ID`, `PROD_ABC_CHANNEL_ID`를 등록한다.
|
||||
- [x] 운영 SSO callback과 관련 변수 등록을 완료했다. 사용자 완료 보고 기준이다.
|
||||
- [ ] ABC project/channel과 조직 API의 실제 접근 권한을 확인한다.
|
||||
- [ ] 이 변경을 `main`에 반영한다.
|
||||
- [ ] Gitea **Actions → Deploy EG-BIM QA Production → Run workflow**에서 `main`을 선택한다.
|
||||
- [ ] 설정 검증·조직 API 검증·정적 파일 업로드·Worker 배포·HTTP 확인이 모두 성공하는지 확인한다.
|
||||
- [ ] 실제 계정으로 로그인하고 문의·첨부·댓글 기능과 저장된 회사·부서를 확인한다. 자동 HTTP 확인은 로그인 이후의 실제 사용자 작업까지 검증하지 않는다.
|
||||
|
||||
## 실패와 롤백
|
||||
|
||||
- 설정·조직 API·빌드 검증 실패는 운영 정적 파일 업로드와 Worker 배포 전에 중단된다.
|
||||
- 정적 파일 업로드가 실패해도 기존 Worker는 이전 커밋 경로를 계속 읽는다. 다시 실행하면 같은 커밋 경로로 업로드한다.
|
||||
- Worker 배포 후 HTTP 확인이 실패하면 workflow는 실패로 표시되지만 이미 반영한 배포를 자동으로 되돌리지는 않는다. 마지막 정상 Worker 버전으로 명시적으로 롤백한다.
|
||||
- Cloudflare의 `baron-qa-gateway-prod` **Deployments**에서 마지막 정상 버전으로 rollback하면 해당 버전의 `QA_ASSET_PREFIX`와 정적 파일을 다시 사용한다. 이전 release 경로는 보관한다.
|
||||
- 첫 배포의 이전 버전은 기본 Hello World일 수 있다. 첫 배포 실패 시에는 설정을 수정해 다시 실행하고, 필요하면 기본 버전으로 되돌릴 수 있다.
|
||||
- R2 release 파일 정리 시 활성 버전과 롤백에 필요한 버전의 prefix를 삭제하지 않는다. 정적 파일 롤백은 ABC에 저장된 문의·댓글 데이터를 되돌리지 않는다.
|
||||
|
||||
## 로컬 확인
|
||||
|
||||
```sh
|
||||
npm run check
|
||||
npm test
|
||||
node scripts/deploy-production.mjs --validate-only
|
||||
npm run deploy:production -- --dry-run
|
||||
```
|
||||
|
||||
마지막 두 명령은 위 runtime 이름의 운영 설정과 `DEPLOY_COMMIT_SHA`가 실행 환경에 필요하다. `--validate-only`는 설정 형식만 확인하고, `--dry-run`은 로컬 번들만 확인한다. 실제 자격증명과 API의 유효성은 Gitea workflow의 조직 API 검증과 실제 배포에서 확인한다.
|
||||
Reference in new issue
Block a user