Skip to content

[이종호] Sprint 8#176

Open
Jong-Ho-LEE-75 wants to merge 20 commits into
codeit-bootcamp-spring:이종호from
Jong-Ho-LEE-75:이종호

Hidden character warning

The head ref may contain hidden characters: "\uc774\uc885\ud638"
Open

[이종호] Sprint 8#176
Jong-Ho-LEE-75 wants to merge 20 commits into
codeit-bootcamp-spring:이종호from
Jong-Ho-LEE-75:이종호

Conversation

@Jong-Ho-LEE-75
Copy link
Copy Markdown

@Jong-Ho-LEE-75 Jong-Ho-LEE-75 commented Apr 10, 2026

스프린트 8


기본요구사항

1. 애플리케이션 컨테이너화

Dockerfile 작성

  • Amazon Corretto 17 이미지를 베이스 이미지로 사용
  • 작업 디렉토리 설정 (/app)
  • 프로젝트 파일을 컨테이너로 복사 (불필요한 파일은 .dockerignore로 제외)
  • Gradle Wrapper를 사용하여 애플리케이션 빌드
  • 80 포트 노출
  • 프로젝트 정보를 환경 변수로 설정 (PROJECT_NAME: discodeit, PROJECT_VERSION: 1.2-M8)
  • JVM 옵션을 환경 변수로 설정 (JVM_OPTS: 기본값 빈 문자열)
  • 애플리케이션 실행 명령어 설정 (환경변수로 정의한 프로젝트 정보 활용)

이미지 빌드 및 실행 테스트

  • Docker 이미지 빌드 및 태그(local) 지정
  • prod 프로필로 실행
  • 데이터베이스: 로컬 PostgreSQL 서버 활용
  • http://localhost:8081로 접속 가능하도록 포트 매핑

Docker Compose 구성

  • 애플리케이션과 PostgreSQL 서비스 포함
  • 각 서비스에 필요한 모든 환경 변수 설정 (.env 파일 활용, 형상관리 제외)
  • 애플리케이션 서비스를 로컬 Dockerfile에서 빌드하도록 구성
  • 애플리케이션 볼륨 구성 (컨테이너 재시작 시 BinaryContentStorage 데이터 유지)
  • PostgreSQL 볼륨 구성 (컨테이너 재시작 시 데이터 유지)
  • PostgreSQL 서비스 실행 후 schema.sql 자동 실행되도록 구성
  • 서비스 간 의존성 설정 (depends_on)
  • 필요한 포트 매핑 구성
  • Docker Compose로 서비스 시작 및 테스트 (--build 플래그 사용)

2. BinaryContentStorage 고도화 (AWS S3)

AWS S3 버킷 구성

  • AWS S3 버킷 생성 (discodeit-binary-content-storage-(이니셜) 형식)
  • 퍼블릭 액세스 차단 설정 활성화 (모든 퍼블릭 액세스 차단)
  • 버전 관리 비활성화

AWS S3 접근을 위한 IAM 구성

  • S3 버킷에 접근하기 위한 IAM 사용자(discodeit) 생성
  • AmazonS3FullAccess 권한 할당
  • 생성된 사용자에 엑세스 키 생성
  • 발급받은 키를 .env 파일에 추가

AWS S3 테스트

  • AWS S3 SDK 의존성 추가 (software.amazon.awssdk:s3:2.31.7)
  • S3 API 테스트 클래스 작성 (AWSS3Test)
  • Properties 클래스를 활용해 .env에 정의한 AWS 정보 로드
  • 작업별 테스트 메소드 작성 (업로드, 다운로드, PresignedUrl 생성)

S3BinaryContentStorage 구현

클래스 다이어그램:

fxlj0hb8j-image
  • discodeit.storage.type 값이 s3인 경우에만 Bean 등록
  • S3BinaryContentStorageTest를 함께 작성하면서 구현
  • application.yaml 수정 (BinaryContentStorage 설정 유연화)
  • AWS 관련 정보는 형상관리 금지 → .env 파일에서 임포트
  • Docker Compose에서도 위 설정 주입 가능하도록 수정
  • download 메소드는 PresignedUrl을 활용해 리다이렉트 방식으로 구현

3. AWS를 활용한 배포 (AWS RDS, ECR, ECS)

AWS RDS 구성

  • AWS RDS PostgreSQL 인스턴스 생성 (discodeit-db, 프리티어)
  • 과금 체크리스트 확인 (프리티어, 퍼블릭 액세스 아니오, 모니터링 7일, 백업 비활성화)

