← 모든 글

staging이 prod를 닮지 않은 날부터 장애는 시작된다

env 동기화 부채가 쌓이는 속도와 그것이 터지는 순간에 대한 회고

처음엔 티가 안 난다

staging과 prod가 언제부터 달라졌냐고 물으면 아무도 모른다. 어느 날 갑자기 벌어진 게 아니라, 매일 조금씩 멀어진 거라서.

  • prod에만 붙어 있는 RDS 파라미터 그룹이 생긴 날: 누군가 급하게 slow query 잡겠다고 innodb_buffer_pool_size를 콘솔에서 건드렸다. 티켓도 없이. staging에 반영됐냐고? 당연히 안 됐다. 두 달 뒤 staging에서 재현 안 되는 OOM이 prod에서 터졌을 때야 추적했다.
  • 환경 변수 19개 중 7개가 staging에만 존재하는 더미였다: 올해 초 감사하다가 발견했다. 누가 테스트하다가 FEATURE_X_ENABLED=true를 staging .env에 박아두고 prod에는 안 옮긴 것. 이게 6개월째 살아 있었다.
  • ALB 리스너 룰이 달랐다: prod는 /api/v2/* 패스 기반으로 신규 타겟 그룹을 물고 있었는데, staging은 여전히 단일 타겟. 배포 파이프라인에서는 이걸 건드리지 않았으니 차이가 생긴 줄 몰랐다.

언제 터지나

막상 터지는 타이밍은 항상 최악이다. 트래픽이 낮을 때 조용히 발견되는 경우는 거의 없었다.

staging에서 멀쩡했던 새 기능이 prod에서 500을 뱉기 시작했다. 원인은 Redis 설정이었다. staging은 ElastiCache cluster-mode disabled, prod는 cluster-mode enabled. 두 환경이 다른 시점이 언제였는지는 terraform state를 뒤져야 알 수 있었다. 결국 7개월 전이었다. 그 사이 수십 번 배포가 지나갔다.

그 때 직접 느낀 건, staging에서 테스트했다는 말이 아무 보증도 안 된다는 것. 오히려 “staging 통과했으니까 괜찮겠지”라는 안도감이 더 위험했다.

부채가 쌓이는 구조

동기화가 깨지는 이유는 단일하지 않다. 경로가 너무 많다.

  • IaC 밖에서 콘솔로 건드리는 습관: 급할 때 콘솔이 빠르다는 건 사실이다. 그런데 그 변경이 코드로 돌아오는 경우는 절반도 안 된다. 특히 보안그룹 인바운드 룰 추가가 그렇다. “임시로”가 영구가 된다.
  • staging 배포 주기가 prod보다 훨씬 빈번해서 설정이 먼저 바뀌는 경우: 신기능 테스트하면서 staging에만 feature flag를 켜두고 prod에는 릴리스 때 넣으려고 미루다가 잊는다. 이런 게 누적된다.
  • IaC를 staging과 prod가 공유하지 않고 별도 state로 관리할 때: 처음엔 격리가 목적이었는데, 어느 순간 staging module이 prod보다 두 버전 뒤처지기 시작한다. 그 차이를 아무도 추적하지 않는다.

내가 해본 것 중 실제로 작동한 것

완벽한 해법은 없었다. 다만 몇 가지는 진짜 효과가 있었다.

  • terraform plan -var-file=prod.tfvars 를 staging CI에서 주기적으로 돌려서 drift를 stdout으로 뱉는 job을 달았다: prod 설정을 기준으로 staging이 얼마나 벗어났는지 매주 슬랙 채널에 올렸다. 처음 실행했을 때 diff가 34줄이었다. 두 달 뒤엔 9줄로 줄었다. 완전히 0은 아니었고, 의도적으로 다르게 둔 항목들은 # intentional-drift 주석으로 표시했다.
  • 환경 변수는 SSM Parameter Store를 단일 소스로 쓰고, staging과 prod가 같은 키 체계를 공유하게 했다: /prod/app/FEATURE_X/staging/app/FEATURE_X를 한 스크립트로 같이 확인할 수 있다. 이전엔 .env 파일이 각자 떠돌았다.
  • 콘솔 변경 감지를 Config Rules로 붙였다: 특정 리소스 타입에 변경이 생기면 슬랙 알림이 온다. 코드로 돌아오기 전에 사라지는 변경을 잡기 위해서였다. 노이즈가 있어서 필터 튜닝을 두 번 했다.

아직 해결 못 한 것

솔직히 말하면, 데이터 레이어가 여전히 문제다.

DB 스키마는 migration으로 관리하는데, 그 외 설정—파라미터 그룹, 스냅샷 주기, 읽기 전용 복제본 유무—은 IaC에서 종종 빠진다. prod에서 복제본을 붙이거나 파라미터를 바꿀 때 staging에 동기화하는 절차가 체계적이지 않다. 그냥 누군가 기억해서 해야 한다. 그리고 보통은 안 된다.

캐시 레이어도 마찬가지다. staging의 Redis TTL이 prod의 절반인 걸 최근에야 알았다. 성능 테스트 결과가 prod에서 재현이 안 됐던 이유 중 하나였다.

다음 한 가지

분기마다 staging vs prod drift report를 IaC 외부—파라미터 그룹, 캐시 설정, ALB 룰—까지 범위를 넓혀서 한 번씩 직접 눈으로 보기로 한다. 자동화가 못 잡는 영역을 사람이 보는 루틴이 있어야 한다.


🛒 이 글과 어울리는 추천 상품

위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.