바이브코딩 서비스를 Docker 컨테이너로 실전서비스 론칭하기 · 3부 — CI/CD, IaC, 무중단 배포, 롤백

17장. 배포 자동화 연결

15장에서 앱 배포를 자동화했고, 16장에서 인프라를 코드(Terraform)로 만들었습니다. 이번 장은 손을 많이 움직이기보다, 지금까지 만든 조각들을 한 걸음 떨어져서 바라보며 "전체 그림"을 완성하는 시간입니다. 짧지만 중요합니다. 이 그림이 곧 실무에서 팀이 일하는 방식 그 자체이기 때문입니다.

[지금 여기]

우리는 22단계를 거쳐 "라이브 투표 서비스"를 만들고, 컨테이너에 담아, AWS에 배포하고, 실무처럼 운영하는 여정을 걷고 있습니다. 지금은 17단계, 지금까지 만든 자동화 조각들을 하나의 흐름으로 잇는 자리입니다.

  1. 1장개발 환경 준비 (터미널 / Node.js / Git / GitHub / VS Code / Claude Code)
  2. 2장Claude Code 사용법 익히기
  3. 3장무엇을 만들지 기획 (라이브 투표 서비스)
  4. 4장로컬에서 서비스 만들기 (React + Express + PostgreSQL)
  5. 5장Docker 개념
  6. 6장Dockerfile 작성
  7. 7장컨테이너 빌드·실행
  8. 8장AWS 시작 (계정 / IAM / 리전 / 비용)
  9. 9장이미지 태깅
  10. 10장ECR에 이미지 올리기
  11. 11장VPC 네트워크 구성
  12. 12장RDS 데이터베이스 생성
  13. 13장SSM 터널로 RDS 초기화
  14. 14장ECS Fargate + ALB로 배포 (기본 완성)
  15. 15장CI/CD (GitHub Actions)
  16. 16장IaC (Terraform)
  17. 17장배포 자동화 연결
  18. 18장현업 운영 구조 이해
  19. 19장무중단 배포
  20. 20장신규 버전 배포 & 롤백
  21. 21장(심화) 프론트를 Vercel로 분리 배포
  22. 22장마무리 (회고 + 리소스 삭제)

이번 장에서 완성되는 것

한 문장으로: "코드를 수정하면 사용자에게 닿기까지" 전체 길을 하나의 그림으로 그릴 수 있게 되고, 인프라 변경을 PR로 올려 검토받는 흐름을 직접 경험합니다.

이렇게 되면 성공입니다: 내 GitHub 저장소에서 작은 변경 하나를 브랜치로 올려 PR을 만들고, 바뀐 내용(diff)을 눈으로 확인한 뒤, 내가 직접 그 PR을 합쳐(merge) 봅니다. 그리고 "앱 파이프라인과 인프라 파이프라인이 무엇이 다른지", "코드 수정 → 사용자 접속까지의 경로"를 말로 설명할 수 있습니다.

사전 조건

이 장은 지금까지 만든 것을 조망하는 장이라, 앞 장들의 결과물이 갖춰져 있어야 이야기가 이어집니다. 아래를 먼저 확인하세요.

참고

이번 장은 새로 만드는 인프라가 없어서 AWS 콘솔은 거의 열지 않습니다. 대부분 개념을 정리하고, 마지막에 GitHub 웹 화면에서 작은 실습 하나만 합니다. AWS 요금이 새로 붙는 작업은 없습니다.

17.1 두 개의 파이프라인 — 앱과 인프라

우리 프로젝트에는 이제 성격이 다른 두 종류의 코드가 있습니다.

그리고 각각에 자동화가 하나씩 붙어 있습니다. 이 자동화 한 벌을 "파이프라인"이라고 부릅니다.

용어

파이프라인(Pipeline) 코드가 "고쳐진 순간"부터 "실제로 반영되는 순간"까지 거치는, 자동으로 이어진 처리 단계들의 줄을 말합니다. 공장의 컨베이어 벨트를 떠올리면 됩니다. 재료(코드 변경)를 한쪽 끝에 올리면, 검사·조립·포장(빌드·테스트· 배포)을 거쳐 완성품이 반대쪽 끝으로 나옵니다. 15장에서 만든 GitHub Actions 워크플로가 바로 우리의 "앱 파이프라인"입니다.

앱 코드 변경frontend / backendmain에 푸시GitHub Actions빌드 → ECR 푸시 → ECS 배포결과 반영인프라 코드 변경infra (Terraform)main에 푸시Terraformplan(검토) → apply(적용)결과 반영