SSH 터널링을 통한 RDS 접근 (EC2)

  • EC2 인스턴스 생성 (rds-ssh)
  • 보안 그룹 인바운드 규칙 편집 (유형: SSH, 소스: 내 IP)
  • DataGrip으로 연결 후 DB 초기화 (사용자/데이터베이스/테이블 생성)
  • 구성 완료 후 rds-ssh 인스턴스 삭제

AWS ECR 구성

  • 퍼블릭 레포지토리(discodeit) 생성
  • AWS CLI 설치 및 aws configure 실행
  • discodeit IAM 사용자에 AmazonElasticContainerRegistryPublicFullAccess 권한 부여
  • Docker 클라이언트 인증
  • 멀티플랫폼 이미지 빌드 및 push (태그: latest, 1.2-M8)
  • AWS 콘솔에서 푸시된 이미지 확인

AWS ECS 구성

  • 배포 환경 변수 파일(discodeit.env) 작성 및 S3 업로드
  • ECS 클러스터 생성 (discodeit-cluster, EC2 t2.micro)
  • 태스크 정의 (discodeit-task, EC2, bridge, CPU 0.25 vCPU, 메모리 0.5 GB)
  • 태스크 실행 역할에 S3 관련 권한 추가
  • 서비스 생성 (discodeit-service, 원하는 태스크 1, 상태 검사 유예 기간 30초)
  • EC2 보안 그룹 인바운드 규칙 설정 (유형: HTTP, 소스: Anywhere-IPv4)
  • 태스크 실행 완료 후 EC2 퍼블릭 IP로 접속 테스트

배포 접속 확인:

스크린샷 2026-04-10 오전 11 54 11

심화요구사항

1. 이미지 최적화하기

  • 멀티 스테이지(빌드, 런타임) 빌드를 활용해 이미지 크기 축소 (태그: local-slim)
  • 이미지 레이어 캐시를 고려해 Dockerfile 수정

2. GitHub Actions를 활용한 CI/CD 파이프라인 구축

CI (지속적 통합) 워크플로우

  • .github/workflows/test.yml 파일 생성
  • main 브랜치에 PR이 생성되면 실행되도록 설정
  • 테스트를 실행하는 Job 정의
  • CodeCov를 통해 테스트 커버리지 뱃지를 README에 추가
tb4cb7hos-image

CD (지속적 배포) 워크플로우

  • .github/workflows/deploy.yml 파일 생성
  • release 브랜치에 코드가 푸시되면 실행되도록 설정

AWS 정보 설정

  • GitHub 레포지토리 시크릿 추가 (AWS_ACCESS_KEY, AWS_SECRET_KEY)
  • GitHub 레포지토리 변수 추가 (AWS_REGION, ECR_REPOSITORY_URI, ECS_CLUSTER, ECS_SERVICE, ECS_TASK_DEFINITION)

Docker 이미지 빌드 및 푸시

  • Docker 이미지를 빌드하고 푸시하는 Job 정의
  • AWS CLI 설정 (Public ECR용 리전 us-east-1)
  • ECR 로그인 Step 추가
  • Docker 이미지 빌드 및 푸시 Step 추가 (멀티플랫폼 제외, x86_64)
  • 이미지 태그: latest + GitHub 커밋 해시

ECS 서비스 업데이트

  • ECS 서비스를 업데이트하는 Job 정의
  • AWS CLI 설정 (AWS_REGION)
  • 태스크 정의 업데이트 (기존 태스크 정의 기반으로 새 이미지 사용)
  • 기존 서비스 중단 (aws ecs update-service --desired-count 0)
  • 새로 등록한 태스크 정의를 사용하도록 ECS 서비스 업데이트
  • AWS 콘솔에서 새로 등록된 태스크 정의로 배포 확인

기능별 커밋 내역

커밋 설명
a5118aeb 설정 파일 환경변수화 및 S3 스토리지 설정 추가
03a1ea53 애플리케이션 컨테이너화 (Dockerfile, Docker Compose)
6fed20dc S3 BinaryContentStorage 구현 및 테스트 추가
699b071b ECS 메모리 최적화를 위한 prod 설정 추가
0b6792ab CI 워크플로우 (test.yml) 추가
440aacc9 README.md 생성 및 CodeCov 커버리지 뱃지 추가
4491a464 CD 워크플로우 (deploy.yml) 추가
ec809932 Dockerfile 멀티 스테이지 최적화 및 레이어 캐시 개선
e7ba78ad 스프린트8 심화요구사항 적용
f8ef3b91 PR 리뷰용 스크린샷 교체 (요구사항 기준 재촬영)
70726450 Docker 빌드 오류 수정 및 환경 설정 파일 정리
451ae870 CI/CD 파이프라인 안정성 개선 및 S3 테스트 환경변수 지원

CI/CD 파이프라인 개선 및 검증 (2026-04-10)

