# OCI Blue/Green 배포 검증 endpoint 구현 계획 | 문서 항목 | 내용 | |---|---| | 상태 | 구현 완료 | | 작성일 | 2026-09-14 | | 요구사항 기준 | `docs/20260914_배포검증readiness및deployment엔드포인트/prd.md` | | 현재 Phase | Phase 1 배포 검증 endpoint | | 현재 활성 Goal | 없음 | ## 목표 배포 스크립트가 애플리케이션 포트에서 readiness를, management 포트에서 readiness와 배포 식별자를 확인할 수 있다. ## 현재 상태 | Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 | |---:|---|---:|---|---| | 1 | 완료 | `4/4` | 없음 | 없음 | ## 범위 ### 포함 - `spring-boot-starter-actuator` 의존성 추가. - `application.yml`(main/test)의 포트·probe·exposure·deployment property 설정. - `DeploymentEndpoint` custom Actuator endpoint 구현. - `SecurityConfig`의 `/readyz` permitAll 최소 변경. - 위 동작을 검증하는 통합 test. ### 제외 - Kubernetes 의존성·설정. - 배포 스크립트(`scripts/`, `appspec.yml`) 변경. - 신규 추상화/라이브러리, 기존 API 변경. ## 기술적 제약 - 기술 스택: Kotlin 1.6.21, Spring Boot 2.7.14, Gradle Kotlin DSL, JUnit 5. - 배포 식별자는 property placeholder만 사용하고 별도 환경변수 파싱·fallback 코드를 만들지 않는다. - 응답 필드명은 snake_case 고정(`application_artifact_version`, `config_commit`). - 검증: 신규 test 우선 실행 후 `./gradlew test` 전체 회귀(공통 보안·설정 변경이므로 전체 회귀 필요). ## Phase 1 배포 검증 endpoint **Phase 결과:** readiness와 deployment endpoint가 지정된 포트 경계에 맞게 동작한다. **선행조건:** 없음. **Phase 완료 조건:** `P1-T1`~`P1-T4` 완료, `./gradlew test`와 `./gradlew bootJar` 성공 기록. ### 구현 항목 #### Task 1.1 Actuator 의존성과 기본 설정 **Goal 실행 `P1-T1`:** Actuator를 추가하고 포트·exposure·deployment property 계약을 설정에 반영한다. - **시작 조건:** PRD `DEPLOY-001`, `DEPLOY-002`, `DEPLOY-005`. - **완료 증거:** 설정 파일 diff와 애플리케이션 컨텍스트 기동 test 통과. - **범위 밖:** endpoint 구현, security 변경. **Files:** - Modify: `build.gradle.kts` - Modify: `src/main/resources/application.yml` - Modify: `src/test/resources/application.yml` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/deployment/DeploymentEndpointIntegrationTest.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/deployment/DeploymentEndpointInjectedValueIntegrationTest.kt` - [x] **RED:** `DeploymentEndpointIntegrationTest`에서 management 포트 readiness/deployment 호출 test를 작성했다. - [x] **RED 확인:** Actuator 부재로 `Could not resolve placeholder 'local.management.port'` 실패를 확인했다. - [x] **GREEN:** `spring-boot-starter-actuator`와 포트·exposure·deployment 설정을 추가했다. - [x] **GREEN 확인:** `./gradlew test --tests 'kr.co.vividnext.sodalive.deployment.*'` 통과. - [x] **REFACTOR:** deprecated `LocalServerPort` import 정리, `./gradlew ktlintCheck` 성공. #### Task 1.2 readiness 접근 허용 **Goal 실행 `P1-T2`:** `/readyz`와 management readiness가 인증 없이 200을 반환한다. - **시작 조건:** `P1-T1` 완료. - **완료 증거:** readiness test 통과. - **범위 밖:** 기타 endpoint의 security 정책 변경. **Files:** - Modify: `src/main/kotlin/kr/co/vividnext/sodalive/configs/SecurityConfig.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/deployment/DeploymentEndpointIntegrationTest.kt` - [x] **RED:** `/readyz` 200 기대 test 작성(`DeploymentEndpointIntegrationTest`). - [x] **RED 확인:** Actuator/보안 미적용 상태 실패 확인. - [x] **GREEN:** `SecurityConfig`에 `/readyz` permitAll과 `EndpointRequest.toAnyEndpoint()` permitAll 추가. - [x] **GREEN 확인:** readiness test 2건 통과. - [x] **REFACTOR:** 추가 변경 없음. #### Task 1.3 deployment custom Actuator endpoint **Goal 실행 `P1-T3`:** `/actuator/deployment`가 snake_case 배포 식별자를 반환한다. - **시작 조건:** `P1-T1` 완료. - **완료 증거:** 기본값·주입값 test 통과. - **범위 밖:** 추가 필드. **Files:** - Create: `src/main/kotlin/kr/co/vividnext/sodalive/deployment/DeploymentEndpoint.kt` - Test: `src/test/kotlin/kr/co/vividnext/sodalive/deployment/DeploymentEndpointIntegrationTest.kt` - [x] **RED:** 기본값(`local`, 40자리 zero)과 주입값 검증 test 작성. - [x] **RED 확인:** endpoint 미구현 실패 확인. - [x] **GREEN:** `@Endpoint(id = "deployment")` + `@ReadOperation` 구현. - [x] **GREEN 확인:** 기본값·주입값 test 통과. - [x] **REFACTOR:** `./gradlew ktlintCheck` 성공. #### Task 1.4 포트 접근 경계 검증 **Goal 실행 `P1-T4`:** 애플리케이션 포트에서 `/actuator/deployment`가 노출되지 않음을 검증한다. - **시작 조건:** `P1-T3` 완료. - **완료 증거:** 애플리케이션 포트 접근 test 통과. - **범위 밖:** 그 외 경로 노출 정책. **Files:** - Test: `src/test/kotlin/kr/co/vividnext/sodalive/deployment/DeploymentEndpointIntegrationTest.kt` - [x] **RED:** 애플리케이션 포트 접근이 200이 아님을 기대하는 test 작성. - [x] **RED 확인:** 초기 404 기대 단정이 `401 UNAUTHORIZED`로 실패함을 확인. - [x] **GREEN:** management 포트 분리로 애플리케이션 포트에서는 endpoint가 매핑되지 않고 401로 차단됨을 확인, 단정을 "200 아님 + 배포 식별자 미포함" 계약으로 정정. - [x] **GREEN 확인:** 해당 test 통과. - [x] **REFACTOR:** `./gradlew test` 전체 회귀 성공. ### Phase Gate `P1-GATE` - [x] `./gradlew test` 성공. - [x] `./gradlew bootJar` 성공 및 실행 가능한 JAR 생성 확인. ## 검증 기록 - 2026-09-14 `./gradlew test --tests 'kr.co.vividnext.sodalive.deployment.*'` → RED 5 failed → GREEN 5 passed. - 2026-09-14 `./gradlew ktlintCheck` → BUILD SUCCESSFUL. - 2026-09-14 `./gradlew test` → BUILD SUCCESSFUL (전체 회귀). - 2026-09-14 `./gradlew bootJar` → `build/libs/sodalive-0.0.1-SNAPSHOT.jar`(141MB), `Main-Class: org.springframework.boot.loader.JarLauncher` 확인. - 참고: 기존 test 실행에는 `JWT_SECRET` 환경변수가 필요하며 이는 이번 변경 이전부터 동일한 전제다. - 참고: 애플리케이션 포트에서 `/actuator/deployment`는 404가 아니라 401로 차단된다. `EndpointRequest` matcher가 management 포트 분리 시 애플리케이션 포트 요청에 매칭되지 않기 때문이며, 노출되지 않는다는 요구는 충족한다.