S3Client 문제인 줄 알았지만 submodule 문제였던 건에 대하여
지난번 S3 사용법을 작성할때 마지막에 S3Client를 사용하면서 발생했던 문제에 대해 다뤄본다고 했었다. 하지만 사실 알고보니 S3Client의 문제가 아니라 S3Client에서 사용하던 bucket Name과 key를 application.yml로 관리중이였는데 이 yml이 submodule이여서 발생했던 문제였다. 이에 대해 좀 더 자세히 다뤄볼까 한다.
동글에서 겪었던 문제는 아래와 같았다.
- Github Actions로 빌드 후 배포하면 S3 Client에서 Access Denied 예외가 발생했다. 이외에 다른 서버 문제는 발생하지 않았다.
- 하지만 로컬에서 빌드 후 배포하면 문제가 없었다.
로컬에서 빌드할때 차이는 서브모듈을 업데이트했다는 것이었다. 이때까지는 서브모듈에 익숙하지 않아 서브모듈이 정확히 어떤 방식으로 작동하는지 몰랐고 actions에서 checkout을 할때 submodules:true
설정만 켜놓으면 최신 서브모듈 커밋을 읽어오는줄 알았다. 왜냐하면 서버에서 과거 서브모듈을 사용했다면 분명히 특정 값이 없어서 서버 자체가 실행되지 않았어야했기 때문이다. 하지만 서버는 정상적으로 작동했고, S3에서만 문제를 일으켰기 때문에 서브모듈을 업데이트가 되지 않았다는 생각을 하지 못했다.
git submodule도 git이다.
기존 동글 프로젝트의 시크릿 키들과 기타 변수들은 github secrets로 관리되고 있었고, actions로 해당 값들을 주입하였다. 하지만 변수들이 늘어남에 따라 값을 관리하고 기억하기 어려워졌고 변수가 늘어날때마다 actions를 수정해야하는 번거로움이 있어서 깃 서브모듈을 도입해 환경변수들을 관리하였다.
그러면 Github Actions는 서브모듈의 어떤 커밋을 기준으로 가져올까?
위의 사진에서 config@60b644d
폴더가 있는데 해당 폴더가 동글에서 추가한 서브모듈이다.
$git submodule add [서브모듈 URL] [메인 프로젝트에 들어갈 PATH]
위의 명령어로 서브모듈을 추가하면 PATH 경로에 서브모듈이 추가된다.
동글에서는 config로 경로를 지정하여서 서브모듈이 추가된 것이다. config 옆에 @60b644d
는 커밋 해시 값이다. 이 해시 값은 어떤 값일까?
만약 메인 프로젝트에서 git submodule add
로 서브모듈을 추가할 경우 최신 커밋을 기준으로 서브모듈을 추가한다.
만약 이 상황에서 서브모듈의 리모트에 새로운 커밋이 추가되면 어떻게 될까? 변경사항이 생겼으니 git push를 하거나 다른 브랜치로 체크아웃을 하면 오류가 뜨지 않을까?라고 생각될 수 있다. 하지만 리모트가 변경되었을 뿐이고 서브모듈 내부에서 git pull
이나 git submodule update --remote
명령어를 입력하지 않는 이상 변경사항이 반영되지 않는다.
실제로 서브모듈의 업데이트를 반영해주면 아래와 같을 것이다.
이제 git status
를 입력하면 아래와 같이 서브모듈에 변경사항이 생긴 것을 알 수 있다.
➜ backend git:(develop) ✗ git status
On branch develop
Your branch is up to date with 'origin/develop'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: src/main/resources/config (new commits)
이렇게 변경사항이 생겼으니 커밋을 하고 메인 프로젝트 리모트로 push 해주면 서브모듈도 최신 커밋을 바라보는 상태로 업데이트가 된다.
Intellij에서는 서브모듈 변경사항이 Commit 창에서도 잘 뜨지 않는다. 따라서 서브모듈을 업데이트 한 경우 cli나 다른 git gui툴로 변경사항을 커밋해야한다.
결론은 서브모듈 자체도 깃이기 때문에 변경사항을 반영해서 push 해줘야한다는 것이다.
그렇다면 S3 Client 문제는 뭐였나?
문제는 서브모듈도 업데이트해서 메인 프로젝트에 커밋하지 않아 과거 서브모듈이 사용되었다는 것이였다. 그렇지만 과거 서브모듈이 사용되었다면 어떻게 서버는 정상적으로 동작했을까?
답은 역시나 공식 문서에 있었다..
Spring Boot Profile Specific Files
application.yml
을 기본적으로 읽고 특정 application-{profile}.yml
이 있고 해당 profile
로 실행될때 값을 오버라이드한다.
Profile-specific properties are loaded from the same locations as standard
application.properties
, with profile-specific files always overriding the non-specific ones.
따라서 과거 application-dev.yml
을 읽었을때 특정 값이 비어있더라도 application.yml
에 값이 있다면 읽어올 수 있었던 것이었다.
예를 들어, dev, prod 프로파일 두개가 설정되었다면 기본적으로 application.yml
값을 읽은 다음 application-dev
를 먼저 오버라이드 하고 application-prod
를 마지막으로 오버라이드를 하는 순서로 작동된다.
결론
새로운 기술을 사용할때 대충 이럴 것이다 생각해서 추측하지 말고 미리 공식문서를 조금 읽어두자. 문제가 생겼을때는 추측으로 인해 문제 발생 부분을 찾아내기 쉽지 않다.