개선 내용

  • Dockerfile
    • 빌드 오류 유발 명령어 제거, clean bootJar -x test로 변경해 테스트 빌드 제외
    • ENTRYPOINT에 -Dserver.port=80 추가해 prod 프로파일과 일관성 확보
  • .env.example: 민감값을 플레이스홀더로 치환해 로컬 개발 가이드 복원
  • S3 테스트 (AWSS3Test, S3BinaryContentStorageTest)
    • loadConfig() 헬퍼 추가: .env 존재 시 파일, 없으면 환경변수에서 로드
    • assumeTrue로 자격증명 미설정 시 자동 스킵 → 로컬/CI 양쪽 대응
  • .github/workflows/test.yml: S3 시크릿 주입 (AWS_S3_ACCESS_KEY, AWS_S3_SECRET_KEY, AWS_S3_REGION, AWS_S3_BUCKET)
  • .github/workflows/deploy.yml
    • 공식 AWS 액션 도입: aws-actions/amazon-ecs-render-task-definition@v1, aws-actions/amazon-ecs-deploy-task-definition@v1
    • jq 기반 수동 태스크 정의 조작을 공식 액션으로 대체해 안정성 향상
    • 프리티어 리소스 절약을 위한 서비스 중단/재개 흐름 유지
  • .gitignore: .continue/ 추가

검증 결과

  • CI (test.yml): 159 테스트 통과 (S3 통합 테스트 7건 포함, 실제 버킷 연동 성공)
  • CD build-and-push: Public ECR에 이미지 푸시 성공 (태그: latest, ${{ github.sha }})
  • CD deploy: ECS 서비스(discodeit-service) 새 태스크 정의 revision 배포 성공

리뷰를 위한 첨부 자료

.env 파일 (엑세스 키, 시크릿 키 제외)

# AWS
AWS_S3_ACCESS_KEY=(보안상 제외)
AWS_S3_SECRET_KEY=(보안상 제외)
AWS_S3_REGION=ap-northeast-2
AWS_S3_BUCKET=discodeit-storage

RDS

  • AWS 콘솔 인스턴스 상세 페이지
RDS 인스턴스 상세
  • SSH 터널링을 통해 연결한 DataGrip (테이블 목록 포함)
SSH 터널링 + 테이블 목록

ECR

  • 푸시된 이미지가 보이는 AWS 콘솔 페이지
ECR 이미지

ECS

  • 실행 중인 태스크 구성정보가 표시된 AWS 콘솔 페이지
ECS 태스크 상세

VPC

  • 보안 그룹의 인바운드 규칙 (ECS용 + RDS SSH용)
VPC 보안그룹 - ECS VPC 보안그룹 - RDS SSH

IAM

  • 사용자의 권한 정책
IAM 사용자 권한

- 변경한 내용:
  * 기본요구사항 3가지에 대한 상세 코드리뷰 문서 작성
  * 초보자 대상 코드 설명 (일처리 순서, 줄별 해설)
  * 요구사항 체크리스트 100% 대조 검증 결과 포함

- 변경 이유:
  * 구현 코드에 대한 이해도 향상 및 학습 자료 제공
  * 기본요구사항과 코드의 일치 여부 문서화

- 주요 파일:
  * docs/sprint8-기본요구사항-코드리뷰.md
- 변경한 내용:
  * 런타임 스테이지를 amazoncorretto:17-alpine으로 변경 (경량 이미지)
  * 의존성 파일 먼저 복사 후 빌드하여 레이어 캐시 최적화
  * 태그: local-slim (878MB → 594MB, 약 32% 감소)

- 변경 이유:
  * 스프린트 8 심화요구사항 - 이미지 최적화

- 주요 파일:
  * Dockerfile
- 변경한 내용:
  * .github/workflows/test.yml 생성
  * main 브랜치 PR 시 자동 테스트 실행
  * JDK 17 (Corretto) + Gradle 캐시 설정
  * JaCoCo 커버리지 리포트를 CodeCov에 업로드

- 변경 이유:
  * 스프린트 8 심화요구사항 - CI 파이프라인 구축

- 주요 파일:
  * .github/workflows/test.yml
- 변경한 내용:
  * 루트 README.md 생성
  * CodeCov 커버리지 뱃지 추가
  * 프로젝트 빌드/실행 가이드 포함

- 변경 이유:
  * 스프린트 8 심화요구사항 - CodeCov 뱃지 추가

- 주요 파일:
  * README.md
- 변경한 내용:
  * .github/workflows/deploy.yml 생성
  * release 브랜치 푸시 시 자동 배포 실행
  * build-and-push Job: Public ECR 로그인, Docker 빌드/푸시 (latest + 커밋해시 태그)
  * deploy Job: 태스크 정의 업데이트, 기존 서비스 중단, 새 태스크로 서비스 업데이트

