Skip to content

[그리디] 이창희 Spring Core (배포) 7,8,9 단계 제출합니다 #182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 22, 2025

Conversation

chxghee
Copy link

@chxghee chxghee commented Jul 16, 2025

안녕하세요 승현님!
두 번쨰로 뵙는군요 ㅎㅎ

어느덧 마지막 스터디 미션이네요 이번 미션도 잘 부탁드립니다!

이번 미션은

  1. Jwt 를 처리하는 코드를 roomescape 패키지 외부의 모듈로 분리하는 작업과
  2. 기존 data.sql로 데이터를 초기화 했던 것을 DataLoader를 통해 테스트 환경과, 프로덕션 환경을 분리해 초기화 하는

비교적 간단한 미션이였습니다!

1번을 구현하기 위해 jwt 패키지를 만들어

  • Jwt 토큰을 발급, 파싱했던 JwtTokenProvider
  • Jwt관련 환경변수를 담은 JwtProperties 클래스 분리하고,
  • 해당 객체들을 JwtConfig를 통해 빈으로 등록했습니다

Application 클래스에서 @Import(JwtConfig.class) 통해 JwtConfig의 설정을 등록해 주었습니다

2번을 구현하기 위해서는

  • Production용과 DataLoader
  • Test용 TestDataLoader를 따로 만들어 DB 초기화를 진행 했고,
  • test 에 관한 설정은 test 패키지 하위 application.yml 파일 생성하여 프로덕션 환경과 분리하도록 했습니다!

제 코드에서 미흡한 점이나 개선할 점이 있다면 편하게 말씀해 주세요~


P.S. 이번 미션이 간단한 편이라 Files Changed가 많지 않고, 리뷰를 남기실 부분도 많지 않을 수 있겠다는 생각이 드네요

혹시 그래서 난감 하셨다면(?), 스프링이나 배포와 관련해서 키워드나 질문을 주시면 제가 공부해 보고 그에 대한 코멘트를 남겨보겠습니다! 😄

감사합니다!

Copy link

@BackFoxx BackFoxx left a comment

Choose a reason for hiding this comment

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

안녕하세요 창희님! 반영해주신 코드 잘 보았습니다. 애플리케이션 레벨에서 크게 변경점이 없어 리뷰할 거리가 많지 않았는데요!
혹시 9단계 진행하시면서 배포 스크립트 파일도 작성해 주셨을까요? 배포 스크립트 파일도 git에서 형상관리가 되게 하면 관리하기가 쉽습니다 :)
스크립트 파일 올려주시면 해당 내용 기반으로 추가 질문 올릴 수 있을 것 같아요!

properties:
hibernate:
format_sql: true
ddl-auto: create

Choose a reason for hiding this comment

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

ddl-auto 값을 운영 쪽은 create로, 테스트는 create-drop으로 잡으셨는데
create를 쓰더라도 애플리케이션 시작할 때 기존 테이블이 있으면 drop돼요!
의도하신 로직이실까요?

Copy link
Author

Choose a reason for hiding this comment

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

그렇게 큰 뜻은 없고,

테스트가 끝나면 테이블을 정리 하는 것이
흐름이 더 깔끔한것 같아서 create-drop을 썼어요! 😅
(인 메모리 DB를 쓰고 있으니까 create을 써도 크게 차이가 없을 것 같긴 하네요)

Choose a reason for hiding this comment

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

ㅎㅎ이해했습니다!

datasource:
url: jdbc:h2:mem:test_db

roomescape:

Choose a reason for hiding this comment

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

같은 값이 prod의 application.yml과 중복 선언이 되어있군요
없어도 동작하지 않았나요? :D

Copy link
Author

Choose a reason for hiding this comment

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

같은 값이 prod의 application.yml과 중복 선언이 되어있군요

제가 질문을 잘 이해하지 못한것 같은데,
말씀해 주신 같은 값이 다음의 jwt 관련 값인가요?

roomescape:
  auth:
    jwt:
      secret: Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=
      expiration: 1800000

Test 패키지의 application.yml에 이 설정이 빠지게 되면 작동이 안 되더라구요
그래서 포트 설정과 DB 설정을 제외한 mian 패키지의 설정 내용을 똑같이 넣어 주었어요!