참고

왜 둘을 나누나 앱과 인프라는 바뀌는 속도와 위험도가 다릅니다. 앱은 하루에도 여러 번 배포하지만, 인프라 변경(예: DB 설정, 네트워크 규칙)은 한 번 잘못 건드리면 서비스 전체가 멈출 수 있어 훨씬 신중해야 합니다. 그래서 파이프라인을 둘로 나누고, 인프라 쪽에는 사람이 검토하는 단계를 더 두는 것이 보통입니다. 이 "검토 단계"의 핵심 도구가 바로 다음 절의 PR과 코드 리뷰입니다.

17.2 새 개념 — PR과 코드 리뷰

인프라가 코드가 되면서 얻은 가장 큰 것은, 인프라 변경을 "코드 리뷰"라는 안전장치 위에 올릴 수 있다는 점입니다. 이 절에서 그 두 축인 PR과 코드 리뷰가 무엇인지부터 차근차근 짚겠습니다.

(1) 개념 — PR과 코드 리뷰가 무엇인가

그동안 우리는 코드를 고치면 곧바로 main(우리 프로젝트의 대표 저장 줄기)에 올렸습니다. 혼자 하는 연습이라 그래도 괜찮았죠. 그런데 여러 명이 같은 저장소를 만지거나, 실수하면 서비스가 멈추는 중요한 코드라면, "바로 올리기"는 위험합니다. 누군가 한 번 봐 주고, 문제가 없을 때만 합쳐지는 관문이 필요합니다. 그 관문이 PR입니다.

용어

브랜치(Branch) 저장소 안에서 코드를 여러 갈래로 나눠 두는 "작업용 복사본 줄기"입니다. main이라는 대표 줄기에서 가지를 하나 쳐서(브랜치를 만들어), 거기서 마음껏 고쳐 보고, 다 되면 main에 다시 합칩니다. 실험하다 잘못돼도 main은 안전하게 그대로 있습니다.

용어

PR(Pull Request, 풀 리퀘스트) "내가 만든 브랜치의 코드 변경을 main에 합쳐(pull) 주세요"라고 올리는 요청서입니다. GitHub의 기능으로, 무엇이 어떻게 바뀌는지가 나란히 표시되고, 동료가 검토(리뷰)하고 승인해야 합쳐집니다. 코드가 main에 들어가는 관문 역할을 합니다.

용어

코드 리뷰(Code Review) PR에 올라온 변경을 다른 사람이 읽고 "문제 없는지, 더 나은 방법은 없는지"를 살펴보고 의견을 다는 과정입니다. 실수는 혼자보다 둘이 볼 때 훨씬 잘 잡힙니다. GitHub에서는 PR 화면의 바뀐 줄 옆에 직접 댓글을 달아 리뷰합니다.

한 문장으로 정리하면, PR은 "합쳐 달라는 요청서"이고, 코드 리뷰는 "그 요청서를 동료가 검토하는 일"입니다. 이 둘이 짝을 이뤄, 검토받지 않은 코드가 함부로 main에 들어가지 못하게 막습니다.

(2) 활용 사례 — 실무에서 PR과 리뷰를 왜 쓰나 (여러 예)

PR과 코드 리뷰는 우리 프로젝트만의 이야기가 아닙니다. 소프트웨어를 여럿이 만드는 거의 모든 팀이 이 방식을 씁니다. 대표적인 쓰임새를 봅시다.

(3) 맛보기 — 아주 작은 PR을 직접 만들어 보기

말로만 들으면 감이 안 오니, 우리 프로젝트와 분리해서 아주 작은 PR을 한 번 직접 만들어 봅시다. 여럿이 아니라 혼자여도 괜찮습니다. 내가 올리고 내가 검토하고 내가 합쳐 보면, PR이 어떻게 생겼는지 손으로 알게 됩니다. 코드가 아니라 설명 파일(README) 한 줄만 고칠 거라, 서비스에는 아무 영향이 없습니다.

