Node.js로 서비스를 만들 때 환경변수를 어떻게 사용해야 할지 처음에는 막막했는데 이제는 고민도 없이 dotenv를 쓴다. 런타임 때 중요한 변수들을 코드로부터 분리하는 방법인데 .env라는 파일에 원하는 변수들을 선언하고 서비스가 시작될 때 읽어들여 필요한 곳에서 사용하는 방식이다. 


NPM 라이브러리 주소는 다음과 같다. 

https://www.npmjs.com/package/dotenv


내용은 많지만 실제로 한 번 사용해보고 정리가 되면 다른 것들은 필요 없다. 가장 자주 쓰는 코드는 다음과 같다.

1
require('dotenv').config()
cs

이 코드를 가장 먼저 실행되도록 적당한 파일의 적당한 위치에 넣기만 하면 끝이다. 라이브러리가 로드되면서 같은 위치에서 .env 파일을 찾아 process.env 변수에 저장한다. 로드하는 파일의 위치를 변경할 수도 있다. 


구현


간단히 프로젝트를 만들어서 dotenv 패키지를 설치한 뒤 index.js 파일을 추가했다.  

npm init 

npm install --save dotenv

touch index.js


위에서 만든 index.js 파일에 아래 코드를 추가한다. 이 파일은 아래의 .env 파일을 읽어 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { parsed, error } = require('dotenv').config()
 
if (error) {
  console.log('dotenv error', error)
  throw error
else {
  console.log('Loaded env variables')
  Object.keys(parsed).forEach(k => {
    console.log(`${k}: ${parsed[k]}`)
  })
  console.log('\nMachine-specific env variables')
  Object.keys(parsed).forEach(k => {
    console.log(`${k}: ${process.env[k]}`)
  })
  console.log('\nOverride ALREADY_SET_VAR with loaded variable')
  process.env.ALREADY_SET_VAR = parsed.ALREADY_SET_VAR
  console.log(`process.env.ALREADY_SET_VAR=${process.env.ALREADY_SET_VAR}`)
}
cs


다음은 .env 예제이다.

1
2
3
4
5
6
7
SERVER_ADDRESS=localhost
SERVER_PORT=8080
DB_ADDRESS=localhost
DB_USER=user
DB_PASSWORD=password
DB_DATABASE=db_user
ALREADY_SET_VAR=2
cs


테스트


파일을 실행하기 전에 다음과 같은 환경변수를 추가한다. 이는 .env 변수를 등록할 때 기존 변수의 유무에 따라 어떻게 동작하는지 보기 위해서이다. 

export ALREADY_SET_VAR=1


다음 명령으로 index.js 파일을 실행한다. 

node .


정상적인 경우 다음과 같은 결과가 출력된다.

Loaded env variables


SERVER_ADDRESS: localhost

SERVER_PORT: 8080

DB_ADDRESS: localhost

DB_USER: user

DB_PASSWORD: password

DB_DATABASE: db_user

ALREADY_SET_VAR: 2


Machine-specific env variables


SERVER_ADDRESS: localhost

SERVER_PORT: 8080

DB_ADDRESS: localhost

DB_USER: user

DB_PASSWORD: password

DB_DATABASE: db_user

ALREADY_SET_VAR: 1


Override ALREADY_SET_VAR with loaded variable


process.env.ALREADY_SET_VAR=2


dotenv.config() 함수가 호출되면 변수들을 모두 process.env에 등록하고 로딩된 변수들을 parsed라는 프로퍼티에 저장해 리턴한다. 정상적인 경우라면 위의 메시지를 볼 수 있는데, 한가지 흥미로운 것은 프로그램 실행 전 export 시킨 변수인 ALREADY_SET_VAR 값은 변경되지 않는다는 것이다. 코드에서처럼 process.env.ALREADY_SET_VAR 값에 로드한 값을 할당해서 사용할 수는 있으나 이 작업은 런타임에서만 유효하다. 


만약 파일이 존재하지 않거나 하여 에러가 발생하면 error 프로퍼티가 추가된다. 다음은 파일이 존재하지 않을 때 위의 index.js 파일의 코드에 의해 생성되는 결과이다.

/project_path/index.js:4

  throw error

  ^


Error: ENOENT: no such file or directory, open '/project_path/.env'


    at Object.fs.openSync (fs.js:646:18)

    at Object.fs.readFileSync (fs.js:551:33)

    at Object.config (/project_path/node_modules/dotenv/lib/main.js:85:29)

    at Object.<anonymous> (/project_path/index.js:1:107)

    at Module._compile (module.js:643:30)

    at Object.Module._extensions..js (module.js:654:10)

    at Module.load (module.js:556:32)

    at tryModuleLoad (module.js:499:12)

    at Function.Module._load (module.js:491:3)

    at Function.Module.runMain (module.js:684:10)


dotenv 라이브러리를 사용하면서 주의할 점은 .env 파일을 git에 등록하지 않아야 한다는 점이다. 위의 .env 예에서와 같이 데이터베이스 유저의 이름과 암호가 포함될 경우 노출의 우려가 있기 때문이다. 그래서 나는 보통 env.sample 파일을 만들어 커밋한다. 이 파일을 이용해서 각자 환경에 맞게 .env 파일을 생성할 수 있도록 해주기 위해서다.


마이크로서비스가 늘어나고 공통되는 변수와 아닌 변수들이 많이 늘어나면서 좀 더 편한 방식은 없는지 찾게 되더라. 하지만 아직은 dotenv로 무리 없이 운영하고 있다.


간단한 예제이지만 소스를 올려놓았다. 


https://github.com/ksleeq21/dotenv-example


Posted by 코딩새싹
,