본문으로 건너뛰기
Sourcegithub.com

CI/CD 가이드라인

· 약 5분
최재훈
LEAD (AI Research Engineer), Brain Crew

TL;DR

Azure VM 환경에서 GitHub Actions를 활용한 Docker 기반 CI/CD 파이프라인 구축 사례입니다. SSH를 통한 원격 배포와 Docker Compose 기반 멀티 컨테이너 관리를 구현했으며, fastclean 두 가지 배포 모드를 제공해 상황에 따라 빠른 업데이트 또는 완전한 재배포를 선택할 수 있습니다. SK Ecoplant 프로젝트에서 실제 운영된 스크립트로, RAG 파이프라인 배포에 최적화되어 있습니다.

Key Takeaways

  • 배포 모드 분리: fast 모드는 캐시 활용으로 빠른 배포를, clean 모드는 완전한 초기화를 통해 환경 일관성을 보장하여 개발/운영 단계에 따라 유연하게 대응
  • SSH 기반 원격 배포: GitHub Secrets를 활용한 안전한 인증 정보 관리와 ssh-keyscan을 통한 MITM 공격 방지로 보안성 확보
  • Docker Compose v2 명시적 설치: Runner 환경에 관계없이 일관된 Docker Compose 버전을 사용하여 예측 가능한 배포 환경 구축
  • 멀티 스테이지 이미지 구조: Base 이미지를 분리해 공통 의존성을 재사용하고, LangGraph와 FastAPI 서비스를 독립적으로 관리하여 빌드 효율성 향상
  • 수동 트리거 지원: workflow_dispatch를 통해 긴급 배포나 롤백 시나리오에서 개발자가 직접 배포 모드를 선택할 수 있는 유연성 제공

상세 내용

프로젝트 배경 및 구조

이 CI/CD 파이프라인은 SK Ecoplant 고객사 프로젝트에서 실제 운영된 배포 스크립트입니다. RAG(Retrieval-Augmented Generation) 파이프라인을 Azure VM 환경에 배포하기 위해 설계되었으며, 다음과 같은 3개의 Docker 이미지로 구성됩니다:

  • Dockerfile.base: 공통 의존성을 포함하는 베이스 이미지
  • Dockerfile.langgraph: LangGraph 기반 워크플로우 서비스
  • Dockerfile.fastapi: API 엔드포인트를 제공하는 FastAPI 서비스

이러한 멀티 이미지 구조는 각 서비스의 독립적인 스케일링과 유지보수를 가능하게 하며, 베이스 이미지 분리를 통해 빌드 시간을 최적화합니다.

GitHub Actions Workflow 구성

트리거 설정

on:
push:
branches:
- main # main push 시 자동 실행
workflow_dispatch:
inputs:
mode:
description: "배포 모드 선택 (fast / clean)"
required: true
default: "fast"
type: choice
options:
- fast
- clean

두 가지 트리거를 지원합니다:

  • 자동 트리거: main 브랜치로의 push 시 자동으로 fast 모드로 배포
  • 수동 트리거: Actions 탭에서 개발자가 직접 배포 모드를 선택하여 실행 가능

이러한 구조는 일반적인 개발 워크플로우(자동 배포)와 긴급 상황(수동 개입)을 모두 지원합니다.

SSH 연결 설정 및 보안

- name: Set up SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.AZURE_SSH_KEY }}" > ~/.ssh/azure_vm_key.pem
chmod 600 ~/.ssh/azure_vm_key.pem
ssh-keyscan -H ${{ secrets.AZURE_VM_IP }} >> ~/.ssh/known_hosts

SSH 연결을 위해 다음 보안 조치를 적용했습니다:

  1. GitHub Secrets 활용: 민감한 정보(SSH 키, VM IP, 사용자명)를 저장소에 노출하지 않고 암호화된 secrets로 관리
  2. 적절한 권한 설정: SSH 키 파일에 600 권한을 부여하여 SSH가 요구하는 보안 기준 준수
  3. Known Hosts 등록: ssh-keyscan을 통해 대상 서버의 호스트 키를 미리 등록하여 MITM(중간자) 공격 방지

필수 GitHub Secrets:

  • AZURE_SSH_KEY: Azure VM 접속을 위한 private key
  • AZURE_VM_IP: 대상 VM의 IP 주소
  • AZURE_VM_USER: VM 로그인 사용자명

Docker Compose v2 설치

- name: Install Docker Compose v2
run: |
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.29.2/docker-compose-linux-x86_64 \
-o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
docker compose version