이 실습은 터미널이 아니라 웹브라우저의 GitHub 화면에서 합니다.

  1. 웹브라우저에서 https://github.com 에 로그인한 뒤, 우리 프로젝트 저장소로 들어갑니다. (오른쪽 위 내 프로필 아이콘 → Your repositories(내 저장소) → 목록에서 우리 투표 프로젝트 저장소 클릭.)
  2. 저장소 첫 화면의 파일 목록에서 README.md 파일을 클릭해 엽니다.
    • [참고] README 파일이 없다면, 파일 목록 위쪽의 Add file(파일 추가) → Create new file(새 파일 만들기)을 눌러 파일 이름을 README.md로 하고 아무 내용이나 한 줄 적은 뒤 진행해도 됩니다.
  3. 파일 오른쪽 위의 연필 모양 아이콘(Edit this file, 이 파일 편집)을 클릭합니다. 편집 화면으로 바뀝니다.
  4. 내용 맨 아래에 아무 줄이나 하나 추가합니다. 예: PR 연습용 한 줄 추가 라고 적습니다.
  5. 오른쪽 위의 Commit changes…(변경 커밋) 버튼을 누릅니다. 작은 창이 뜹니다.
  6. 이 창 아래쪽에 두 개의 선택지가 있습니다. 여기서 두 번째 선택지인 Create a new branch for this commit and start a pull request(이 커밋을 위한 새 브랜치를 만들고 풀 리퀘스트를 시작한다)를 고릅니다.
    • 그 아래 브랜치 이름 입력칸에 이미 patch-1 같은 이름이 자동으로 들어가 있습니다. 그대로 두면 됩니다.
    • [주의] 첫 번째 선택지(Commit directly to the main branch, main에 바로 커밋)를 고르면 PR 없이 곧장 합쳐져 버립니다. 우리는 PR을 경험하는 게 목적이니, 반드시 두 번째를 고르세요.
  7. Propose changes(변경 제안) 버튼을 누릅니다. GitHub가 "브랜치의 내용과 main을 비교하는" 화면(Open a pull request, 풀 리퀘스트 열기)으로 데려갑니다.
  8. 제목과 설명을 적는 칸이 보입니다. 제목은 자동으로 채워져 있으니 그대로 두거나, 설명칸에 "PR이 어떻게 생겼는지 연습" 정도로 한 줄 적습니다. 그리고 Create pull request(풀 리퀘스트 만들기) 버튼을 누릅니다.
  9. 여기가 핵심입니다. 방금 만들어진 PR 화면에서 위쪽 Files changed(바뀐 파일) 탭을 눌러 보세요. 내가 추가한 한 줄이 초록색으로 표시됩니다. 이것이 바로 리뷰어가 보는 화면입니다. 무엇이 어떻게 바뀌는지가 한눈에 보입니다.
    • [참고] 실무라면 여기서 동료가 이 초록 줄 옆에 댓글을 달아 리뷰합니다. 지금은 혼자 하니, 눈으로 확인하는 것으로 리뷰를 대신합니다.
  10. 이제 이 PR을 합쳐 봅시다. Conversation(대화) 탭으로 돌아가, 아래쪽의 Merge pull request(풀 리퀘스트 합치기) 버튼을 누르고, 이어서 Confirm merge(합치기 확인)를 누릅니다.
  11. "Pull request successfully merged and closed(성공적으로 합쳐지고 닫힘)"가 보이면, 나타나는 Delete branch(브랜치 삭제) 버튼을 눌러 연습용 브랜치를 정리합니다.

방금 여러분은 PR의 한살이 전체를 직접 겪었습니다. 브랜치에서 고치기 → PR 올리기 → 바뀐 내용 확인 → 합치기. 실무의 인프라 변경도 정확히 이 흐름을 탑니다.

(4) 우리 프로젝트 — 인프라 변경을 PR로 관리한다

이제 이 흐름을 우리 투표 서비스의 인프라에 대입해 봅시다. 실무에서 "DB 앞을 지키는 보안 그룹 규칙을 하나 바꿔야 하는" 상황을 상상해 보겠습니다.

콘솔 시절(2부에서 하던 방식): 담당자가 AWS 콘솔에 들어가 보안 그룹 규칙을 조용히 클릭해 바꿉니다. 아무도 모르고, 기록도 안 남고, 실수해도 알아챌 사람이 없습니다. 나중에 "이 규칙 누가 왜 열었지?"를 물어도 답할 길이 없습니다.

IaC 시절(16장 이후, 이제부터):

  1. 담당자가 vote-app/infra/ 안의 해당 .tf 파일에서 보안 그룹 규칙을 수정하고, (17.2 맛보기에서 해 본 것처럼) 브랜치를 만들어 PR을 올립니다.
  2. PR에 자동으로 terraform plan 결과가 붙습니다. — "이 변경으로 보안 그룹 규칙 1개가 추가됩니다." 기계가 먼저 한 번 걸러 줍니다.
  3. 동료가 리뷰합니다. "이 포트를 여는 이유가 뭐예요?"라는 질문과 답이 PR에 기록으로 남습니다. 사람이 또 한 번 걸러 줍니다.
  4. 승인되면 main에 합쳐지고, terraform apply가 돌아 실제 AWS 인프라에 반영됩니다.

같은 "보안 그룹 규칙 하나 변경"인데, 안전망이 완전히 다릅니다. 누가· 언제·왜 바꿨는지 전부 남고, 실수는 plan(기계)과 리뷰(사람)에서 두 번 걸러집니다. "인프라를 바꾼다 = PR을 올린다"가 되는 것, 이것이 IaC가 바꾸는 일하는 방식입니다.

참고

혼자 하는 프로젝트에서도 PR이 유용한가? 유용합니다. PR을 올리면 합치기 전에 plan 결과와 바뀐 줄을 차분히 다시 보게 되고, 변경 이력이 깔끔하게 남습니다. 몇 달 뒤의 내가 "이때 이걸 왜 바꿨지?"를 찾을 때, PR에 적어 둔 설명이 가장 고마운 기록이 됩니다. 방금 맛보기에서 혼자 PR을 올리고 합쳐 본 것처럼요.

17.3 전체 그림 — 코드 수정에서 사용자 접속까지

이제 이 책에서 만든 전체 시스템을 한 장으로 그려 보고, "코드를 한 줄 고치면 그것이 사용자 화면에 닿기까지" 어떤 길을 지나는지 처음부터 끝까지 따라가 봅시다.

개발자(나)코드 수정 → PR → 리뷰 → main 병합앱 코드인프라 코드GitHub Actions빌드 → ECR 푸시 → ECS 배포Terraformplan → applyAWSALB (퍼블릭)사용자 요청을 받는 입구ECS Fargate 태스크 (프라이빗)web + api 컨테이너RDS PostgreSQL (프라이빗)관리 통로: SSM 터널 → RDS / CloudWatch ← 로그

코드 수정 → 사용자 접속까지의 경로를 순서대로 짚으면 이렇습니다.

  1. 코드 수정. 내가 (Claude Code의 도움을 받아) vote-app/frontend/backend/의 코드를 고칩니다. — 1부에서 배운 것.
  2. GitHub에 올리기(브랜치 → PR → main). 변경을 브랜치로 올려 PR을 만들고, 확인·리뷰를 거쳐 main에 합칩니다. — 이번 17장에서 정리한 것.
  3. 앱 파이프라인 작동(빌드·배포). main이 바뀌면 GitHub Actions가 자동으로 컨테이너 이미지를 빌드해 ECR에 올리고, ECS Fargate 서비스를 새 이미지로 갱신합니다. — 15장 CI/CD.
  4. 인프라는 그 밑을 받친다. 이 모든 것이 올라가는 무대(VPC, RDS, ECS, ALB)는 16장에서 Terraform 코드로 정의해 두었고, 인프라를 바꿀 때도 2번과 같은 PR 흐름을 탑니다. — 11~14장, 16장.
  5. 사용자 접속. 사용자가 브라우저로 ALB 기본 DNS 주소(HTTP)에 접속하면, ALB가 요청을 ECS의 web 컨테이너(Nginx)로 넘기고, web은 React 화면을 보여주며 /api 요청은 api 컨테이너로 넘깁니다. api는 RDS PostgreSQL에서 데이터를 읽고 씁니다. — 14장에서 완성한 기본 구조.

1부의 우리는 이 그림에서 "1번 코드 수정"까지밖에 할 수 없었습니다. 지금은 코드 수정부터 사용자 접속까지 전 구간이 자동화된 하나의 길로 이어져 있습니다. 손으로 하나씩 만들던 조각들이 전부 제자리에 놓여, 자동으로 흐르는 파이프라인이 된 것입니다.

남은 것은 이 길 위에서 실제 운영을 해 보는 일 — 현업의 운영 구조를 이해하고, 새 버전을 무중단으로 내보내고, 문제가 생기면 되돌리는 일입니다. 그것이 남은 장들의 내용입니다.

[확인]

이번 장이 제대로 됐는지 확인합니다. 새로 만든 인프라가 없으니, "직접 해 본 것"과 "말로 설명할 수 있는 것" 두 가지로 확인합니다.

막히면

[체크리스트]

아래를 스스로 말로 설명할 수 있는지 확인하세요. 하나라도 막히면 해당 절로 돌아가 다시 읽습니다.

모두 됐다면, 이제 이 길 위에서 실제로 운영을 해 볼 차례입니다.