잘 만들어진 애플리케이션을 가지고 서비스를 잘 하려면, 서버에 배포를 정확히 하는 것이 중요합니다. 배포해야 할 서버는 하나일 수도, 또는 개발서버, 검증서버, 운영서버 등으로 분리하기도 합니다. 그래서 환경설정 파일을 분리하여, 애플리케이션을 실행할 때, 동작하는 서버에 맞춰서 설정을 적용하는 것이 필요합니다.
실행환경 별로 설정 파일의 분리
먼저 생각해 볼 수 있는 것은 운영서버 적용되는 설정을 분리하여 저장하는 방법입니다. 서버에 적용되는 설정을 파일로 분리하는 것입니다. 실행 될 환경 별로 파일을 분리하여, 로컬 개발환경의 설정이 운영서버에 적용되는 실수를 막고, 적용시에 설정파일을 변경해야 하는 것을 막는 것입니다.
예를 들어, spring boot나 rails 애플리케이션에서는 각각 application-production.properties, application-development.properties, application-local.properties, local.rb, development.rb, production.rb와 같이 환경별 설정 파일을 분리하여 저장하고, 애플리케이션을 실행할 때, 해당 설정이 적용되도록 옵션을 주는 것입니다.
# springboot
$ java -Dspring.profiles.active=production -jar target/bitlog-1.0.0.BUILD-SNAPSHOT.jar
# rails
$ bundle exec rails server RAILS_ENV=production
이렇게 실행하는 서버에 맞게 설정을 분리하면, 배포할때마다 환경에 맞추어 설정을 변경하지 않아도 됩니다. 만약 배포되어야 할 서버(개발서버,검증서버 등)가 더 있다면, 설정파일을 환경에 맞게 추가하면 됩니다.
설정 파일 분리의 문제점
하지만 위와 같은 방식은 설정 파일이 분리되기 때문에 관리할 파일이 늘어나게 되고, 그럼으로써 관리가 어려워지는 단점이 생깁니다. 예를 들어 설정에 추가되어야 할 항목이 추가되면 모든 설정파일의 항목을 찾아 수정해 주어야 합니다. 그리과 위에서 예에서와 같이 sping-boot는 application.properties를 rails는 config폴더 내의 특정 파일을 환경설정을 위한 변수로 사용합니다. 즉 사용하는 프레임웍마다 형식이 달라질 수 있는 것입니다. 이렇게 분기가 많다는 점은 여러모로 관리가 용이하지 않게 만들게 됩니다.
그리고 결정적으로 환경설정에 데이터 베이스 설정정보라도 담고 있다면 안전하게 보관되어야 할 인증정보(id/password)도 담을 수 밖에 없고, 그것들은 코드 저장소에 저장되어 누구나 접근할 수 있는 공개된 정보가 됩니다. 안전하게 보관되어야 할 정보의 유출의 위험이 더 커지게 되는 것이죠.
해결책
그래서 The Twelve-Factor App에서는 설정을 환경 변수에 저장하라고 합니다. 내용은 환경변수에 저장하고 설정 파일은 (application.properties 혹은 config.rb 처럼)하나를 사용하고 배포되는 환경에 따라 환경변수로 이용하여 항목을 설정하는 것입니다. 위에서 예로든 SpringBoot나 Rails에서는 설정 파일에 환경변수를 사용할 수 있는 방법을 제공하고 있습니다. 가령 Database 접속에 관한 설정이라면 다음과 같이 할 수 있습니다.
# env var
DATABASE_USERNAME=bitlog
DATABASE_PASSWORD=db!admIn1075
# config file
...
spring.datasource.username=$DATABASE_USERNAME
spring.datasource.password=$DATABASE_PASSWORD
...
이렇게 하게 되면, 설정파일은 코드 변경 없이 쉽게 배포될 수 있으며, rails에서도 DB를 접속하려고 한다면 모두 동일한 환경변수를 사용할 수 있기 때문에 프레임웍에 따른 변경도 없게 됩니다. 또 코드에서는 값을 저장하고 있지 않기 때문에 민감한 정보가 코드 저장소에 올라갈 확률도 줄어들게 됩니다.
하지만 설정 파일에서 환경변수를 읽어오는 방법을 제공하지 않는 어플리케이션은 어떻게 해야할까요? 이런 경우에 사용할 수 있는 envsubst라는 애플리케이션이 있습니다. envsubst는 파일을 전달받아, 파일 내의 환경변수 항목을 실행하는 시스템의 환경 변수와 비교하여 동일한 항목이 있는 경우 내용을 치환한 결과를 출력해 줍니다.
가령 다음과 같이 config.json을 설정으로 사용하는 애플리케이션이 있다면 envsubst에 파일을 입력하면 출력으로 치환된 결과를 전달해 줍니다.
# config.json
{
"database": {
"user": "$DATABASE_USERNAME",
"password": "$DATABASE_PASSWORD"
},
}
$ envsubst < config.json > config.json
# replaced config.json
# config.json
{
"database": {
"user": "bitlog",
"password": "db!admIn1075"
},
}
따라서 애플리케이션이 실행되기 전에 먼저 envsubst를 한번 실행해 준다면 환경 변수를 설정파일에서 사용할 수 있게 됩니다.
결론
애플리케이션을 배포할 때, 실행환경과 관련된 설정은 분리되어 실행 환경이 바뀔때마다 변경하지 않도록 하는 것이 중요합니다. 그리고 환경설정 항목은 관리하기 쉽도록 만들어야 하고 설정 상의 실수를 최소화 할 수 있도록 하여야 합니다. 그런 점을 생각하면 환경 변수를 설정에 사용하는 것이 애플리케이션 배포를 더 잘 관리할 수 있게 하는 방법일 것입니다.