GitHub Actions runner에 Docker Compose v2를 명시적으로 설치합니다. 이는 다음과 같은 이점을 제공합니다:

  • 버전 일관성: 특정 버전(v2.29.2)을 사용해 예측 가능한 동작 보장
  • 새로운 문법 지원: docker compose (v2) vs docker-compose (v1) 문법 차이 해결
  • Runner 환경 독립성: 사전 설치된 도구에 의존하지 않음

배포 모드별 전략

Fast 모드 (기본값)

echo "⚡ 빠른 배포 모드 실행..."
docker build -t sk_eco_base:latest -f environments/Dockerfile.base .
docker compose -f environments/docker-compose.yml build
docker compose -f environments/docker-compose.yml up -d --remove-orphans
docker image prune -f

특징:

  • Docker 빌드 캐시 활용으로 빠른 배포
  • 변경된 레이어만 재빌드
  • 사용하지 않는 dangling 이미지만 정리
  • 일반적인 코드 업데이트에 적합

사용 시나리오:

  • 소스 코드 수정 반영
  • 의존성 변경이 없는 일상적인 배포
  • 개발 환경의 빈번한 업데이트

Clean 모드

echo "🧹 깨끗한 재배포 모드 실행..."
docker compose -f environments/docker-compose.yml down --remove-orphans
docker system prune -af --volumes

docker build -t sk_eco_base:latest -f environments/Dockerfile.base .
docker compose -f environments/docker-compose.yml build --no-cache
docker compose -f environments/docker-compose.yml up -d

docker builder prune -af

특징:

  • 모든 컨테이너, 이미지, 볼륨, 네트워크 제거
  • --no-cache 옵션으로 완전한 재빌드
  • 빌드 캐시까지 삭제
  • 환경을 완전히 초기화

사용 시나리오:

  • 의존성 패키지 메이저 업데이트
  • 원인 불명의 빌드 오류 해결
  • 프로덕션 환경의 정기 클린업
  • 캐시 손상으로 인한 문제 해결

원격 배포 실행 흐름

ssh -i ~/.ssh/azure_vm_key.pem ${{ secrets.AZURE_VM_USER }}@${{ secrets.AZURE_VM_IP }} << 'EOF'
set -e # 에러 발생 시 즉시 중단
cd /home/${{ secrets.AZURE_VM_USER }}/sk-eco-rag-pipeline
git pull origin main
# ... 배포 스크립트 실행
EOF

SSH를 통해 원격 서버에서 다음 작업을 수행합니다:

  1. 코드 업데이트: git pull로 최신 코드 가져오기
  2. 베이스 이미지 빌드: 공통 의존성을 포함한 base 이미지 먼저 빌드
  3. 서비스 이미지 빌드: Docker Compose를 통해 나머지 서비스 빌드
  4. 컨테이너 실행: up -d로 백그라운드에서 서비스 시작
  5. 정리 작업: 미사용 이미지/빌드 캐시 제거로 디스크 공간 확보

set -e 옵션을 통해 중간에 오류가 발생하면 즉시 배포를 중단하여 부분적으로 배포된 상태를 방지합니다.

개선 가능한 영역

문서에서 명시된 것처럼 Dockerfile 최적화는 별도로 수행되지 않았습니다. 향후 개선 가능한 영역은 다음과 같습니다:

  • 멀티 스테이지 빌드: 최종 이미지 크기 감소
  • 레이어 캐싱 최적화: 의존성 설치와 소스 코드 복사 순서 조정
  • Health Check 통합: 컨테이너 시작 후 서비스 가용성 확인
  • 롤백 메커니즘: 배포 실패 시 이전 버전으로 자동 복구
  • 슬랙/이메일 알림: 배포 성공/실패 알림 시스템
  • Blue-Green 배포: 무중단 배포를 위한 전략 도입

실무 적용 시 고려사항

이 파이프라인을 다른 프로젝트에 적용할 때 고려해야 할 사항:

  1. 환경 변수 관리: .env 파일이나 secrets를 통한 환경별 설정 분리
  2. 로그 관리: 컨테이너 로그를 중앙화된 로깅 시스템으로 전송
  3. 모니터링: 배포 후 서비스 메트릭 모니터링 체계 구축
  4. 백업 전략: 볼륨 데이터에 대한 정기 백업 계획
  5. 보안 스캔: 이미지 취약점 스캔을 CI 파이프라인에 통합

References