2 minute read

Elixir에서는 두 종류의 설정 파일이 있다. 빌드 타임 설정에 사용하는 config.exs 파일과 런타임 설정에 사용하는 runtime.exs 파일이다. 두 파일 모두 사용할 수밖에 없다. 빌드 타임에 모든 걸 결정할 수 없기 때문이다. DB 접속 정보가 대표적인 예다.

런타임 설정을 어떻게 관리하면 좋을까? runtime.exs 파일을 직접 수정하는 건 좋은 생각이 아니다. runtime.exs 파일은 배포를 위해 릴리즈(release)를 만들면 같이 포함되기 때문이다. 내가 편집한 설정이 릴리즈에 포함된 파일에 덮어 씌여져서 사라지는 걸 방지해야 한다.

환경 변수가 있으면 읽어서 사용

환경 변수가 있으면 읽어서 사용하는 방법을 생각할 수 있다. Heroku 같은 PaaS(platform as a service)를 사용하면 앱마다 환경 변수를 웹에서 손쉽게 관리할 수 있어서 설정하기 편하다.

예를 들어 개발 환경이 아닌 배포 환경에서만 Sentry를 사용한다면 runtime.exs 파일을 통해 설정할 수 있어야 한다.

# runtime.exs

import Config

if sentry_dsn = System.get_env("SENTRY_DSN") do
  config :sentry, dsn: sentry_dsn
end

System.get_env/1 함수로 환경 변수를 읽어 있다면 세팅하게 구성한다. release.exs 파일에 elixir 코드를 사용할 수 있어서 N 개의 설정을 읽는 복잡한 작업도 가능하다.

Systemd로 elixir 앱 실행을 관리한다면 서비스 파일로 환경 변수를 세팅한다.

[Service]
...

Environment="ACCOUNT1_INTERVAL_MINUTE=60"
Environment="ACCOUNT1_KEY=[SECRET]"
Environment="ACCOUNT1_SECRET=[SECRET]"
Environment="ACCOUNT1_TOKEN=[SECRET]"
Environment="ACCOUNT1_TOKEN_SECRET=[SECRET]"
...

대부분은 환경 변수만으로 충분하다. 특히 사이드 프로젝트 규모라면. 만약 복잡한 계층 구조를 가진 설정이라서 환경 변수들로 평면적으로 풀 수 없다면 어떻게 하면 될까? 설정 파일을 써야 한다.

외부 설정 파일을 사용

runtime.exs 파일을 직접 수정하는 건 피하고 싶다. 릴리즈를 만들어 배포할 때, runtime.exs 파일이 포함되기 때문이다. 디폴트 설정을 runtime.exs 파일에 하고 사용자가 바꿀 수 있는 설정은 환경 변수나 외부 설정 파일로 빼면 배포할 때마다 설정이 덮어 씌여지는 걸 걱정하지 않아도 된다.

FHS(Filesystem Hierarchy Standard)를 준수한다면 외부 설정 파일 경로는 /etc/opt/my_app/runtime.exs 정도가 좋겠다. /etc/my_app/runtime.exs 정도로 해도 무난하다. 만약 Docker 라면 /config/runtime.exs 경로를 사용해도 된다.

아래와 같은 외부 설정 파일을 만든다.

# /etc/opt/my_app/runtime.exs
import Config

config :my_app, MyApp.Repo,
  database: "ecto_simple",
  username: "postgres",
  password: "postgres",
  hostname: "localhost"

디폴트 설정을 모아두는 runtime.exs 파일에서는 외부 설정 파일이 있는지 검사하고 로드한다. 기본 설정을 덮어쓸 수 있게 제일 마지막에 검사하고 적용해야 한다.

import Config

# 설정 마지막에 외부 설정 파일 로드
external_config_path = "/etc/opt/my_app/runtime.exs"
if File.exists?(external_config_path) do
  IO.puts("Loading external config from #{external_config_path}")
  Code.eval_file(external_config_path)
else
  IO.puts("No external config found at #{external_config_path}, using default settings")
end

마치며

release.exs 파일을 직접 수정하는 건 피해야 한다. 릴리즈에 포함돼서 덮어쓰는 걸 주의해야 하기 때문이다. release.exs 파일에서 환경 변수를 로드하거나 외부 설정 파일을 읽도록 지원해야 한다.

사이드 프로젝트는 외부 설정 파일까지는 필요 없고 환경 변수만으로 충분하다. 그래도 또 모른다. 프로젝트가 오래 진행돼서 커진다면 환경 변수를 사용해 복잡한 설정을 1차원으로 풀어내는 게 버거워진다. 그때 외부 설정 파일을 고려하면 된다.

링크