티스토리 뷰
환경변수 분리
애플리케이션을 배포하게 되면 환경변수를 분리하게 됩니다. 왜 분리를 해야 할까요? 다양한 이유가 있겠지만 가장 와닿는 이유로는 DB 연결정보가 다르기 때문입니다. 로컬에서 작업을 하는 것과 서버로 배포된 application이 사용하는 DB 정보가 다르기 때문입니다. 예를 들어, local에서는 docker로 띄운 DB를 사용하지만, prod 환경에서는 AWS RDS에 띄운 DB를 사용해야하므로 연결 정보를 다르게 해야 합니다.
현재 진행하고 있는 프로젝트의 경우 2개의 profile을 사용하고 있습니다.
- local(로컬)
- prod(운영)
기존에는 application.yml 1개에 설정 정보를 모두 넣고 사용하였습니다. 그러나 개발이 완료된 서버를 배포하게 되면서 작업 환경을 분리해야 할 필요성이 있었습니다. 따라서 local 환경에서 작업할 때의 설정 정보와 prod 환경에서 사용할 설정 정보를 다르게 설정하였습니다.
- application.yml
# JPA
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: "jdbc:mysql://localhost:3307/past-forward"
username: dev
password: 1234
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
open-in-view: false
# Swagger
springdoc:
api-docs:
path: /api-docs
swagger-ui:
path: /api
disable-swagger-default-url: true
display-request-duration: true
packages-to-scan: aws.retrospective
default-consumes-media-type: application/json;charset=UTF-8
default-produces-media-type: application/json;charset=UTF-8
- application-local.yml
# JPA
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: "jdbc:mysql://localhost:3307/past-forward"
username: dev
password: 1234
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
open-in-view: false
config:
activate:
on-profile: local
aws:
secretsmanager:
enabled: off
- application-prod.yml
# JPA
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: "jdbc:mysql://${host}:${port}/${dbname}"
username: ${username}
password: ${password}
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
open-in-view: false
config:
activate:
on-profile: prod
환경변수 우선순위
현재 프로젝트에는 3개의 yml 파일이 존재합니다.
- application.yml
- application-local.yml
- application-prod-yml
스프링 부트의 application.yml을 기본 설정으로 사용하고, 특정 설정 정보가 담긴 Profile을 추가로 적용할 수 있습니다. 즉, application.yml 위에 특정 Profile 설정 정보가 Override 됩니다.
저희 프로젝트의 경우 다음과 같이 yml 파일을 배치하였습니다. (data.sql은 무시해도 됩니다.)
src/main/resources 에는 공통으로 사용되는 파일을 배치하고, profile에 따라 달라지는 설정 정보는 src/main/resources-${profile} 디렉토리를 생성하여 파일을 배치하였습니다.
다음으로 build.gradle을 수정합니다. Gradle을 빌드할 시에 profile 설정 정보가 없으면 local 프로 파일이 사용되고, 반대로 profile 설정 정보가 있다면 해당 profile을 사용하게 됩니다.
사용되는 profile에 따라서 src/main/resources 디렉터리와 src/main/resoucres-${profile} 디렉터리가 합쳐서 사용되게 됩니다.
ext {
profile = (!project.hasProperty('profile') || !profile) ? 'local' : profile
}
sourceSets {
main {
resources {
srcDirs "src/main/resources", "src/main/resources-${profile}"
}
}
}
단, application.yml과 application-{profile}.yml에 동일한 환경변수 값이 저장되어 있다면 profile에 저장된 값이 우선하여 적용됩니다.
아래는 profile에 따라 application 실행 시에 출력 정보가 달라집니다.
인텔리J에서 Profile 적용
무료 버전
Run - Edit Configurations - Modify options - add VM options 클릭 후 -Dspring.profiles.active={profile명} 등록
유료 버전
Run - Edit Configurations - Active profiles에 {profile명} 등록
느낀 점
AWS와 관련된 환경 변수 값을 외부에서 관리하고 있다. 즉, 스프링에서는 해당 환경변수 값을 가지고 있지 않다.
ex. region, s3 bucket 정보
따라서 AWS 개인 계정으로 AWS Secrets Manager를 생성하고 그곳에 key:value 형식으로 값을 저장하였다. 해당 key와 value를 application-local.yml에 작성하고, API를 호출하여 AWS Secrets Manager에 등록된 key를 가져올 수 있는지 테스트를 진행하였다 -> https://server-technology.tistory.com/280
해당 API가 깃허브에 올라가게 된다면 prod 프로파일이 사용되게 된다. 운영 환경에서 사용되는 access key, secret key, region, s3 bucket 설정 정보가 적용된다.
이렇게 local과 prod 환경을 분리하여 운영하게 되면 개발을 진행하는 데 있어 매우 편한 것 같다.
사실 나도 100퍼센트 이해했다고 장담은 할 수 없는 것 같다. 환경 변수를 분리하는 개념만 알아서 될 것이 아니라 CI/CD 등 엮여있는 것이 많기 때문이다. 스스로가 판단하기에도 CI/CD 개념에 대해서 부족하기 때문에 공부의 필요성이 느껴진다. 주변에는 개발을 잘하는 사람들이 많다. 스스로 판단하기에 개발을 잘 하는 사람들의 특징이 있다면 협업을 많이 해봤다는 것이다. 혼자서 인강을 듣고 개발 연습을 하는 것보다 협업을 하면서 다양한 문제를 직면하고 해결하는 과정에서 실력이 더 성장한다고 느끼게 되었다.