Phoenix Local 환경에서 Env 설정 자동화

깡부지깡부지
3 min read

Problem

Elixir / Phoenix 스택으로 처음 서비스를 구현하고 있다.
민감한 정보를 코드에서 사용해야 할 경우가 생겨서 환경변수를 사용하는 코드가 생겼다.
Production 환경에는 배포 방식에 따라서 서버가 실행되기 전에 환경변수를 미리 설정하는 여러가지 방법들이 있는데,
로컬에서 mix 로 서버를 실행 할 때 환경변수를 깔끔하게 자동으로 적용할 수 있는 방법을 찾기가 어려웠다.
고민끝에 나름대로 마음에 드는 방법을 발견해서 정리 겸 공유를 위해 글을 작성한다.

Requirements

  • 없으면 안되는 환경변수가 없는 경우 서버 실행 시 에러가 발생해야 한다.

  • 환경변수 설정을 위해 기술스택을 벗어난 다른 프로그램을 활용하지 않아야 한다.

    • ex) source .env && mix phx.server / env-cmd -f .env && mix phx.server
  • 로컬에서 서버 실행 시 환경변수를 자동으로 설정하기 위해 기존 Application 코드를 수정하지 않아야 한다.

TLDR;

# mix.exs
defmodule MyApp.MixProject do
  # ...
  defp aliases do
    [
      # ...
      "phx.server.dev": ["load_env .env.dev", "phx.server"]
    ]
  end
end
  • 로컬 개발용 mix alias 를 추가한다. (위 예제 코드의 phx.server.dev)

  • mix phx.server 가 실행되기 전에 미리 env 파일을 읽어서 환경변수를 설정하는 mix task 를 실행한다.

  • 물론 mix load_env .env.dev 가 실행될 수 있도록 Mix Task 를 추가해야 한다.

Prerequisite

먼저 하나 짚고 넘어가야 할 부분이 있다.

모든 환경변수는 runtime.exs 에 존재한다고 가정한다.

. (phoenix root)
└── config/
   ├── config.exs
   ├── dev.exs
   ├── prod.exs
   ├── runtime.exs
   └── test.exs

위 config 파일들 중 runtime.exs 를 제외한 모든 파일은 mix 초기화 시점(mix task 가 실행되기 전)에 평가된다.
mix task 실행 전에 환경변수를 설정해야 한다면 외부 프로그램 사용이 불가피하다.
그렇기 때문에 runtime.exs 를 제외한 다른 config 파일에 환경변수를 읽는 코드가 있으면 해당 글의 방법은 동작하지 않는다.
사실 지금은 runtime.exs 을 통해서 환경변수를 읽는 방법으로 통일된 것으로 알고 있지만 오래된 elixir version 을 사용하는 경우에는 dev.exsprod.exs 파일에서 읽는 경우도 있는 것 같다.

그러면 본격적으로 작업을 시작해보자.

How?

먼저 Mix Task 를 만들자.
env 파일을 직접 읽는 대신 이미 존재하는 Dotenv 패키지를 사용하자.

# lib/mix/tasks/load_env.ex
defmodule Mix.Tasks.LoadEnv do
  use Mix.Task

  @shortdoc "Loads environment variables from .env file"

  @impl Mix.Task
  def run(args) do
    file = List.first(args) || ".env"

    Dotenv.load!(file)
  end
end

Task 에서 Dotenv 를 사용하니 의존성에 :dotenv 를 추가해야 한다.

# mix.exs
defmodule Monotick.MixProject do
  # ...
  defp deps do
    [
      # ...
      {:dotenv, "~> 3.1"}
    ]
  end
end

mix deps.get 을 실행하면 패키지가 추가된다.
그리고 아래와 같이 mix.exs 에 alias 하나를 추가하자.

# mix.exs
defmodule Monotick.MixProject do
  # ...
  defp aliases do
    [
      # ...
      "phx.server.dev": ["load_env .env.dev", "phx.server"]
    ]
  end
end

이렇게만 하면 끝이다.

마지막으로 env 파일을 추가하기 전에 gitignore 에 env 파일을 무시하는 설정이 있는지 확인하자.
나는 .env.example 를 사용해서 아래와 같이 gitignore 에 설정한 상태로 사용한다.

# Env files
.env*
!.env.example

Test

먼저 필수 환경변수가 없는 경우 에러가 발생하는지 확인해보자. 아래 코드를 runtime.exs 에 추가하자.

# config/runtime.exs

foo = System.fetch_env!("FOO")

fetch_env! 함수는 환경변수에 주어진 Key 값이 없는 경우 에러를 발생시킨다.
터미널에서 mix phx.server.dev 를 실행하면 아래와 같이 에러가 발생하는 것을 확인할 수 있다.
** (System.EnvError) could not fetch environment variable "FOO" because it is not set

이제 FOO 환경변수를 env 파일에 추가해서 정상적으로 서버가 올라가는지 확인해보자.
예제는 .env.dev 를 읽도록 했으니 .env.dev 에 아래 환경변수를 추가하자.

# .env.dev
FOO="foo"

mix phx.server.dev 실행 시 서버가 정상적으로 작동하는 것을 확인할 수 있다.

혹시나 다른 좋은 방법이 있다면 댓글로 남겨주시면 감사하겠습니다.

0
Subscribe to my newsletter

Read articles from 깡부지 directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

깡부지
깡부지