- 변경 이유:
  * 스프린트 8 심화요구사항 - CD 파이프라인 구축

- 주요 파일:
  * .github/workflows/deploy.yml
- 변경한 내용:
  * docs/sprint8-심화요구사항.md - 심화요구사항 전체 정리
  * docs/sprint8-심화-설계서.md - 설계 및 구현 계획

- 변경 이유:
  * 스프린트 8 심화요구사항 문서화

- 주요 파일:
  * docs/sprint8-심화요구사항.md
  * docs/sprint8-심화-설계서.md
- 변경한 내용:
  * @activeprofiles("test") 추가하여 H2 인메모리 DB 사용

- 변경 이유:
  * CI 환경(GitHub Actions)에서 PostgreSQL 미설치로 contextLoads 실패

- 주요 파일:
  * src/test/java/.../DiscodeitApplicationTests.java
- 변경한 내용:
  * badge URL에서 /branch/main 경로 제거

- 변경 이유:
  * main 브랜치에 커버리지 미업로드 상태에서 unknown 표시되는 문제 해결

- 주요 파일:
  * README.md
- 변경한 내용:
  * codecov.yml 생성, 기본 브랜치를 이종호8-로 설정

- 변경 이유:
  * main 브랜치에 커버리지 미업로드 상태에서 뱃지가 unknown 표시되는 문제 해결

- 주요 파일:
  * codecov.yml
- 변경한 내용:
  * AWS 콘솔 스크린샷 6장 추가 (RDS, ECR, ECS, VPC, IAM)
  * .env.example에 AWS RDS 접속 정보 추가 (키 제외)

- 변경 이유:
  * PR 리뷰를 위한 인프라 구성 증빙 자료