현재 미션에서 test 와 prod 환경을 분리해 보았는데요, 생각난 방법이 두 가지가 있었어요

첫 번째 방법

  1. application.yml 에 prod와 test 환경의 공통 설정을 모아 놓기 + prod를 기본 active로 설정
  2. application-prod.yml, application-test.yml를 각각 만들어 서로 다른 설정들을 작성하기 (DB 설정 등...)

근데 이렇게 하면 모든 test 클래스 들에 @ActiveProfiles("test")을 붙여줘야 하는 것이 번거롭게 느껴져서 두 번쨰 방식을 사용하여 미션을 제출했어요


두 번째 방법

  1. test/resourses 패키지에 application.yml을 만들어 main 패키지의 설정과 아예 분리하기

드는 생각이 prod 와 test 의 공통된 설정을 바꾸게 된다면,
두 번째 방법은 main패키지의 application.yml과 test 패키지의 application.yml도 같이 바꾸어 줘야 하는 불편함이 있는것 같네요🤔

이렇게 환경 분리를 해본 경험이 별로 없어 어떤 방식으로 환경을 분리해야 할지 감이 잘 안 잡히네요

승현님은 테스트 환경과, 프로덕션 환경, 로컬 개발 환경을 분리할때 어떤 방식으로 분리를 하시나요?
가능하시다면 어떠한 장점이 있어서 해당 방식을 사용하시는지도 궁금합니다!!

Choose a reason for hiding this comment

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

스프링 부트는 yml을 사용해서 더 편한 방법으로 설정할 수 있게 도와주니 관련 설정들을 더 검색해보셔도 좋을 것 같습니다.
예를 들어 창희님의 main/application.yml은

server:
  port: 8080

spring:
  profiles:
    active: prod

  h2:
    console:
      enabled: true
      path: /h2-console

  datasource:
    url: jdbc:h2:mem:database

  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    ddl-auto: create

roomescape:
  auth:
    jwt:
      secret: Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=
      expiration: 1800000

이렇게 되어있어 prod라는 프로필을 사용하는 환경에서만 위 환경변수들이 설정되는데,
prod와 test에서 공통으로 사용하는 환경변수라면 굳이 prod에서만 사욜하지 않고 기본값으로 두어도 괜찮습니다.

server:
  port: 8080

roomescape:
  auth:
    jwt:
      secret: Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=
      expiration: 1800000

---

spring:
  profiles:
    active: prod

  h2:
    console:
      enabled: true
      path: /h2-console

  datasource:
    url: jdbc:h2:mem:database

  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
    ddl-auto: create

이런 식으로요. yml 파일 하나에서도 '---'을 구분자로 하여 여러 profile에 대한 설정을 할 수가 있습니다.
spring.profiles.active 설정을 걸지 않은 환경변수는 전역적으로 적용되기 때문에 test/application.yml에도 자동 적용이 될 거에요.

Copy link

@BackFoxx BackFoxx Jul 20, 2025

Choose a reason for hiding this comment

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

application-prod.yml, application-test.yml <- 요 방식은 spring.profiles.active와는 용례가 살짝 다릅니다.

spring.profiles.active는 애플리케이션의 실행 환경 (테스트, 베타, 스테이지, 프로덕션 등)에 따라 다른 설정을 적용하고 싶을 때 사용합니다. 창희님께서 운영용과 테스트용 profile을 분리하신 것처럼요!

반면 application-{이름}.yml은 profile보다는, 모듈마다 고유한 application.yml을 만들고 싶을 때 사용합니다.
스프링 프로젝트에서 멀티모듈을 사용해 프로젝트를 만들어본 경험이 있으신가요?
안 해보셨다면, 간단히 생각해서 한 폴더 안에 스프링 부트 프로젝트가 여러 개 있고, 프로젝트끼리 서로 implementation해서 사용하는 모습을 떠올리시면 됩니다. 저희가 jpa 쓸 때 boot-starter-jpa 라이브러리 implemetaion해서 사용하듯이요.

