배포 직후 장애. "로컬·스테이징에선 됐는데 운영에서만 죽어요." 로그를 보니 운영에만 없는 환경변수, 운영 DB에만 안 적용된 스키마, 9시간 어긋난 시간 표시, 구버전 앱에서만 나는 에러가 뒤섞여 있습니다. 이 모든 건 '환경 차이'라는 한 범주입니다. PM·인프라가 이 용어들을 알면 "운영에서만"이라는 증상에서 원인을 빠르게 좁힙니다. 이 사전은 환경 차이·설정·운영 이슈 용어를 빠르게 해독합니다.
- 1환경(dev/stg/qa/uat/prod)과 프로파일·설정 외부화를 설명할 수 있다
- 2시크릿 관리(Vault/Secret)와 노출 시 대응을 설명할 수 있다
- 3버전/스키마/데이터 불일치 등 "환경 차이" 장애를 진단할 수 있다
- 4타임존(KST/UTC)·인코딩·하위호환 이슈를 식별할 수 있다
환경과 설정
dev에서 prod까지, 코드는 같고 설정만 다르게
| 용어 | 한 줄 뜻 | 비고 | 중요도 |
|---|---|---|---|
| Dev / Stage / QA / UAT / Production Environment | 개발/스테이징/QA/사용자검수/운영 환경 | 단계별 검증 | ★★ |
| Environment Variable / Config File / Profile | 환경변수 / 설정파일 / 프로파일 | 환경별 분리 → 12-Factor App | ★★★ |
| Externalized Config / Property Override | 설정 외부화 / 값 덮어쓰기 | 코드 동일, 설정만 | ★★ |
| Feature Toggle | 기능 토글 | → 릴리스 전략 | ★★ |
| Config Reload / Hot Reload / Cold Restart | 설정 재적용 / 무중단·재시작 | 적용 방식 | ★ |
핵심: 12-Factor대로 코드는 모든 환경에서 동일, 설정만 환경에 따라 주입합니다(12-Factor App). 'dev/prod parity'(환경 간 차이 최소화)가 "운영에서만 죽는" 문제를 줄이는 근본 원칙입니다.
확대
위 그림처럼 동일한 애플리케이션 코드가 Dev·Stage·Prod에 배포되지만, 각 환경에 주입되는 시크릿(Mock DB vs Vault)과 Feature Toggle 설정이 다릅니다. 코드를 환경별로 다르게 빌드하지 않고 **설정 외부화(환경변수 주입)**로 분리해야 "운영에서만 다르게 동작"하는 사고를 구조적으로 줄일 수 있습니다.
시크릿 관리
비밀을 코드에서 떼어 안전하게
| 용어 | 한 줄 뜻 | 비고 | 중요도 |
|---|---|---|---|
| Secret Management / Vault | 비밀 중앙 관리 / 대표 도구 | 코드에 박지 말 것 | ★★★ |
| Keystore / Truststore | 내 키·인증서 / 신뢰 인증서 저장소 | TLS → 용어사전 | ★★ |
핵심: 비밀(DB 비밀번호·API 키)을 코드/이미지에 박으면 git 이력·레이어에 영구 노출됩니다(12-Factor App). Vault/Secret Manager로 중앙 관리하고, 노출되면 삭제가 아니라 즉시 교체(rotate) 합니다(이력엔 남으므로).
확대
위 그림처럼 비밀을 코드에 직접 쓰면 git commit 즉시 이력에 영구 보존되고 Docker 이미지 레이어에도 포함됩니다. 반면 Vault/Secret Manager를 사용하면 코드에는 참조만 남고 실제 값은 런타임에만 주입되어 이미지에 포함되지 않습니다. 노출 사고 발생 시 삭제가 아닌 **즉시 교체(rotate)**가 필수입니다.
환경 차이 장애
'운영에서만'의 단골 원인들
| 용어 | 한 줄 뜻 | 비고 | 중요도 |
|---|---|---|---|
| Version Mismatch / Dependency·Library Conflict | 버전 / 의존성·라이브러리 충돌 | 잠금파일 → 시맨틱 버저닝 | ★★★ |
| Schema Mismatch / Data Mismatch | 스키마 / 데이터 불일치 | 마이그레이션 → Flyway와 Liquibase를 이용한 DB 마이그레이션 버전 관리 | ★★ |
| Permission Issue | 권한 문제 | 파일·계정 권한 → chmod/chown으로 파일 읽기·쓰기·실행 권한 완벽 제어 | ★★ |
| Encoding Issue | 인코딩 문제 | UTF-8 통일 → 용어사전 | ★★ |
| Timezone / Locale Issue / KST / UTC / Epoch Time/Millis / Timestamp / Date Format | 타임존·로케일·시각 표현 | UTC 저장+표시 변환 → 정밀한 데이터 타입(숫자·문자·날짜) 선택 기준 | ★★ |
핵심: "로컬은 되는데 운영은 안 됨"은 거의 항상 이 표의 항목 중 하나입니다. 버전(잠금파일 누락), 스키마(마이그레이션 미적용), 시크릿(환경변수 누락), 타임존, 인코딩을 순서대로 점검합니다.
확대
위 그림처럼 "운영에서만" 증상은 5축(설정/시크릿 → 버전 불일치 → 스키마 불일치 → 타임존/로케일 → 인코딩) 순서로 점검하면 대부분 원인을 좁힐 수 있습니다. 각 축마다 전형적 증상이 다르므로(환경변수 누락·UnsupportedClassVersion·컬럼 없음·9시간 어긋남·한글 깨짐), 증상을 보고 해당 축을 직접 확인합니다.
호환성
신·구 버전이 공존할 때
'운영에서만' 장애 진단 — 직접 확인
"로컬은 되는데 운영은 안 됨"은 환경 차이 5축(설정·버전·스키마·타임존·인코딩)으로 좁힙니다.
1) 설정/시크릿: 운영에만 없는 환경변수? → 값은 출력하지 말고 변수명만 diff로 비교
2) 버전: 런타임/라이브러리 버전 차이? → java -version, 잠금파일 적용?
3) 스키마: 운영 DB에 마이그레이션 미적용? → 버전 테이블 확인([[migration-versioning]])
4) 타임존: 서버 TZ가 UTC인데 변환 누락? → date, DB now()
5) 인코딩: 운영 DB charset이 UTF-8인가? → ([[mysql-features]])
diff 환경변수: prod에 PAYMENT_API_KEY 없음 → 결제 초기화 실패(운영만)
java -version: local 17 / prod 11 → UnsupportedClassVersion([[language-runtime-build]])
스키마: prod에 V12 마이그레이션 미적용 → 컬럼 없음 에러
→ '운영에서만'의 3대 원인 모두 환경 차이로 확인
주의:
env전체를 비교하면 비밀번호·API 키 값이 터미널 기록이나 로그에 남을 수 있습니다. 실습에서도 반드시 변수명만 비교하고, 실제 시크릿 값은 출력·복사하지 마세요. 운영 서버 접근 권한과 명령 실행 정책을 먼저 확인합니다.
diff <(env | cut -d= -f1 | sort) <(ssh prod 'env | cut -d= -f1 | sort')- 환경변수 diff에서 운영에만 빠진 키가 있으면 그게 원인 1순위 → 시크릿/설정 외부화가 환경별로 누락됐는지(12-Factor App)
- 런타임/라이브러리 버전이 환경마다 다르면 → 잠금파일·불변 이미지로 통일(시맨틱 버저닝·컴파일·인터프리터·빌드·런타임)
- "컬럼 없음/테이블 없음" 에러가 운영에서만이면 마이그레이션 미적용 → 스키마 버전 테이블 확인(Flyway와 Liquibase를 이용한 DB 마이그레이션 버전 관리)
- 시간이 9시간(또는 배수) 어긋나면 타임존 변환 누락/중복 → 저장 UTC + 표시 변환 원칙 확인(정밀한 데이터 타입(숫자·문자·날짜) 선택 기준)
상황: 새 결제 기능을 배포했는데 로컬·스테이징은 정상이고 운영에서만 결제 초기화가 실패합니다. 코드는 동일한데 운영에서만 죽습니다.
원인: 운영 환경에만 필요한 환경변수(PAYMENT_API_KEY)가 설정되지 않은 것입니다. dev/stg엔 있었지만 prod 시크릿에 추가하는 것을 빠뜨렸습니다 — 전형적 환경 차이 장애입니다(12-Factor App).
진단:
# 환경별 설정 키 비교(값 아닌 키만)
diff <(grep -o '^[A-Z_]*' .env.stg | sort) <(ssh prod 'env' | grep -o '^[A-Z_]*' | sort)
# 운영에만 없는 키 = 범인 후보
해결: (1) 누락 시크릿을 운영 Secret Manager에 추가·재배포. (2) 근본 대응 — 설정 키 목록을 환경 간 검증하는 단계를 배포 파이프라인에 추가(CI/CD 파이프라인)해, 필수 키 누락 시 배포 전에 실패하게. (3) .env.example(12-Factor App)로 필요한 키를 문서화. "운영에서만 죽는" 문제의 절반은 설정·시크릿 누락이므로, 환경 간 설정 정합성 검증을 자동화하는 것이 예방책입니다.
심화 — 설정을 외부화한 다음에 오는 질문들
심화: 설정도 코드다 — 외부화가 만든 새 관리 대상
설정을 코드 밖으로 뺐다는 건, 코드 리뷰와 버전 관리가 지켜주던 안전망 밖으로 뺐다는 뜻이기도 합니다. 면접과 실무에서 한 단계 깊은 질문은 대부분 여기서 나옵니다.
- "코드는 안 바꿨는데 장애가 났어요"의 정체: 설정 외부화 이후엔 배포 없이도 시스템 동작이 바뀝니다. 환경변수·토글 변경이 이력 없이 일어나면 "무엇이 언제 바뀌었나"에 아무도 답할 수 없게 됩니다. 그래서 성숙한 팀은 설정도 저장소에서 리뷰·이력 관리하고(config as code), 서버에서 직접 고치는 것을 금지합니다.
- rotate는 '갈아끼우기'가 아니라 '겹치기'입니다: 시크릿을 한 번에 교체하면 옛 키로 붙어 있던 인스턴스가 일제히 인증 실패합니다. 실전 순서는 새 키 발급 → 신·구 키 동시 유효(겹침 구간) → 전 인스턴스 전환 확인 → 옛 키 폐기입니다. 그리고 유출 대응은 rotate로 끝이 아니라, 유출 구간 동안 그 키로 무엇이 접근됐는지 감사까지가 한 세트입니다.
- Feature Toggle의 수명 관리: 토글은 태생이 임시 분기입니다. 제거 기한 없이 쌓이면 토글 조합 수만큼 '테스트 안 된 경로'가 늘고, 오래돼 잊힌 토글을 다른 용도로 재사용하는 것이 대형 사고의 고전적 경로입니다(릴리스 전략). 토글마다 소유자와 제거 예정일을 함께 기록합니다.
- parity의 마지막 축은 데이터입니다: 설정·버전·스키마를 다 맞춰도 운영 데이터의 규모·NULL·이상값은 dev에 없습니다. 5축을 다 확인하고도 원인이 안 보이면, 운영에만 존재하는 데이터 패턴을 의심합니다.
정리하면, 외부화는 끝이 아니라 시작입니다 — "이 설정은 누가, 언제, 왜 바꿨나"에 답할 수 있어야 12-Factor App이 완성됩니다.
상황: 몇 주 전 외부 연동 장애를 운영 서버에서 환경변수 하나를 직접 수정해 급히 막았습니다. 이후 잠잠하다가, 관련 없어 보이는 정기 배포 직후 동일한 장애가 그대로 재발합니다.
원인: 긴급 대응 때 값을 서버에서만 고치고 설정 저장소(Secret Manager·배포 설정)에는 반영하지 않았습니다. 배포가 인스턴스를 새로 만들며 설정을 저장소 기준으로 주입하자 핫픽스가 조용히 원복된 것입니다 — 설정의 출처가 두 곳(서버 실제값 vs 저장소 기준값)으로 갈라진 config drift입니다.
진단:
# 서버와 설정 저장소의 키 목록만 비교(값은 절대 출력하지 않음)
diff <(ssh prod 'env | cut -d= -f1 | sort') <(cut -d= -f1 deploy/env.prod | sort)
# 배포 시각과 장애 시작 시각이 일치하는지 확인
해결: (1) 올바른 값을 설정 저장소에 반영하고 재배포합니다 — 서버 직접 수정으로 또 덮지 않습니다. (2) 설정의 단일 출처를 정합니다: 모든 변경은 설정 저장소를 거쳐 배포로만 적용되고, 긴급 상황도 예외가 아니라 '승인 경로만 빠른' 것으로(CI/CD 파이프라인). (3) 서버 실제값과 저장소 기준값의 diff를 주기 점검해 drift를 자동 감지합니다. "급해서 서버에서 직접"은 그 순간엔 가장 빠르지만, 다음 배포 때 시한폭탄으로 돌아옵니다(12-Factor App).
인프라/SRE에게 환경 차이 관리는 핵심 책임입니다 — 설정 외부화·시크릿 중앙관리(Vault)·환경 간 정합성 검증·dev/prod parity를 설계해 "운영에서만 죽는" 사고를 구조적으로 줄입니다(12-Factor App). 마이그레이션 적용·런타임 버전 통일·타임존(UTC) 표준도 인프라가 지킵니다. PM은 이 용어로 "운영에서만 안 돼요"를 "설정/버전/스키마/타임존/인코딩 중 무엇"으로 좁혀, 정확한 담당과 빠른 복구로 연결합니다. 배포 전 환경 정합성 체크리스트는 가장 값싼 장애 예방책입니다.
다음(마지막) 용어사전에서는 프론트엔드와 UX/UI 용어를 정리합니다.
용어 식별 실습으로 굳히기: 용어 식별 — Config / 환경 차이 / 운영 이슈 — 증상을 보고 설정·환경차이·운영이슈 용어를 가려냅니다.