feat: SprintMission8 - 나은비#185
Conversation
joonfluence
left a comment
There was a problem hiding this comment.
전체 리뷰 요약
Docker 컨테이너화, AWS S3/RDS/ECS 배포, GitHub Actions CI/CD 파이프라인을 구축한 PR입니다. 멀티 스테이지 빌드 적용, MDC 로깅 인터셉터, API 인터페이스 분리, 커서 기반 페이지네이션 등 좋은 패턴들이 잘 적용되어 있습니다. 다만 아래 몇 가지 포인트를 확인해 주세요.
| AWS_S3_PRESIGNED_URL_EXPIRATION=600 | ||
|
|
||
| # DataSource Configuration | ||
| RDS_ENDPOINT=discodeit-db.c1ig0uegaldx.ap-northeast-2.rds.amazonaws.com |
There was a problem hiding this comment.
[P2] discodeit.env 파일이 저장소에 커밋되고 있습니다.
.gitignore에 discodeit.env를 추가했지만 이미 추적된 파일은 자동으로 untrack되지 않습니다. 결과적으로 이 파일이 커밋에 포함되어 RDS 엔드포인트(discodeit-db.c1ig0uegaldx.ap-northeast-2.rds.amazonaws.com)와 S3 버킷명(discodeit-binary-content-storage-neb)이 공개 저장소에 노출됩니다.
자격증명은 비어있지만 인프라 정보 노출은 공격자의 타겟 식별에 활용될 수 있습니다.
권장 조치:
git rm --cached discodeit.env이후 .env.example 파일만 커밋하고 실제 값은 팀 내부에서 별도 공유하세요.
|
|
||
| NEW_TASK_DEF=$(echo $TASK_DEF | jq \ | ||
| --arg IMAGE "${{ vars.ECR_REPOSITORY_URI }}:${{ github.sha }}" \ | ||
| '.taskDefinition | |
There was a problem hiding this comment.
[P3] $TASK_DEF 변수가 따옴표 없이 사용되고 있습니다.
JSON에 공백이나 개행이 포함되면 쉘 word-splitting으로 인해 파싱이 실패할 수 있습니다.
| '.taskDefinition | | |
| NEW_TASK_DEF=$(echo "$TASK_DEF" | jq \ |
| aws ecs update-service \ | ||
| --cluster ${{ vars.ECS_CLUSTER }} \ | ||
| --service ${{ vars.ECS_SERVICE }} \ | ||
| --desired-count 1 No newline at end of file |
There was a problem hiding this comment.
[P3] 서비스 재시작 후 ECS 태스크 안정화를 기다리는 단계가 없습니다.
배포가 실패해도 워크플로우는 성공으로 끝납니다. 아래 단계를 추가하면 실제 배포 완료를 보장할 수 있습니다:
- name: 배포 안정화 대기
run: |
aws ecs wait services-stable \
--cluster ${{ vars.ECS_CLUSTER }} \
--services ${{ vars.ECS_SERVICE }}| JVM_OPTS="" | ||
|
|
||
| # jar만 복사 | ||
| COPY --from=builder /app/build/libs/*.jar app.jar |
There was a problem hiding this comment.
[P3] 와일드카드 *.jar 패턴으로 인한 잠재적 빌드 오류
bootJar 빌드 시 Spring Boot는 실행 가능 fat jar와 plain jar 두 개를 생성할 수 있습니다. 여러 파일이 매칭되면 COPY 명령이 실패합니다.
| COPY --from=builder /app/build/libs/*.jar app.jar | |
| COPY --from=builder /app/build/libs/*-M8.jar app.jar |
또는 build.gradle에서 plain jar 생성을 비활성화하세요:
jar {
enabled = false
}| SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL:-jdbc:postgresql://db:5432/discodeit} | ||
| SPRING_DATASOURCE_USERNAME: ${SPRING_DATASOURCE_USERNAME:-discodeit} | ||
| SPRING_DATASOURCE_PASSWORD: ${SPRING_DATASOURCE_PASSWORD:-discodeit} | ||
| depends_on: |
There was a problem hiding this comment.
[P3] depends_on이 PostgreSQL 준비 완료를 보장하지 않습니다.
컨테이너 시작만 기다릴 뿐, DB가 실제로 쿼리를 받을 준비가 됐는지 확인하지 않아 앱 시작 시 연결 실패가 발생할 수 있습니다.
| depends_on: | |
| depends_on: | |
| db: | |
| condition: service_healthy |
db 서비스에 healthcheck도 추가해야 합니다:
db:
image: postgres:17
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5|
|
||
| env: | ||
| SPRING_PROFILES_ACTIVE: test | ||
| AWS_S3_ACCESS_KEY: ${{ secrets.AWS_S3_ACCESS_KEY }} |
There was a problem hiding this comment.
[P3] CI 테스트가 실제 AWS S3에 의존하고 있습니다.
Secrets가 설정되지 않으면 CI가 실패하고, 불필요한 비용이 발생하며, 네트워크 의존성으로 인해 테스트가 불안정해집니다.
application-test.yaml에 storage.type=local 설정을 추가하여 S3 의존성을 제거하고, CI workflow에서 AWS S3 시크릿을 제거하는 것을 권장합니다:
# application-test.yaml
discodeit:
storage:
type: local| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| @Configuration | ||
| public class DotEnvConfig { |
There was a problem hiding this comment.
[P4] 빈 Configuration 클래스 - 의도가 불명확합니다.
클래스명이 .env 파일 로딩을 암시하지만 실제로 아무 동작도 하지 않습니다. 팀원이나 미래의 자신이 혼란스러울 수 있습니다.
실제 기능이 없다면 삭제하거나, .env 파일 로딩 의도가 있었다면 dotenv-java 등의 라이브러리를 사용한 구현을 추가해 주세요.
요구사항
기본
심화
주요 변경사항
스크린샷
AWS 콘솔 인스턴스 상세 페이지 스크린샷 이미지
푸시된 이미지가 보이는 AWS 콘솔 페이지 스크린샷 이미지
실행 중인 태스크 구성정보가 표시된 AWS 콘솔 페이지 스크린샷 이미지
배포된 EC2 엔드포인트
보안 그룹의 인바운드 규칙을 확인할 수 있는 AWS 콘솔 페이지 스크린샷 이미지
사용자의 권한 정책이 표시된 AWS 콘솔 페이지 스크린샷 이미지
멘토에게