이번 미션의 프로젝트를 예로 들면, '예약' 모듈과 '인증' 모듈을 분리하여 별도로 관리하는 겁니다.
인증 모듈이 별도의 스프링 부트 프로젝트로 분리되었으니, application.yml도 분리될 것입니다.

// application.yml
roomescape:
  auth:
    jwt:
      secret: Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=
      expiration: 1800000

예약 모듈에서 인증 모듈을 가져와 사용하는 경우, 인증 모듈의 application.yml도 같이 적용을 할 수 있어야 애플리케이션을 정상적으로 실행할 수 있을 거에요. 이 때 사용하는 방식이 application-{이름}.yml입니다.
인증 모듈의 application.yml 이름을 application-auth.yml로 지정하는 겁니다.
그리고 예약 모듈에서 해당 yml 설정을 import해서 함께 적용할 수 있습니다. 이 때 사용하는 설정이 spring.profiles.include입니다.

spring:
  config:
    include: auth << application-auth.yml 설정을 가져와 등록

server:
  port: 8080

spring:
  profiles:
    active: prod

  h2:
    console:
      enabled: true
      path: /h2-console
...

모든 곳에서 이 용도를 딱 정해서 쓰진 않지만, 대체로 이렇게 씁니다!

Copy link
Author

Choose a reason for hiding this comment

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

정리하자면,
spring.profiles.active는 실행 환경(dev, test, prod 등..)에 따라 다른 설정을 적용하고 싶을 때 사용하고

application-{이름}.yml은 공통 설정을 담은 application.yml과 분리하여
환경별 또는 모듈별 설정을 정의하는 데 사용되는군요

또한 이 설정파일을 include 하거나 spring.profiles.active에 지정할 수 있는 것이군요!

자세한 설명 감사합니다!

@chxghee
Copy link
Author

chxghee commented Jul 18, 2025

배포 스크립트 작성했어요~~!

편하신 시간에 확인해 주시고 리뷰 부탁드려요 👍

Copy link

@BackFoxx BackFoxx left a comment

Choose a reason for hiding this comment

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

안녕하세요! 스크립트 파일 공유해주셔서 감사합니다. 궁금한 점들을 질문 올려드렸으니 확인 후 답변 부탁드려요! :)

echo "********** [배포 중 에러 발생] : $(date +%Y-%m-%d\ %H:%M:%S) **********" >> $DEPLOY_LOG
echo " -> 실패한 명령어: '$BASH_COMMAND'" >> $DEPLOY_LOG
echo " -> 위치: ${BASH_SOURCE[1]}:${LINENO[1]}" >> $DEPLOY_LOG
exit 1

Choose a reason for hiding this comment

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

우와 로그가 아주 상세한데요? 직접 만드셨나요? :0 👍

Copy link
Author

@chxghee chxghee Jul 21, 2025

Choose a reason for hiding this comment

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

배포 스크립트로 실행했을떄 오류가 나게 되면 어떤 명령어에서 문제가 발생했는지 알기 쉽지 않을 것 같아
최대한 자세히 로그를 남기고 싶었습니닷

(셸 스크립트로 구현하는 방법은 지피티의 도움을 받았어요 😅 )


# 1. 최신 코드 pull
echo "> Git pull" >> $DEPLOY_LOG
git pull >> $DEPLOY_LOG 2>&1

Choose a reason for hiding this comment

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

2>&1
요건 무슨 뜻인가요?

Copy link
Author

Choose a reason for hiding this comment

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

git pull을 했을때 발생할 수 있는 표준에러(2)표준 출력(1)과 함께 DEPLOY_LOG 로그에 같이 저장하기 위한 설정이에요

2>&1 를 안 해주면, 표준에러가 로그에 저장되지않고 2로 터미널에 출력이 될 것 같아 같이 로그에 저장할 수 있도록 설정했습니닷

deploy.sh Outdated
else
echo " -> 실행 중인 애플리케이션 종료 (PID: $CURRENT_PID)" >> $DEPLOY_LOG
kill -15 $CURRENT_PID
sleep 5

Choose a reason for hiding this comment

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

