config 파일이냐 환경변수냐 DB냐 — 세 번 틀리고 나서 생긴 기준
설정 매체 세 가지를 언제 어떻게 고르는지, 직접 겪은 사고로 정리한 기준.
설정 하나 잘못 놓는 바람에 프로덕션이 세 시간 날아간 적이 있다. 그 뒤로 설정 매체를 고르는 기준을 좀 정리해뒀는데, 써보니 팀원한테도 설명하기 편해서 여기 옮긴다.
세 가지 매체, 세 가지 질문
설정 매체를 고를 때 내가 먼저 묻는 건 딱 세 가지다. “바꿀 때 배포가 필요한가”, “비밀인가”, “런타임 중에 바뀌어야 하는가”. 이 세 물음에 대한 답이 각각 어느 매체를 써야 하는지를 거의 결정한다. 실제로 이 기준을 팀에 공유한 뒤, 설정 관련 인시던트가 분기에 평균 3건에서 1건 미만으로 줄었다.
config 파일 — 배포 주기와 함께 움직이는 값
로그 레벨, 타임아웃 기본값, 피처 플래그 초기값처럼 “코드 릴리즈와 같이 검토받아야 하는” 설정은 파일이 맞다. 이유는 단순하다. Git에 들어가기 때문에 누가 언제 왜 바꿨는지 이력이 남는다. 리뷰도 붙고, CI도 물린다.
config/production.yaml에http_timeout: 30s를 박아둔 이유가 “원래 그랬으니까”인 경우가 많다. 막상 Git blame 을 보면 3년 전 퇴사한 엔지니어 커밋이 전부다. 파일이라도 남아 있어서 당시 PR 설명을 찾아볼 수 있었다 — 환경변수였으면 그냥 안개 속이었을 것.- 팀에서 한번
max_connections를 환경변수로 관리했다가, 스테이징 서버에만 몰래 400으로 올려놓은 게 한 달 넘게 코드리뷰를 피해갔다. 프로덕션 배포 후 DB 연결 폭증으로 터졌다. 그 이후 커넥션 관련 값은 전부 파일로 이동했다. - 단,
secrets.yaml같은 이름으로 키를 파일에 때려박은 사례를 나도 저질렀다..gitignore에 넣어뒀다고 안심했는데 머지 실수로 한 번 노출됐다. 비밀값은 파일에서 빼야 한다 — 이건 아래에서.
환경변수 — 배포 단위가 다른 비밀값
환경변수의 강점은 코드베이스 바깥에 존재한다는 것이다. API 키, DB 비밀번호, 서드파티 웹훅 시크릿. 이것들은 Git에 들어가는 순간 사고다.
- 다만 환경변수를 “뭐든 넣는 서랍”으로 쓰기 시작하면 금방 난장판이 된다. 올해 초 어떤 서비스를 인수인계받았는데 환경변수가 87개였다.
FEATURE_NEW_DASHBOARD=true같은 피처 플래그까지 전부 환경변수로 들어가 있었고, 이 중 어느 게 실제로 읽히는지조차 코드를 뒤져야 했다. 결국 파일로 이사하는 데 하루가 걸렸다. - 비밀값이면서 교체 주기가 짧은 경우, 예를 들어 토큰을 90일마다 로테이션해야 하는 경우엔 환경변수 단독보다 Vault 나 AWS Secrets Manager 같은 시크릿 스토어를 앞에 두고 환경변수로 주입하는 구조가 낫다. 로테이션 자동화를 붙이기 쉬워서다.
- 환경변수는 값이 바뀌면 프로세스를 재시작해야 반영된다. 이걸 모르고 “환경변수 바꿨는데 왜 안 됩니까”라고 물어보는 케이스를 분기에 한 번씩은 본다. 온콜 공유 문서에 한 줄 박아뒀다.
DB — 런타임 중에 바뀌어야 하는 값
운영자가 배포 없이 즉시 반영해야 하는 설정은 DB(혹은 그에 준하는 KV 스토어)가 답이다. 배너 노출 여부, 점검 모드 온오프, 요금제별 요청 한도. 이런 건 배포 사이클을 기다릴 수 없다.
- 올해 초 대규모 이벤트 때 트래픽이 예상치 세 배로 올라왔다. 사용자별 API 호출 한도를 즉시 절반으로 낮춰야 했는데, DB 기반 설정이어서 관리자 화면에서 30초 만에 반영했다. 파일이었으면 배포 파이프라인 돌리는 데 최소 8분 걸렸을 것이고, 그 8분이 꽤 컸을 상황이다.
- DB 설정의 함정은 캐시다. 설정 테이블을 메모리에 캐시해놓고 TTL 을 300초로 잡았다가, “방금 바꿨는데 왜 5분 동안 안 되냐”는 민원을 두 번 받았다. 이제는 캐시 TTL을 문서에 같이 적어두고, 어드민 화면에도 “최대 N초 후 반영”을 명시한다.
- DB 설정은 이력 관리가 약하다. 누가 어드민 화면에서 값을 바꿨는지 로그가 없으면 사고 후 추적이 힘들다. 설정 변경 이벤트를 별도 audit 테이블에 박는 것, 귀찮더라도 해두는 게 맞다.
세 매체를 섞을 때 생기는 충돌
막상 해보면 세 매체가 같은 키를 두고 충돌하는 경우가 꼭 생긴다. 우선순위를 명시해두지 않으면 “어디 값이 실제로 적용됐냐”를 디버깅하는 데 시간이 사라진다.
우리 팀은 현재 DB 설정 > 환경변수 > config 파일 순서로 덮어쓰는 단순 규칙을 코드에 명문화했다. 그리고 서비스 시작 시 최종 적용된 설정 전체를 INFO 레벨로 한 번 덤프하게 만들었다. 비밀값은 마스킹해서. 이거 하나로 “혹시 환경변수 안 먹힌 거 아닌가요” 류의 질문이 눈에 띄게 줄었다.
다음 한 가지
설정 변경 audit 로그, 지금 절반 서비스에만 붙어 있다. 다음 글 쓰기 전에 나머지에도 붙이고 “진짜 했나” 한 줄 적는다.
🛒 이 글과 어울리는 추천 상품
위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.