AWS ML CI/CD와 CDC 파이프라인 구축 (0) 프로젝트 소개
운영 DB를 분석용 DB로 실시간 동기화하는 CDC 파이프라인부터 push 한 번으로 SageMaker 학습까지 이어지는 ML CI/CD까지, 두 파이프라인을 AWS 위에 구축한 프로젝트의 소개와 진행 순서를 다룹니다.
데이터 동기화부터 모델 학습 자동화까지, ML 시스템의 앞뒤 배관을 직접 구축한 프로젝트 시리즈의 0편입니다. 프로젝트 전체 소개와 실행 방법을 다룹니다.
무엇을 만들었나
모델 코드를 고친 뒤 노트북에서 학습을 다시 돌리고, 결과를 눈으로 확인하고, 파일을 어딘가에 올리는 수작업이 반복된다면 모델이 좋아져도 시스템은 좋아지지 않습니다. 이 프로젝트는 그 수작업 구간을 두 개의 파이프라인으로 자동화합니다.
- CDC 동기화 파이프라인: 운영 DB(MySQL)에 발생하는 모든 변경을 캡처해서 분석용 DB(PostgreSQL)로 실시간 복제합니다. 분석과 학습은 이 사본만 바라봅니다.
- ML CI/CD 파이프라인: GitHub의 main 브랜치에 push가 일어나면 테스트 → 학습 컨테이너 빌드 → SageMaker 학습 → 평가 → 성능 게이트 → 모델 등록까지 자동으로 이어집니다.
두 파이프라인은 분석용 DB에서 만납니다. CDC가 채워 주는 사본이 ML 파이프라인의 학습 데이터 소스가 되는 구조입니다.
왜 필요한가
분석 쿼리와 운영 트래픽은 성격이 다릅니다. 운영 DB는 주문 한 건을 넣고 읽는 짧은 쿼리를 쉼 없이 처리하는 곳입니다. 여기에 “전체 차량의 30일치 센서 데이터를 집계해 줘” 같은 무거운 학습용 쿼리를 던지면 서비스가 느려집니다. 그래서 사본을 분리하는데, 사본이 낡으면 의미가 없으니 실시간으로 따라가게 만드는 기술이 필요합니다. 이것이 CDC(Change Data Capture)입니다.
학습과 배포는 사람 손을 탈수록 재현이 안 됩니다. “이 모델이 어떤 코드로 학습됐는지”를 수작업 기록에 의존하면 언젠가 반드시 끊어집니다. 이 프로젝트는 git 커밋 하나가 이미지 태그, 파이프라인 파라미터, 모델 메타데이터까지 관통하도록 만들어서, 배포된 모델에서 코드 버전을 역추적할 수 있게 했습니다.
전체 구조
flowchart LR
subgraph OPS["운영계"]
SRC[("MySQL<br/>운영 DB")]
end
subgraph CDC["CDC 파이프라인"]
DBZ["Debezium"] --> KAFKA["Kafka"] --> SINK["JDBC Sink"]
end
subgraph ANA["분석계"]
DST[("PostgreSQL<br/>분석용 DB")]
end
subgraph ML["ML CI/CD 파이프라인"]
GIT["GitHub push"] --> CP["CodePipeline<br/>테스트 → 이미지 빌드"]
CP --> SM["SageMaker Pipeline<br/>전처리 → 학습 → 평가 → 등록"]
end
SRC -->|binlog| DBZ
SINK --> DST
DST -->|학습 데이터| SM
기술 스택
| 영역 | 도구 | 역할 |
|---|---|---|
| ML 코드 | Python, scikit-learn, uv | 전처리, 학습, 평가 스크립트와 의존성 관리 |
| 컨테이너 | Docker | 학습 환경을 이미지로 고정 |
| CI/CD | CodePipeline, CodeBuild | push 감지, 테스트, 이미지 빌드, 배포 순서 관리 |
| 이미지 저장 | ECR | 학습 이미지 보관 (태그 = 커밋 SHA) |
| ML 실행 | SageMaker Pipeline | 전처리 → 학습 → 평가 → 조건 분기 → 모델 등록 |
| CDC | Debezium, Kafka, Kafka Connect | binlog 캡처와 이벤트 전달 |
| DB | MySQL(소스), PostgreSQL(타깃) | 운영 데이터와 분석용 사본 |
| IaC | Terraform | AWS 리소스 정의의 코드화 |
저장소 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── docs/ # 설계 문서 (통합 개요, 문제별 상세)
├── ml-cicd/
│ ├── src/ # preprocess / train / evaluate
│ ├── tests/ # 단위 테스트
│ ├── docker/ # 학습 컨테이너 Dockerfile
│ ├── buildspec/ # CodeBuild 단계별 명령 (test / build / deploy)
│ ├── pipelines/ # SageMaker Pipeline 정의 (Python SDK)
│ └── infra/ # Terraform 정의
└── cdc/
├── docker-compose.yml # MySQL + Kafka + Debezium + PostgreSQL 로컬 데모
├── connectors/ # source / sink 커넥터 설정 JSON
└── mysql-init/ # 소스 스키마와 샘플 데이터
동작 흐름 1: 코드를 push하면 벌어지는 일
main 브랜치에 push가 도착하면 CodePipeline이 네 단계를 순서대로 실행합니다.
- Source: GitHub에서 해당 커밋의 코드를 받아 옵니다.
- Test: lint와 단위 테스트를 돌립니다. 여기서 깨지면 뒤 단계는 실행되지 않습니다.
- Build-Image: 학습 컨테이너 이미지를 빌드해 ECR에 올립니다. 태그는 커밋 SHA입니다.
- Deploy: SageMaker Pipeline 정의를 갱신하고 실행을 시작합니다. 방금 만든 이미지 주소가 파라미터로 주입됩니다.
이어서 SageMaker가 관리형 인스턴스를 띄워 전처리 → 학습 → 평가를 돌리고, 평가 지표(AUC)가 기준을 넘을 때만 Model Registry에 모델을 등록합니다. 기준 미달이면 등록 없이 실패 처리되어, 나쁜 모델이 배포 후보에 오르는 일을 파이프라인 수준에서 차단합니다.
구축하면서 배운 것 하나를 꼽으면, 평가는 학습과 같은 컨테이너 이미지에서 돌려야 한다는 점입니다. 직렬화된 모델 파일은 저장한 라이브러리 버전과 같은 환경에서만 안전하게 열리는데, 처음에는 평가를 SageMaker 제공 컨테이너(구버전 scikit-learn)로 돌리도록 설계했다가 로컬 검증에서 모델 로드가 깨지는 것을 확인하고 구조를 고쳤습니다. 클라우드에 올리기 전에 로컬 도커로 실행 규약을 재현해 본 덕에 잡은 버그였습니다.
동작 흐름 2: DB의 변경이 사본에 도착하기까지
MySQL은 모든 데이터 변경을 binlog라는 파일에 순서대로 기록합니다. Debezium은 이 로그를 복제본처럼 구독해서, 변경 한 건마다 “어느 테이블의 어느 행이 무엇에서 무엇으로 바뀌었다”는 이벤트를 만들어 Kafka로 보냅니다. 반대편에서 JDBC Sink 커넥터가 이벤트를 받아 PostgreSQL에 upsert합니다. 소스에 INSERT를 하면 몇 초 안에 타깃에서 조회되는 구조입니다.
로컬 데모로 검증한 포인트가 세 가지 있습니다.
- 초기 스냅샷: CDC는 “구독 시작 이후의 변경”만 나릅니다. 이미 쌓여 있던 데이터는 signal 테이블에 명령 행을 넣는 방식(incremental snapshot)으로, 운영을 멈추지 않고 청크 단위로 옮겨지는 것을 확인했습니다.
- 스키마 변경 대응: 소스 테이블에 컬럼을 추가하자 타깃 테이블에도 컬럼이 자동 생성되고 새 값이 유실 없이 도착했습니다. 단, 자동 반영은 컬럼 추가 같은 안전한 변경까지이고, 삭제나 타입 변경은 수동 절차가 필요합니다.
- 장애 복구: 커넥터는 “어디까지 읽었는지”를 오프셋으로 영속화합니다. 태스크를 재시작해도 그 지점부터 이어서 진행되는 것을 확인했습니다.
실행 방법
CDC 파이프라인은 전부 오픈소스라 로컬에서 무료로 재현할 수 있습니다. docker compose로 MySQL, Kafka, Debezium, PostgreSQL 4개 container를 띄우고 커넥터 2개를 REST로 등록하면 동작하며, 전체 명령과 검증 과정은 4편에 있습니다.
ML 쪽은 학습 코드가 SageMaker의 실행 규약(고정 경로와 환경변수)을 지키는지를 로컬 docker로 먼저 검증할 수 있습니다. 재현 명령과 그 과정에서 잡은 버그는 1편에 있습니다.
AWS 리소스(ECR, CodeBuild, CodePipeline, IAM 역할)는 ml-cicd/infra/의 Terraform으로 정의되어 있어 terraform plan으로 구성을 확인할 수 있습니다. 실제 학습 실행은 인스턴스 가동 시간만큼 비용이 발생하므로, 파이프라인에는 학습 시작 직전에 사람이 승인하는 게이트를 두었습니다.
시리즈 계획
| 편 | 주제 |
|---|---|
| (0) | 프로젝트 소개 (이 글) |
| (1) | ML 코드 작성과 로컬 검증 |
| (2) | AWS 인프라 구성: ECR, S3, IAM, CodeBuild |
| (3) | CodePipeline 조립과 트러블슈팅 |
| (4) | CDC 파이프라인: Debezium 로컬 구축과 실험 |
| (5) | Terraform 코드화와 마무리 |
1편부터 5편까지 실제 작업 순서(2026-07-23~26) 그대로 진행합니다. 각 편은 그때 실행한 명령과 설정, 만난 문제를 사실 위주로 기록합니다.