CI/CD 배포 자동화 실패했을 때, 밤새 복구하며 배운 3가지 교훈
CI/CD 배포 자동화 실패했을 때, 밤새 복구하며 배운 3가지 교훈
월요일 오전 9시, 엊그제 잘 돌아가던 배포 파이프라인이 갑자기 붉은 경고등을 켰습니다. 예고도 없이 깨진 CI/CD 배포 자동화는 평화로운 주말을 산산조각냈고, 결국 저는 밤새 콘솔 창 앞에 붙어 에러 로그와 씨름해야 했습니다. “이제 자동화했으니 퇴근하고 잠만 자면 되겠다”는 찰나의 안도감은 어디로 사라지고, 예상치 못한 실패 지점 하나하나를 수동으로 점검하느라 눈이 빨개지는 상황이 벌어졌습니다. 이 글에서는 제가 겪은 배포 자동화 실패 사례를 바탕으로 원인 분석 순서, 설정 점검 방법, 재발 방지 팁까지 구체적으로 정리합니다.
📌 이 글의 핵심 요약
- 왜 CI/CD 배포 자동화가 실패하는가? – 3가지 주요 원인 (환경 변수 누락, 권한 오류, 캐시 문제)
- 실제 복구 타임라인 – 밤 10시부터 새벽 5시까지의 생생한 기록
- 문제 진단 방법 – 로그 분석보다 먼저 해야 할 것
- 재발 방지 대책 – 안정적인 배포 체계 구축을 위한 4가지 실전 팁
1. 사건의 발단: 순조롭던 배포의 시작
우리 팀은 주 3회 배포를 목표로 GitLab CI/CD 파이프라인을 운영하고 있었습니다. 테스트 코드, 빌드, 도커 이미지 생성, 프로덕션 서버 배포까지 모든 것이 자동화되어 있었죠. 그날 저녁, 팀원이 코드를 머지하고 파이프라인이 자동으로 돌아가기 시작했습니다. 문제는 빌드 스테이지는 통과했지만 배포 스테이지에서 튕겨져 나온 것입니다. 에러 메시지는 단 한 줄, Permission denied (publickey)였습니다.
처음에는 단순히 SSH 키가 만료되었나 싶었습니다. 하지만 재발급받고 다시 파이프라인을 돌려도 같은 에러가 반복됐습니다. 마치 한밤중에 나타난 유령처럼, CI/CD 배포 자동화의 빌드 과정은 정상인데 배포 과정에서만 계속 오류가 발생한 겁니다. 이때부터 제 밤샘 작업이 시작되었습니다.
2. 실패 원인 분석: 로그 하나로 밝혀진 진실
밤 10시부터 로그를 뒤지기 시작했지만, 새벽 12시가 넘어서야 저는 단순히 키 문제가 아니라 서버 측 SSH 키 등록 방식이 문제임을 깨달았습니다. 새로 발급받은 키를 프로덕션 서버의 authorized_keys에 추가했지만, 파이프라인 실행 계정이 특정 사용자(예: gitlab-runner)로 고정되어 있어서 해당 계정에 키가 등록되지 않았던 것입니다.
2.1. 숨은 함정: 환경 변수와 스크립트 주입
문제는 이것뿐만이 아니었습니다. 제가 파이프라인을 수정하면서 환경 변수(Environment Variables)를 잘못 매핑한 것이 두 번째 실패 원인이었습니다. 배포 스크립트가 프로덕션 서버의 IP를 하드코딩으로 참조하는 바람에, 새로 교체한 스테이징 서버와 충돌이 발생해 배포 사본이 서로 엉킨 것입니다. 이처럼 환경에 따라 달라지는 값은 코드 안에 두지 말고 GitLab CI/CD 설정의 Variables 메뉴에 등록하는 것이 안전합니다. 등록할 때는 Masked 옵션을 활성화해 시크릿 값이 로그에 노출되지 않게 해야 합니다.
| 원인 유형 | 증상 | 발견 난이도 | 수정 시간 |
|---|---|---|---|
| SSH 키 권한 문제 | Permission denied | 하 | 약 30분 |
| 환경 변수 누락/삭제 | 빌드 성공 & 배포 실패 | 상 | 약 2시간 |
| 캐시(Cache) 오염 | 배포된 컨텐츠가 이전 버전 | 중 | 약 1시간 |
2.2. 캐시 때문에 새벽 3시까지 붙잡히다
SSH 문제와 환경 변수 문제를 모두 고치고 나니, 이번에는 배포된 웹사이트가 예전 버전으로 표시되는 겁니다. 분명 최신 코드가 서버에 업로드되었는데, CDN이나 서버 내부의 캐시가 이를 가리고 있었습니다. CI/CD 배포 자동화에서 가장 빈번하게 간과되는 부분이 바로 이 캐시 무효화(Cache Invalidation)입니다.
여기서 중요한 점은 자동화를 작성할 때 반드시 설치 및 빌드 스테이지에서 의존성 파일(cache)을 정리하는 작업을 함께 넣어야 한다는 것입니다. 제 경우에는 GitLab Runner의 캐시 정책 설정을 cache:key로 분리하지 않아서, 이전 파이프라인에서 작성된 node_modules 캐시가 계속 유지되어 마치 옛날 소스를 배포하는 듯한 착각을 불러일으켰습니다. 브랜치나 작업 단위로 캐시 키를 분리하고, CDN을 사용한다면 배포 후 퍼지(Purge) 작업을 스크립트에 포함하는 것이 좋습니다.
3. 밤샘 복구가 끝나고 든 생각: 실패는 곧 리스크 관리
새벽 5시 30분, 마침내 CI/CD 배포 자동화가 파란불을 켰습니다. 수많은 시행착오 속에서 저는 단순히 에러를 고친 것이 아니라, 우리 파이프라인의 구조적 약점을 발견했습니다. 모든 것을 하나의 스크립트로 몰아넣었기 때문에, 문제가 생기면 원인을 분리하기가 매우 어려웠던 것입니다. 실패를 빠르게 진단하려면 로그를 뒤지기 전에 이번 변경에서 무엇이 바뀌었는지부터 먼저 확인하는 것이 효과적입니다.
3.1. 문제 해결을 위한 변경 전략
새벽 내내 고생한 경험을 바탕으로 저는 파이프라인을 아래와 같이 재설계했습니다.
- 단계별 분리: 빌드, 테스트, 배포를 각각 별도의 스크립트와 환경으로 분리.
- 설정 파일(Config) 분리: 환경별(
.env) 파일을 외부로 빼서 하드코딩 제거. - 에러 알림 강화: Slack 봇을 연동하여 실패 즉시 알림을 받는 구조로 변경.
- 배포 후 헬스 체크 자동화: 운영 서비스의 HTTP 상태 코드, DB 연결 상태를 자동으로 확인하여 실패를 즉시 감지.
4. 결론: 고통 없이 배우는 교훈은 없다
밤새 복구한 그 경험은 이제 제게 자산이 되었습니다. 여러분도 CI/CD 배포 자동화를 구축하거나 운영할 때, 단순히 성공에만 집중하지 마시고 실패 지점을 어떻게 빠르게 찾을 것인가에 더 집중하시길 바랍니다. 실제로 지금 우리 팀은 이 사건 이후로 모든 배포 작업 전에 사전 점검 리스트(Pre-flight check)를 수행하고 있습니다.
배포 전 점검 리스트에는 다음 항목이 포함됩니다.
- CI/CD 변수와 환경별 설정 파일이 정상적으로 등록되어 있는지
- 파이프라인 실행 계정에 SSH 키가 올바른 사용자로 등록되었는지
- 캐시 키 전략과 CDN 퍼지(purge) 절차가 정의되어 있는지
- 배포 후 헬스 체크가 자동으로 실행되는지
마지막으로 드리고 싶은 조언은, 가장 성가신 문제는 항상 자동화 설정 자체가 아닌, 그 안에 숨겨진 환경 의존성이라는 것입니다. 오늘 여러분이 겪고 있는 배포 실패가 단순한 설정 오류인지, 아니면 제가 겪은 것처럼 논리적 충돌인지 꼭 확인해 보세요. 이 과정을 거치면 배포 파이프라인의 안정성을 크게 높일 수 있습니다.
이 글이 도움이 되셨다면, 주변 동료에게 공유해보세요. 어쩌면 그들의 주말을 지켜줄 수도 있으니까요!