# OCI Blue/Green 배포 검증용 readiness 및 deployment endpoint PRD ## 문서 정보 | 항목 | 내용 | |---|---| | 문서 상태 | 구현 완료 | | 작성일 | 2026-09-14 | | 최종 수정일 | 2026-09-14 | | 대상 제품 | sodalive server 배포 검증 endpoint | | 작성자·결정권자 | 요청 사용자 | | 관련 구현 계획 | `docs/20260914_배포검증readiness및deployment엔드포인트/plan-task.md` | | 관련 review | 없음 | ## 1. Overview OCI Blue/Green 배포에서 배포 스크립트가 새로 기동한 인스턴스의 기동 완료 여부와, 실제로 어떤 artifact/config가 올라갔는지를 HTTP로 확인할 수 있어야 한다. 이를 위해 Spring Boot Actuator의 readiness probe와 배포 식별 정보를 반환하는 custom Actuator endpoint를 제공한다. ## 2. Problem Statement - 현재 프로젝트에는 Actuator 의존성과 health endpoint가 없어 배포 스크립트가 기동 완료를 판정할 방법이 없다. - 어떤 artifact 버전과 config commit이 배포되었는지 런타임에서 확인할 수 없다. - 모든 요청이 Spring Security의 `anyRequest().authenticated()`로 보호되어 있어 인증 없는 probe 호출이 불가능하다. 해결 판단 기준: 배포 스크립트가 인증 없이 `GET :8080/readyz`로 기동을 판정하고, 운영 전용 포트에서 `GET :8082/actuator/deployment`로 배포 식별자를 확인할 수 있다. ## 3. Goals - 애플리케이션 포트(8080)에서 인증 없이 readiness 확인 가능. - Management 포트(8082)에서 readiness와 배포 식별 정보 확인 가능. - 배포 식별자는 환경변수로 주입하고, 환경변수가 없어도 로컬/테스트 기동이 가능해야 한다. ## 4. Non-Goals - Kubernetes 관련 의존성·설정 추가. - liveness 기반 자동 재기동 정책, 배포 스크립트 자체 변경. - health details/components 공개, 신규 추상화 계층 도입. ## 5. 권한 - 인증 주체: 없음(배포 스크립트/로드밸런서). - `/readyz`: 애플리케이션 포트에서 인증 없이 허용. - `/actuator/**`: management 포트(8082)에서만 노출. 애플리케이션 포트에서는 노출하지 않는다. - `/readyz` 응답에는 민감 정보나 배포 식별자를 포함하지 않는다. ## 6. 기능 요구사항 | ID | 상태 | 요구사항 | 수용 기준 | Goal 연결 | |---|---|---|---|---| | `DEPLOY-001` | 확정 | `spring-boot-starter-actuator` 의존성을 추가한다(중복 추가 금지). | `build.gradle.kts`에 1회만 존재 | `P1-T1` | | `DEPLOY-002` | 확정 | 애플리케이션 포트 8080, management 포트 8082로 분리한다. | `application.yml`에 `server.port: 8080`, `management.server.port: 8082` | `P1-T1` | | `DEPLOY-003` | 확정 | health probes와 additional path를 활성화해 `/readyz`를 제공한다. | `GET :8080/readyz` → 200 | `P1-T2` | | `DEPLOY-004` | 확정 | management 포트에서 readiness를 제공한다. | `GET :8082/actuator/health/readiness` → 200 | `P1-T2` | | `DEPLOY-005` | 확정 | web exposure는 `health`, `deployment`만 포함하고 health details/components는 공개하지 않는다. | `management.endpoints.web.exposure.include: health,deployment`, `show-details: never`, `show-components: never` | `P1-T1` | | `DEPLOY-006` | 확정 | `DEPLOY_ARTIFACT_VERSION`/`DEPLOY_CONFIG_COMMIT`을 property placeholder로 연결한다. | 환경변수 없으면 `local`, 40자리 zero commit | `P1-T3` | | `DEPLOY-007` | 확정 | `/actuator/deployment`를 custom Actuator endpoint로 구현한다. | REST controller가 아닌 `@Endpoint` 구현체 존재 | `P1-T3` | | `DEPLOY-008` | 확정 | 응답 필드는 정확히 `application_artifact_version`, `config_commit`이다. | snake_case JSON 검증 test 통과 | `P1-T3` | | `DEPLOY-009` | 확정 | 애플리케이션 포트에서 `/actuator/deployment`가 노출되지 않는다. | `GET :8080/actuator/deployment` → 200 아님 | `P1-T4` | | `DEPLOY-010` | 확정 | Security 정책 최소 변경으로 readiness가 401/403/redirect 되지 않는다. | `SecurityConfig`에 `/readyz` permitAll 추가 | `P1-T2` | ## 7. API 계약 ### 7.1 `GET :8080/readyz` - 인증 불필요. 응답 body는 Actuator 기본 health 응답(`{"status":"UP"}`), 세부 정보 비공개. ### 7.2 `GET :8082/actuator/health/readiness` - 응답: `{"status":"UP"}`. ### 7.3 `GET :8082/actuator/deployment` ```json { "application_artifact_version": "local", "config_commit": "0000000000000000000000000000000000000000" } ``` ## 8. 성공 기준 - [x] `GET :8080/readyz`가 200을 반환한다. (`DEPLOY-003`, `DEPLOY-010`) - [x] `GET :8082/actuator/health/readiness`가 200을 반환한다. (`DEPLOY-004`) - [x] `GET :8082/actuator/deployment`가 주입값을 snake_case JSON으로 반환한다. (`DEPLOY-006`~`DEPLOY-008`) - [x] `GET :8080/actuator/deployment`가 200을 반환하지 않는다(401로 차단). (`DEPLOY-009`) - [x] `./gradlew test`, `./gradlew bootJar` 성공. ## 9. Open Questions 없음. ## 10. Decision Log | 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항 | |---|---|---|---|---|---| | 2026-09-14 | `DEC-001` | 확정 | Kubernetes 의존성 없이 Actuator 기본 probe만 사용 | 사용자 요구사항 범위 제한 | `DEPLOY-003`, `DEPLOY-004` | | 2026-09-14 | `DEC-002` | 확정 | 배포 식별자는 별도 파싱 코드 없이 Spring property placeholder로만 연결 | 사용자 요구사항, 단순성 유지 | `DEPLOY-006` | | 2026-09-14 | `DEC-003` | 확정 | `/actuator/deployment`는 `@Endpoint` 기반 custom Actuator endpoint로 구현 | 사용자 요구사항(REST controller 금지) | `DEPLOY-007` |