- 주요 파일:
  * screenshots/*.png
  * .env.example
- 변경한 내용:
  * IntelliJ SSH/SSL 탭 설정 스크린샷 추가
  * SSH 구성 상세 (호스트, 키 페어 인증) 스크린샷 추가
  * SSH 터널링 연결 테스트 성공 스크린샷 추가

- 변경 이유:
  * 기본요구사항 - SSH 터널링을 통한 RDS 접근 증빙

- 주요 파일:
  * screenshots/ssh-tunnel-tab.png
  * screenshots/ssh-tunnel-config.png
  * screenshots/ssh-tunnel-test-success.png
- 변경한 내용:
  * 전체 화면 스크린샷에서 브라우저 콘텐츠 영역만 크롭
  * macOS 메뉴바, 브라우저 탭바, AWS 네비게이션 바, 하단 빈 공간 제거
  * IAM 사용자 스크린샷을 권한 정책 페이지로 교체

- 변경 이유:
  * PR 첨부용 스크린샷의 가독성 향상

- 주요 파일:
  * screenshots/rds-instance.png
  * screenshots/vpc-sg-rds.png
  * screenshots/vpc-sg-ecs.png
  * screenshots/ecr-images.png
  * screenshots/ecs-task.png
  * screenshots/iam-user.png
- 변경한 내용:
  * HELP.md (Spring Initializr 기본 파일) 삭제
  * AI 분석 비교 문서 5개 삭제 (code-analysis-*, sonnet-vs-opus, pagination-comparison)
  * Dockerfile에 멀티 스테이지 빌드, 레이어 캐시 설명 주석 추가
  * docker-compose.yml에 서비스별 역할, 환경변수 설명 주석 추가

- 변경 이유:
  * PR에 불필요한 파일 제거로 코드 정리
  * 초보자가 Docker 설정을 이해할 수 있도록 주석 보강

- 주요 파일:
  * Dockerfile
  * docker-compose.yml
- 변경한 내용:
  * 기존 스크린샷 9장 삭제, 새 스크린샷 7장으로 교체
  * RDS 인스턴스 상세 + SSH 터널링 테이블 목록 포함
  * ECS 태스크 상세 구성정보 (Public IP 포함)
  * VPC 보안그룹 인바운드 규칙 (ECS용, RDS SSH용)
  * IAM 사용자 권한 정책

- 변경 이유:
  * 스프린트8 PR 리뷰 요구사항에 맞게 스크린샷 재촬영
  * DataGrip 테이블 목록 누락 보완

- 주요 파일:
  * screenshots/1-1.RDS-Instances-Details.png
  * screenshots/1-2.RDS-SSH-tunneling.png
  * screenshots/2.ECR-Image.png
  * screenshots/3.ECS-Tasks-Details.png
  * screenshots/4.VPC-Security-Inbound1.png
  * screenshots/4.VPC-Security-Inbound2.png
  * screenshots/5.IAM-User.png
@Jong-Ho-LEE-75 Jong-Ho-LEE-75 added 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. labels Apr 10, 2026
- 변경한 내용:
  * .env.example 파일 삭제

- 변경 이유:
  * 요구사항에 없는 파일이므로 제거
  * .env 파일은 .gitignore로 형상관리 제외, PR 본문에 별도 첨부

- 주요 파일:
  * .env.example (삭제)
@Jong-Ho-LEE-75 Jong-Ho-LEE-75 changed the title [스프린트 8] 컨테이너화, AWS S3/RDS/ECR/ECS 배포, CI/CD 파이프라인 [이종호] Sprint8 Apr 10, 2026
@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

Jong-Ho-LEE-75 commented Apr 10, 2026

코드 리뷰 반영 - Docker 빌드 오류 수정 및 환경 설정 정리

커밋: 67e4f2ac

변경한 내용

  • Dockerfile 1행 잘못 포함된 텍스트 제거 — Docker 빌드 실패 원인 해결
  • 빌드 태스크를 buildbootJar로 변경 — 실행 JAR만 생성하여 효율성 향상
  • ENTRYPOINT에 -Dserver.port=80 명시 — ECS 배포 시 포트 설정 명확화
  • .continue/mcpServers/ 불필요한 IDE 설정 파일 삭제
  • .gitignore.continue/ 추가 — 재발 방지
  • .env.example 복원 (민감 정보 제거한 템플릿 형태)

변경 이유

  • Dockerfile 1행에 잘못 포함된 텍스트로 Docker 빌드가 실패할 수 있는 상태였음
  • bootJarbuild보다 효율적 (실행 가능 JAR만 생성, 불필요한 아티팩트 생략)
  • -Dserver.port=80을 명시하여 ECS 배포 환경에서 포트 설정 안정성 확보
  • IDE 설정 파일(.continue/)이 PR에 포함되어 있어 불필요한 노이즈 발생
  • .env.example이 없으면 새 개발자가 필요 환경변수를 파악하기 어려움 (업계 표준 관행)

주요 파일

  • Dockerfile
  • .env.example
  • .gitignore
  • .continue/mcpServers/ (삭제)

- 변경한 내용:
  * Dockerfile 1행 잘못 포함된 텍스트 제거
  * 빌드 태스크를 build에서 bootJar로 변경 (실행 JAR만 생성)
  * ENTRYPOINT에 -Dserver.port=80 명시로 포트 설정 명확화
  * .continue/mcpServers/ 불필요한 IDE 설정 파일 삭제
  * .gitignore에 .continue/ 추가 (재발 방지)
  * .env.example 복원 (민감 정보 제거한 템플릿)

- 변경 이유:
  * Dockerfile 1행에 잘못 포함된 텍스트로 Docker 빌드 실패 가능성 존재
  * bootJar 태스크가 build보다 효율적 (실행 가능 JAR만 생성)
  * -Dserver.port=80 명시로 ECS 배포 시 포트 설정 안정성 확보
  * IDE 설정 파일이 PR에 포함되어 불필요한 노이즈 발생
  * .env.example이 없으면 새 개발자가 필요 환경변수를 파악 불가

- 주요 파일:
  * Dockerfile
  * .env.example
  * .gitignore
  * .continue/mcpServers/ (삭제)
- 변경한 내용:
  * S3 테스트: .env 파일 없을 때 환경변수에서 자격증명 로드 (loadConfig 메서드)
  * test.yml: S3 자격증명을 GitHub Secrets로 주입 (CI에서 S3 테스트 실행 가능)
  * deploy.yml: 수동 jq 조작을 공식 ECS 액션으로 대체
    - aws-actions/amazon-ecs-render-task-definition@v1 (태스크 정의 렌더링)
    - aws-actions/amazon-ecs-deploy-task-definition@v1 (배포)
  * deploy.yml: 서비스 중단 후 services-stable 대기 추가 (프리티어 안정성)

- 변경 이유:
  * 기존 S3 테스트는 .env 파일에만 의존하여 CI 환경에서 실행 불가능
  * 환경변수 fallback으로 로컬(.env)과 CI(Secrets) 양쪽 지원
  * 공식 AWS 액션은 유지보수성이 높고 태스크 정의 필드 삭제 등 엣지 케이스 처리
  * 서비스 scale-down 후 stable 대기로 EC2 프리티어 슬롯 충돌 방지

- 주요 파일:
  * .github/workflows/test.yml
  * .github/workflows/deploy.yml
  * src/test/java/com/sprint/mission/discodeit/storage/s3/AWSS3Test.java
  * src/test/java/com/sprint/mission/discodeit/storage/s3/S3BinaryContentStorageTest.java
@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

CI/CD 파이프라인 안정성 개선

커밋: 451ae870

다른 PR 리뷰에서 확인된 개선점을 반영했습니다.

1. CI에서 S3 테스트 실행 가능하도록 개선

문제: 기존 S3 테스트(AWSS3Test, S3BinaryContentStorageTest)는 .env 파일에만 의존하여 CI 환경에서는 항상 스킵되었습니다.

개선: .env 파일이 없으면 환경변수에서 자격증명을 로드하는 loadConfig() 메서드를 추가했습니다.

private Properties loadConfig() throws IOException {
  Properties props = new Properties();
  if (Files.exists(Paths.get(".env"))) {
    try (FileInputStream fis = new FileInputStream(".env")) {
      props.load(fis);
    }
  } else {
    // CI 환경: 환경변수에서 로드
    for (String key : new String[]{"AWS_S3_ACCESS_KEY", "AWS_S3_SECRET_KEY", ...}) {
      String value = System.getenv(key);
      if (value != null) props.setProperty(key, value);
    }
  }
  return props;
}
  • 로컬: .env 파일 사용 (기존 동작 유지)
  • CI: GitHub Secrets 주입 환경변수 사용
  • 자격증명 없음: assumeTrue로 안전하게 스킵

test.yml에 S3 관련 환경변수도 추가했습니다:

env:
  AWS_S3_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
  AWS_S3_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
  AWS_S3_REGION: ${{ vars.AWS_REGION }}
  AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}

AWS_S3_BUCKET Secret을 추가해야 CI에서 실제 S3 테스트가 실행됩니다. 없으면 자동 스킵됩니다.

2. 공식 AWS ECS 액션 사용으로 deploy.yml 개선

기존: jq로 태스크 정의 JSON을 수동 조작하여 register + update-service 호출
개선: AWS 공식 액션으로 대체 → 유지보수성/안정성 향상

- name: 새 이미지로 태스크 정의 렌더링
  id: render-task-def
  uses: aws-actions/amazon-ecs-render-task-definition@v1
  with:
    task-definition: task-definition.json
    container-name: discodeit-app
    image: ${{ vars.ECR_REPOSITORY_URI }}:${{ github.sha }}

- name: ECS 서비스에 새 태스크 정의 배포
  uses: aws-actions/amazon-ecs-deploy-task-definition@v1
  with:
    task-definition: ${{ steps.render-task-def.outputs.task-definition }}
    cluster: ${{ vars.ECS_CLUSTER }}
    service: ${{ vars.ECS_SERVICE }}

장점:

  • del()로 수동 제거하던 필드(taskDefinitionArn, revision, status 등)를 액션이 자동 처리
  • 태스크 정의 포맷 변경에도 유연하게 대응
  • 커뮤니티 유지보수 받음

3. 서비스 중단 후 stable 대기 추가

프리티어 EC2(t2.micro) 1개 슬롯 환경에서 기존 태스크가 완전히 내려간 후 새 태스크가 뜨도록 aws ecs wait services-stable을 추가했습니다.

- name: 기존 서비스 중단 (프리티어 리소스 절약)
  run: |
    aws ecs update-service --desired-count 0 ...
    aws ecs wait services-stable --cluster ... --services ...

검증

  • 전체 테스트 통과 (./gradlew clean test)
  • .env 제거 후에도 S3 테스트가 정상 스킵됨을 확인
  • 기존 S3 테스트는 .env에서 정상 로드 (하위 호환)

변경 파일

  • .github/workflows/test.yml
  • .github/workflows/deploy.yml
  • src/test/java/com/sprint/mission/discodeit/storage/s3/AWSS3Test.java
  • src/test/java/com/sprint/mission/discodeit/storage/s3/S3BinaryContentStorageTest.java

@Jong-Ho-LEE-75 Jong-Ho-LEE-75 changed the title [이종호] Sprint8 [이종호] Sprint 8 Apr 10, 2026
@codeityebon codeityebon marked this pull request as draft April 10, 2026 06:59
@codeityebon codeityebon marked this pull request as ready for review April 10, 2026 07:15
- name: AWS CLI 설정 (Public ECR용 - us-east-1)
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현업에서는 보안적인 관점에서 ACCESS_KEY보다는 Role 방식으로 인증하오니 참고 부탁드립니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피드백 감사합니다.
현재 스프린트8 기본요구사항에서 IAM 사용자 생성, 엑세스 키 생성 -> .env 파일에 추가 흐름이 명시되어 있어서 요구사항에 따른 내용입니다.

말씀해주신 Role 방식은 좀 더 공부하고 확인해서 다른 프로젝트에서 사용 할 수 있도록 준비하겠습니다.

run: |
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws

- name: Docker 이미지 빌드 및 푸시
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

미션 8 요구사항에서는 docker-compose와 Dockerfile을 활용해야하기 때문에 CI/CD 과정에서 도커 이미지를 생성하신 것 같아요.
해당 방법 외에 JIB 플러그인을 활용해서 CI/CD 과정에서 도커 설치없이 이미지를 생성할 수 있으니 참고부탁드려요.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JIB는 처음 들어봐서 찾아봤는데 Docker 데몬 없이 이미지를 빌드/푸시할 수 있다는 점이 확실히 장점이네요.
이번 스프린트미션 8 기본요구사항이 Dockerfile 작성 + docker-compose 구성을 명시하고 있어서 해당 방식으로 구현했습니다.

JIB 공부를 해서 빌드 파이프라인에서 Docker 설치 자체를 덜어낼 수 있는 방법을 현업에서 사용해 볼 수 있도록 노력하겠습니다.

- name: 테스트 실행
run: ./gradlew clean test
env:
# S3 테스트용 자격증명 (GitHub Secrets). 값이 비어있으면 S3 테스트는 자동 스킵됨.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍👍

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다.

Comment thread docker-compose.yml
build: . # 로컬 Dockerfile로 이미지 빌드
ports:
- "${APP_PORT:-8080}:80"
- "${APP_PORT:-8080}:80" # 호스트:컨테이너 포트 매핑
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dockerfile 에 정의된 Entrypoint에서도 80 Port 띄우던데 혹시 애플리케이션을 실행하는 Port를 80으로 선정하신 이유는 요구사항 때문이군요.

80 Port는 잘 알려진 즉 HTTP 프로토콜이 사용하는 Port라 사용하지 않고 Java Application을 구동할 때 보통 8080 Port를 사용하며 호스트와 컨테이너 간 포트 포워딩을 통해 진행합니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공감합니다.
저도 처음엔 8080으로 하고 싶었는데,
이번 미션 기본요구사항의 Dockerfile 체크리스트에 "80 포트 노출"이 명시되어있고 ECS 태스크 정의에서도 "호스트 80, 컨테이너 80"을 요구하고 있어서 컨테이너 포트를 80으로 맞췄습니다.

다만 로컬 개발 환경의 docker-compose에서는 말씀해주신 관례대로 ${APP_PORT:-8080}:80으로 호스트 측은 8080으로 포워딩해두었습니다.

이 부분을 리뷰 코멘트에 같이 기재했어야 했는데 설명이 부족했던 것 같습니다.

Comment thread .gitignore
@@ -35,6 +35,9 @@ bin/
### VS Code ###
.vscode/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 못찾는건지 모르겠지만 gitignore 파일에 .env 파일 정의가 없네요.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인 부탁드립니다.
.gitignore 54~56번째 줄에 다음과 같이 .env와 discodeit.env를 등록해두었습니다.

이미지 2026  4  22  오전 9 15

혹시 제가 놓친 다른 환경변수 파일이 있다면 파일명 알려주시면 추가하겠습니다.

@eedys1234
Copy link
Copy Markdown
Collaborator

IAM에 Role을 부여할 때 최소 권한의 원칙(Principle of Least Privilege, PoLP)를 기준으로 부여한다고 생각해주시면 좋을 것 같습니다.!

@eedys1234
Copy link
Copy Markdown
Collaborator

PR 변경점에는

discodeit.storage.type 값이 s3인 경우에만 Bean 등록
S3BinaryContentStorageTest를 함께 작성하면서 구현
application.yaml 수정 (BinaryContentStorage 설정 유연화)
AWS 관련 정보는 형상관리 금지 → .env 파일에서 임포트
Docker Compose에서도 위 설정 주입 가능하도록 수정
download 메소드는 PresignedUrl을 활용해 리다이렉트 방식으로 구현

이 파일들이 존재하지 않네요ㅠㅠ

@eedys1234
Copy link
Copy Markdown
Collaborator

S3 Bucket 이미지도 있으면 좋을 것 같습니다!

@eedys1234
Copy link
Copy Markdown
Collaborator

RDS를 Private Subnet 위치에 존재하게 하기 때문에 Bastion Server(rds-ssh)를 통해 SSH 터널링을 활용하여 로컬에서 접근하니 참고 부탁드려요.

@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

Jong-Ho-LEE-75 commented Apr 22, 2026

IAM에 Role을 부여할 때 최소 권한의 원칙(Principle of Least Privilege, PoLP)를 기준으로 부여한다고 생각해주시면 좋을 것 같습니다.!

최소 권한의 원칙, 말씀해주셔서 감사합니다.
현재는 요구사항이 AmazonS3FullAccess 부여를 명시하고 있어 그대로 따랐습니다.

실제 S3 연동에서 사용하는 API는 PutObject, GetObject, DeleteObject, ListBucket 정도로 한정되므로,
운영 관점에서는 해당 액션만 허용하는 커스텀 정책으로 축소하는 것이 맞다고 생각합니다.

다음부터는 개인적으로 정책 파일을 만들어서 적용해보겠습니다.

@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

Jong-Ho-LEE-75 commented Apr 22, 2026

PR 변경점에는

discodeit.storage.type 값이 s3인 경우에만 Bean 등록
S3BinaryContentStorageTest를 함께 작성하면서 구현
application.yaml 수정 (BinaryContentStorage 설정 유연화)
AWS 관련 정보는 형상관리 금지 → .env 파일에서 임포트
Docker Compose에서도 위 설정 주입 가능하도록 수정
download 메소드는 PresignedUrl을 활용해 리다이렉트 방식으로 구현

이 파일들이 존재하지 않네요ㅠㅠ

확인해주셔서 감사합니다. 말씀하신 항목들은 모두 구현되어 있는데,
이전 스프린트 브랜치에서 먼저 머지된 상태라 이번 PR의 diff에는 보이지 않는 것 같습니다.
해당 파일 경로 공유드립니다.

  • 조건부 빈 등록: src/main/java/com/sprint/mission/discodeit/storage/s3/S3BinaryContentStorage.java:27
    @ConditionalOnProperty(name = "discodeit.storage.type", havingValue = "s3")

  • PresignedUrl 리다이렉트 다운로드: 동일 파일 download() 메서드 (81~86번 줄)
    return ResponseEntity.status(HttpStatus.FOUND)
    .location(URI.create(presignedUrl))
    .build();

  • AWS S3 테스트:

    • src/test/java/com/sprint/mission/discodeit/storage/s3/AWSS3Test.java (업로드 / 다운로드 / PresignedUrl)
    • src/test/java/com/sprint/mission/discodeit/storage/s3/S3BinaryContentStorageTest.java
  • application.yaml 스토리지 유연화: src/main/resources/application.yaml:23~33
    discodeit:
    storage:
    type: ${STORAGE_TYPE:local}
    local: ...
    s3:
    access-key: ${AWS_S3_ACCESS_KEY:}
    secret-key: ${AWS_S3_SECRET_KEY:}
    region: ${AWS_S3_REGION:}
    bucket: ${AWS_S3_BUCKET:}
    presigned-url-expiration: ${AWS_S3_PRESIGNED_URL_EXPIRATION:600}

  • AWS 정보 형상관리 금지: .gitignore:55~56에서 .env, discodeit.env 제외

  • Docker Compose 환경 주입: docker-compose.yml:18~19에서 env_file: - .env 로 .env의 STORAGE_TYPE, AWS_S3_*를 app 컨테이너에 자동 주입 (environment: 블록에는 Spring 프로파일 / 데이터소스 4개만 명시)

확인이 어려우셨던 점 반영해서 다음 PR에서는 base 브랜치 포함 변경 범위를 본문에 별도로 정리해 올리겠습니다.

@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

Jong-Ho-LEE-75 commented Apr 22, 2026

S3 Bucket 이미지도 있으면 좋을 것 같습니다!

일단, 현재 과금 때문에 S3 버킷을 이미 삭제한 상태라서 지금 바로 캡처가 어렵습니다.

스프린트8 미션 요구사항에서 리뷰를 위해 PR에 포함해야 할 정보에는
S3버켓 스크린샷에 대한 언급이 없어서 따로 S3 버켓 정보를 캡쳐하지 못하였습니다.

스크린샷 2026-04-22 오전 9 41 07

다음번 미션때는 꼭 챙기도록하겠습니다.

@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

RDS를 Private Subnet 위치에 존재하게 하기 때문에 Bastion Server(rds-ssh)를 통해 SSH 터널링을 활용하여 로컬에서 접근하니 참고 부탁드려요.

다행이네요
저도 같은 구성으로 진행했습니다.

RDS는 퍼블릭 액세스를 "아니오"로 두고 프라이빗 서브넷에 위치 시켰고, 접근이 필요할 땐
rds-ssh라는 t2.micro EC2 Bastion을 띄워서 .pem 키페어 기반 SSH 터널링으로 DataGrip에서 접속했습니다.

초기화 스크립트 실행 후에는 과금을 피하려고 해당 EC2를 삭제했습니다.

@Jong-Ho-LEE-75
Copy link
Copy Markdown
Author

피드백 해주신 내용 감사합니다.
앞으로 좀 더 공부해서 실무에서도 잘 사용 할 수 있도록 하겠습니다.

답변 드린 것 처럼 코드를 따로 수정할 내용이 없는 것 같아서
머지 부탁드립니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants