← 목차 · 케이스 4

팀 배포 체계 — 없던 것을 세운 일

2025 ~ 현재 · GitHub Actions · Cloud Run · Secret Manager · Docker

합류한 팀에는 배포 체계가 없었습니다. 서비스마다 배포 절차가 따로 있었고, 새 서비스를 올릴 때마다 복사됐습니다.
흩어진 절차를 재사용 워크플로우 하나로 모았습니다. 지금 Cloud Run으로 나가는 배포는 전부 그 한 곳을 탑니다.
그리고 그 표준이 사고를 두 번 냈습니다 — 기본값 하나가 여러 서비스로 퍼졌고, 릴리스 자동화는 자기가 관리하던 버전을 뒤로 돌렸습니다.
둘 다 아래에 적었습니다.

이 문서는 배경 → 문제정의 → 해결방안 → 결과 → 정직하게 순서입니다(짧은 케이스라 각 절은 가볍게). 이력서의 팀 배포 절은 아래 ①②③ 블록의 첫 문장을 가져갑니다.

배경 — 합류한 팀에 배포 체계가 없었습니다

서비스마다 배포 절차가 따로 있었고, 새 서비스를 올릴 때마다 그 절차가 복사됐습니다. 콘솔에서 손으로 배포하는 경우도 있어 어떤 버전이 나가 있는지 추적하기 어려웠습니다. 처음부터 세웠습니다.

문제정의 — 왜 어려운가

배포 스크립트를 모으는 일은 기술적으로 어렵지 않습니다. 어려운 것은 모으지 않았을 때 무엇이 망가지는지가 늦게 보인다는 점이고, 모은 뒤에는 그 표준이 실수까지 표준화한다는 점입니다.

  • 절차가 서비스마다 다르면 어디를 봐야 하는지가 사람마다 다릅니다. 배포를 아는 사람이 병목이 됩니다.
  • 복사된 절차는 같이 늙지 않습니다. 한 곳에서 고친 것이 나머지에 가지 않고, 어느 것이 최신인지 아무도 모릅니다.
  • 시크릿이 배포 과정에서 평문 환경변수로 주입됐습니다. 값이 남을 수 있는 자리가 그만큼 늘어납니다.
  • 새 서비스를 올리는 비용이 곧 새 서비스를 만들지 않는 이유가 됩니다.

해결방안 — 무엇을 했나

① 서비스마다 따로 있던 배포 절차를 재사용 워크플로우 하나로 모았고, 지금 Cloud Run으로 나가는 배포는 전부 그 한 곳을 탑니다

pinch to zoom · drag to pan
  • 배포 절차를 재사용 워크플로우 하나로 모았습니다. 서비스별 파일에는 이름·리전·자원 크기·동시성 같은 입력값만 남습니다.
  • 시크릿을 파일로 마운트하는 방식을 넣었습니다. 배포 과정에서 값을 평문으로 풀어 넘기지 않습니다.
  • 릴리스와 버전 태깅을 자동화했습니다. 사람이 태그를 붙이지 않습니다.
    일부 서비스는 그 태그를 밀면 해당 버전이 그대로 배포되도록 배포 트리거에 물려 뒀습니다.
  • 새 서비스 온보딩이 워크플로우 파일 하나 추가로 끝나게 했습니다.
  • 이 기반이 있어서 나중에 배포 설정과 앱 설정의 불일치를 잡는 CI 게이트를 얹을 수 있었습니다.
    검사를 걸 자리가 한 곳이라 한 번만 만들면 됐습니다(→ 아래 절).

② 표준의 기본값이 어디까지 퍼지는지는 나중에 알았고, 같은 패턴을 전수 점검한 뒤 배포 설정과 앱 설정이 어긋나면 머지 전에 걸리는 검사를 붙였습니다

재사용 워크플로우에는 요청 동시 처리 수의 기본값이 들어 있습니다. 값을 적지 않은 서비스는 그 기본값으로 나갑니다.
데이터베이스 커넥션 풀을 쥐는 서비스에는 그 기본값이 맞지 않는데, 표준에 그 구분을 넣지 않았습니다.

한 서비스에서 트래픽이 몰린 날 그 불일치가 실제 장애로 드러났습니다. 그 서비스만 고치고 끝내지 않고
같은 조합을 쓰는 서비스를 전부 훑어 같은 패턴 5개를 찾았고, 위험이 큰 2개를 먼저 고쳤습니다. 나머지 3개는 백로그에 남겼습니다.
그리고 배포 설정과 앱 설정이 어긋나면 머지 전에 걸리도록 검사를 붙였습니다 — 편의를 위해 만든 표준에,
편의가 만든 사고를 막는 검사를 같이 붙인 셈입니다.

③ 릴리스 자동화가 자기가 관리하던 버전을 뒤로 돌린 뒤, 겹치면 취소가 아니라 대기하게 고치고 그 이유를 설정 옆 주석으로 남겼습니다

릴리스 자동화는 여러 컴포넌트의 버전을 한 파일에서 함께 관리합니다.
그래서 릴리스 작업이 둘 이상 겹치면, 나중에 끝난 쪽이 먼저 올라간 다른 컴포넌트의 버전까지 예전 값으로 되돌립니다.

실제로 그렇게 됐습니다. 한 컴포넌트의 버전이 뒤로 밀렸고, 같은 버전이 두 번 릴리스되면서 태그가 전진하지 못했습니다.
그 결과 유령 릴리스 PR이 두 달 동안 다시 생성됐습니다. 배포는 멀쩡히 돌았기 때문에 아무도 급하지 않았고, 그래서 오래 갔습니다.

고친 것은 한 줄입니다 — 릴리스 작업을 겹쳐 돌리지 않되, 겹치면 취소가 아니라 대기하게 했습니다.
취소하면 마지막 상태를 반영한 실행이 사라져, 열린 릴리스 PR들이 낡은 채로 남습니다.

그리고 왜 취소가 아니라 대기여야 하는지를 설정 파일 주석으로 남겼습니다.
이 한 줄은 겉보기에 흔한 옵션이라, 이유가 붙어 있지 않으면 다음 사람이 "취소가 낫지 않나" 하고 되돌립니다.
고친 것보다 왜 그렇게 고쳤는지를 코드 옆에 두는 편이 오래 갑니다.

무엇을 버리고 무엇을 샀나

버린 것산 것왜
서비스별 자유도 — 각자에게 맞는 배포 방식을 고를 수 있었습니다한 곳에서 고치면 전부 바뀝니다 — 검사·보안·정책을 한 번만 붙이면 됩니다자유도의 실제 사용처는 대부분 "예전에 복사해 온 값"이었습니다
한 곳의 실수가 한 곳에 머무는 성질(같은 것)표준은 실수도 표준화합니다. 동시성 기본값 하나가 여러 서비스로 퍼져 그중 하나가 터졌고, 릴리스 자동화는 자기가 관리하던 버전을 뒤로 돌렸습니다(→ 무엇을 했나 뒤 두 절)

결과 — 측정과 지금 상태

  • 배포 워크플로우 55개 중 49개가 이 재사용 워크플로우를 탑니다. 나머지 6개는 대상 플랫폼이 달라(Vercel) 별도 경로입니다.
    즉 Cloud Run으로 나가는 배포는 전부 한 곳을 지납니다. (2026-08-27 저장소 실측)
  • 그중 40개가 시크릿 파일 마운트 방식으로 나갑니다.

어떻게 쟀나. 저장소의 워크플로우 파일에서 재사용 워크플로우를 호출하는 것과 시크릿 옵션을 켠 것을 세었습니다.

지금 상태

  • 새 서비스는 워크플로우 파일 하나를 추가하면 배포에 올라갑니다.
  • 되돌리기는 입력값 한 줄입니다. 다만 명령줄로 바꾼 값은 다음 배포에서 원복되므로, 급한 변경도 반드시 워크플로우에 반영합니다.
  • 되돌릴 수 있게 만들어 둔 것 — 릴리스마다 버전과 변경 내역이 자동으로 붙고, 일부 서비스는 그 태그를 밀면 해당 버전이 배포됩니다.
    되돌릴 대상을 날짜가 아니라 이름으로 지목할 수 있습니다.
    다만 되돌린 경험 자체는 많지 않습니다. 컨테이너 리비전을 이전으로 돌리는 편이 빨라 실제로는 그쪽을 씁니다.
  • 지금도 제가 고칩니다.

정직하게 — 한계와 남은 일

  • "온보딩 시간을 몇 % 줄였다" 같은 수치는 없습니다. 체계가 없던 시절의 배포 시간·실패율 기록이 없어 비교 대상이 없습니다.
    셀 수 있는 것은 지금 몇 개가 한 곳을 타는지까지입니다. 그 이상은 말하지 않습니다.
  • 시크릿 마운트는 기본값이 아니라 선택입니다. 켜지 않으면 예전 방식으로 나갑니다. 기본값을 바꾸는 것은 남은 일입니다.
  • 표준이 낸 사고가 두 건입니다. 기본값이 퍼진 것 하나, 자동화가 자기 상태를 망친 것 하나.
    표준을 만든 사람은 편의뿐 아니라 그 편의가 어디까지 퍼지고 무엇을 덮는지까지 책임져야 한다는 것을 그 둘로 배웠습니다.
  • 되돌린 경험이 많지 않습니다. 되돌릴 수 있게 만들어 두는 것과 되돌려 본 것은 다르고, 저는 앞쪽이 두껍고 뒤쪽이 얇습니다.
© 2026 이남기 · portfolio.namgee.dev