애플리케이션이 언제나 5초 안에 종료됨을 보장할 수 있나요?
또 5초보다 더 빨리 종료되는 경우 불필요한 기다림을 최소화할 수 있는 방법이 있을 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

고민해 보았는데,

생각이 나는 방식이 루프를 돌다가 종료가 되면 break 하는 방법이 생각나네요!

  1. 우선 실행중인 프로그램이 있다면 Kill -15 로 종료를 시도한 뒤
  2. 루프를 돌다가 종료가 되면 break 를 하는 방식

이렇게 하게 되면 루프를 약 10 초 동안 돌다가 만약 10초가 지났음에도 kill -15로 종료가 되지 않았다면,

kill -9로 강제 종료하는 로직을 추가해 보았어요!

# 5. 실행 중인 애플리케이션이 있으면 종료
echo "> 실행 중인 애플리케이션이 있다면 종료" >> $DEPLOY_LOG
if [ -z "$CURRENT_PID" ]; then
  echo "  -> 현재 실행 중인 애플리케이션이 없습니다." >> $DEPLOY_LOG
else
  echo "  -> 실행 중인 애플리케이션 종료 (PID: $CURRENT_PID)" >> $DEPLOY_LOG
  kill -15 $CURRENT_PID

  for _ in {1..10}
  do
    if ! ps -p $CURRENT_PID > /dev/null; then
      echo "   → 종료 완료" >> $DEPLOY_LOG
      break
    fi
    sleep 1
  done

  if ps -p $CURRENT_PID > /dev/null; then
    echo "   → 정상 종료 실패, 강제 종료 시도." >> $DEPLOY_LOG
    kill -9 $CURRENT_PID
    sleep 2
  fi
fi

이러한 루프를 타는 방식 외에 개선할 다른 방법이 있다면 피드백 부탁드려요!

Choose a reason for hiding this comment

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

제가 유도한 바를 정확히 구현해 주셨어요! 최고에요

deploy.sh Outdated

# 6. 새 애플리케이션 백그라운드 실행
echo "> 새 애플리케이션 실행" >> $DEPLOY_LOG
nohup java -jar $JAR_FILE > $APP_LOG 2> $APP_ERROR_LOG & # 정상 출력 로그-> > APP_LOG / 비정상 출력 로그 -> 2> ERROR_LOG

Choose a reason for hiding this comment

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

이대로 실행하면 애플리케이션의 profile이 default로 들어가서 창희님께서 설정하신 application.yml의 설정들이 안 적용될 것 같은데, 실제 해보시니 어땠나요?

Copy link
Author

Choose a reason for hiding this comment

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

실제로 배포 스크립트를 실행해 보니까
profile이 prod 로 실행이 되었어요

image

아마 application.yml에 아래와 같이 프로파일 설정을 해 주니까 prod 로 실행이 된 것 같아요

spring:
  profiles:
    active: prod

하지만 이렇게 application.yml에 직접 설정을 넣게 되면 실행 시에 항상 application.yml을 수정해 주어야 하니
jvm 옵션으로 profile을 지정할 수 있도록 수정해 볼게요!

-Dspring.profiles.active=prod

Choose a reason for hiding this comment

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

좋아요! profile을 외부에서 변수로 주입받을 수 있게 설정하면
나중에 베타용, 스테이지용, 운영용 애플리케이션을 따로 띄워야 할 때 유연하게 대응할 수 있습니다. 👍

@chxghee
Copy link
Author

chxghee commented Jul 22, 2025

[변경내용]

  1. 기존에 application.yml으로 작성되었던 파일을
    application-prod.yml application-test.yml로 나누어 실행 환경 별로 profile을 지정해서 선택적으로 실행 할 수 있도록 했고,

  2. 배포 스크립트

  • 실행 프로그램 중단 로직 보안
  • 프로그램 실행 시 jvm 옵션을 통해 profile 지정

이렇게 수정해 보았어요~!

Copy link

@BackFoxx BackFoxx left a comment

Choose a reason for hiding this comment

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

멋지게 구현해 주셨네요! 앞으로의 여정도 응원합니다. 프로젝트도 화이팅하세요!

@boorownie boorownie merged commit 19a9ce5 into next-step:chxghee Jul 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants