설정 주입 경로 - fresh-market/fm-backend GitHub Wiki
설정 주입 경로
같은 application.yml 을 읽어도 실행 방법마다 값의 출처가 다르다.
스프링 서버 실행과 통합 테스트, 두 경로에서 각 값이 실제로 어디서 오는지 정리했다.
로그와 테스트 결과는 2026-08-20 에 로컬 Docker 로 직접 돌려 확인한 것이다.
출처는 셋이다
| 출처 | 뜻 |
|---|---|
| 저장소 | git 에 올라가는 파일. 클론하면 누구나 같은 값을 갖는다 |
| 저장소 밖 | git 에 없다. 각자 만들거나 배포가 넣어준다. 비밀값이 여기 있다 |
| 런타임 주입 | 파일이 아니라 실행 중에 만들어진다. 컨테이너가 뜬 뒤 그 접속 정보를 읽어 넣는다 |
덮는 순서
같은 키를 여러 곳이 말하면 위쪽이 이긴다.
| 순위 | 출처 | |
|---|---|---|
| 1 | 런타임 주입. Testcontainers @ServiceConnection, docker-compose 감지 |
가장 셈 |
| 2 | 명령행 인자. --spring.datasource.url=... |
|
| 3 | 시스템 프로퍼티. Gradle systemProperty |
|
| 4 | OS 환경변수. DB_URL, SPRING_PROFILES_ACTIVE |
|
| 5 | 프로필 파일. application-{프로필}.yml |
|
| 6 | 기본 파일. application.yml |
가장 약함 |
환경변수는 이 우선순위의 한 칸일 뿐이고, 실제로는 그보다 위 칸이 자주 값을 가로챈다.
그리고 .env 는 이 우선순위에 아예 없다. Docker Compose 만 읽어서 컨테이너를 어떻게 띄울지 정할 뿐,
Spring 에는 닿지 않는다. .env 에 DB_URL 을 적어도 스프링 서버는 못 본다.
스프링 서버 실행: ./gradlew bootRun
프로필을 아무것도 주지 않는다. application.yml 의 기본값이 local 을 켠다.
1. 프로필 결정 application.yml [저장소]
| profiles.default: local
|
2. 기본값 application.yml [저장소]
| DB 접속 정보. compose 구성에 맞는 기본값
|
3. 로컬 값 application-local.yml [저장소 밖]
| 카카오 키, JWT 서명 키. .gitignore 가 막는다
|
4. DB 를 덮는다 spring-boot-docker-compose [런타임 주입]
| compose.yaml 의 MySQL 을 띄우고
| 그 컨테이너에서 읽은 접속 정보로 덮는다
|
5. 기동 Flyway 마이그레이션 -> Hibernate validate -> Tomcat
확인한 로그다.
No active profile set, falling back to 1 default profile: "local"
application.yml 의 url, username, password 는 bootRun 에서는 실제로 안 쓰인다.
컨테이너에서 읽은 값이 이기기 때문이다.
그 셋이 쓰이는 때는 compose 없이 붙을 때다. 대표적으로 IntelliJ 에서 main() 을 직접 실행할 때인데,
그 경로는 Gradle 을 안 거쳐서 docker-compose 지원이 붙지 않는다. DB 를 미리 띄워둬야 한다.
통합 테스트: ./gradlew integrationTest
여기서는 환경변수가 한 칸도 안 쓰인다. 프로필은 시스템 프로퍼티로, DB 는 Testcontainers 로 들어온다.
1. 프로필 결정 build.gradle [저장소]
| systemProperty 'spring.profiles.active', 'integrationTest'
| IDE 직접 실행 대비로 테스트 클래스에 @ActiveProfiles 도 붙였다
|
2. 기본값 application.yml [저장소]
| 공통만. local 이 안 켜지므로 application-local.yml 은 안 읽힌다
|
3. 비밀값 src/integrationTest/resources/ [저장소]
| application-integrationTest.yml
| 가짜 값이라 커밋한다. 이게 없으면 컨텍스트가 안 뜬다
|
4. DB @ServiceConnection MySQLContainer [런타임 주입]
| 테스트마다 컨테이너를 띄우고 그 접속 정보를 넣는다
| 파일에 DB 설정이 없어도 된다
|
5. 결과 22건 통과 (Product 11, Category 8, Placement 3)
확인한 로그다.
The following 1 profile is active: "integrationTest"
application-integrationTest.yml 이 생긴 이유
CI 는 PR 에서 브랜치 머리가 아니라 병합 커밋을 체크아웃한다.
그래서 비밀값 키를 추가한 브랜치가 통합 테스트를 하나도 안 건드렸어도,
develop 쪽 통합 테스트가 그 브랜치의 application.yml 위에서 함께 돌아 빌드가 깨진다.
같은 커밋에서 이 파일만 빼면 11건이 전부 PlaceholderResolutionException 으로 실패한다.
값별로 보면
같은 키가 경로마다 다른 곳에서 온다.
| 키 | bootRun | 통합 테스트 | 운영 |
|---|---|---|---|
spring.profiles.active |
application.yml 기본값 | Gradle systemProperty | SPRING_PROFILES_ACTIVE |
spring.datasource.url |
compose 컨테이너 | Testcontainers | DB_URL |
spring.datasource.username |
compose 컨테이너 | Testcontainers | DB_USERNAME |
jwt.secret |
application-local.yml | application-integrationTest.yml | JWT_SECRET |
...kakao.client-id |
application-local.yml | application-integrationTest.yml | KAKAO_CLIENT_ID |
kakao.admin-key |
application-local.yml | application-integrationTest.yml | KAKAO_ADMIN_KEY |
hibernate.format_sql |
application.yml (true) | application.yml (true) | application-prod.yml (false) |
MYSQL_PORT |
.env -> Compose |
해당 없음 | 해당 없음 |
마지막 줄을 보라. MYSQL_PORT 만 .env 에서 오고, 그것도 Spring 이 아니라 Compose 가 읽는다.
.env 가 스프링 서버 설정에 관여하는 칸은 이 표에 하나도 없다.
운영은 아직 배선 전이다
파일은 이름만 갖고 있고 값을 넣어줄 쪽이 아직 없다. infra 문서가 정한 경로는 이렇다.
SSM Parameter Store (SecureString) [저장소 밖]
| 서명 키와 DB 자격증명
|
배포 스크립트 아직 없다
| 컨테이너 교체보다 먼저 값을 갱신해야 한다 (INF-7-03)
|
컨테이너 환경변수 [저장소 밖]
| 서버 위 .env 를 거칠 수도 있다. 어느 쪽이든 저장소에는 없다
|
application-prod.yml [저장소]
${DB_URL} 처럼 이름만 적혀 있다
기본값이 없어 값이 빠지면 기동이 막힌다
없는 것이 셋이다.
| 없는 것 | 상태 |
|---|---|
| Dockerfile | 스프링 서버 컨테이너 이미지를 만들 방법이 아직 없다 |
| 배포 워크플로 | .github/workflows 에 pr-gate, registry-check, wiki-sync 뿐이다 |
| SSM 파라미터 | 문서에 정해져 있고 실제로 만들어진 것은 없다 |
함께 볼 것
설정 파일 각각의 역할과 로컬에서 무엇을 고치는지는 저장소의 docs/project/configuration.md 에 있다.