업데이트를 자동화하다 : CI/CD 파이프라인 구축기
지난 글에서 서버를 구축하고, 트러블 슈팅을 거쳐, 모니터링 시스템까지 갖췄습니다. 이제 개발에만 집중하면 될 줄 알았습니다. 하지만 코드를 한 줄 수정하거나, AI 모델을 업데이트할 때마다 저는 '수동 배포 로봇'이 되어야 했습니다.
- 로컬에서 테스트 코드 돌리기
- Docker 이미지 빌드하기
- Docker Hub에 푸시하기
- 쿠버네티스에 배포 명령 내리기
이 과정은 매번 10분 이상 소요되었고, 명령어 하나라도 실수하면 에러가 났습니다.
특히 코드 한줄이라도 업데이트할 때마다 이 지루한 과정을 반복하는 건 너무 비효율적이었습니다.
"나는 AI 로직을 고민하고 싶은데, 배포 스크립트와 씨름하느라 시간을 다 쓰고 있다."
저 뿐만이 아니라 모든 팀원이 느꼈습니다. 이것이 CI/CD를 도입하게 된 결정적인 이유였습니다.
목표: "Git Push가 곧 배포다"
제 목표는 단순했습니다.
"Github의 develop 브랜치에 코드를 푸시(Push)하면, 나머지는 알아서 다 해줘."
테스트, 빌드, 이미지 생성, 쿠버네티스 배포까지의 모든 과정을 자동화하여, 개발자가 인프라 걱정 없이 코드 작성에만 몰입할 수 있는 환경을 만드는 것입니다.
도구 선택: 왜 Github Actions인가?
CI/CD 도구로는 Jenkins, CircleCI 등 여러 가지가 있습니다. 하지만 저는 Github Actions를 선택했습니다.
- 접근성: 별도의 CI 서버를 구축할 필요 없이 Github 레포지토리 내에서 바로 설정 가능합니다.
- 비용: Public Repository는 무료이며, 충분한 성능을 제공합니다.
- 통합: 코드 저장소와 파이프라인이 한곳에 있어 관리가 용이합니다.
혼자서 AI 모델링부터 백엔드, 인프라까지 다루는 상황에서 '관리 포인트'를 줄이는 것이 최우선이었습니다.
파이프라인 설계: 빌드부터 배포까지
.github/workflows/deploy.yml 파일을 작성하여 전체 과정을 자동화했습니다. 단순히 스크립트를 나열하는 것이 아니라, 멀티 아키텍처 빌드와 동적 태깅 전략을 적용했습니다.
name: Build and Deploy AI Server
on:
push:
branches: [ "main" ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. 코드 체크아웃
- uses: actions/checkout@v3
# 2. Docker Buildx 설정 (멀티 아키텍처 빌드용)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# 3. Docker Hub 로그인
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# 4. 이미지 빌드 및 푸시 (Git SHA 태그 사용)
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
# ✅ GKE(amd64)와 로컬(arm64) 모두 지원
platforms: linux/amd64,linux/arm64
push: true
tags: |
choij17/stock-ai-analyze-server:latest
choij17/stock-ai-analyze-server:${{ github.sha }}
# 5. Kubectl 설정
- name: Setup Kubectl
uses: azure/setup-kubectl@v3
- name: Configure Kubeconfig
run: |
echo "${{ secrets.KUBECONFIG }}" | base64 -d > kubeconfig
export KUBECONFIG=./kubeconfig
# 6. 쿠버네티스 배포 (이미지 교체)
- name: Deploy to Kubernetes
run: |
export KUBECONFIG=./kubeconfig
# 방금 빌드한 이미지(Git SHA)로 교체
kubectl set image deployment/stock-analyze-deployment \
server=choij17/stock-ai-analyze-server:${{ github.sha }} \
--namespace=default
# 롤링 업데이트 상태 확인 (타임아웃 5분 설정)
kubectl rollout status deployment/stock-analyze-deployment \
--namespace=default \
--timeout=5m
실무 설정: Secret 관리와 이미지 태그 전략
Github Secrets 설정 (보안)
워크플로우 파일에 비밀번호나 인증 정보를 하드코딩할 수는 없습니다. Github Repository Settings의 Secrets 기능을 이용해 안전하게 주입했습니다.
- DOCKER_USERNAME / DOCKER_PASSWORD: Docker Hub 인증 정보
- KUBECONFIG: 쿠버네티스 클러스터 접속 정보 (base64 인코딩)
Tip: 로컬의 kubeconfig 파일을 Github Secret에 넣을 때는 base64로 인코딩해서 넣어야 줄바꿈 깨짐 등을 방지할 수 있습니다.
cat ~/.kube/config | base64
이미지 태그 전략 (Static vs Dynamic)
deployment.yaml 파일에는 기본적으로 image: ...:0.1.17 처럼 고정된 버전이 적혀 있습니다. 하지만 CI/CD 파이프라인에서는 Git Commit Hash (${{ github.sha }})를 태그로 사용했습니다.
- 이유: 매번 v1, v2 버전을 수동으로 올리는 것은 번거롭고 실수하기 쉽습니다. Git SHA를 사용하면 '어떤 코드가 배포되었는지' 확실하게 추적할 수 있고, 문제 발생 시 특정 시점으로 되돌리기가 매우 쉽습니다.
- 적용: kubectl set image 명령어를 통해 실행 중인 Pod의 이미지를 동적으로 교체합니다.
문제 : 아키텍처의 벽 (AMD64 vs ARM64)
파이프라인 구축 초기, 로컬(Mac, ARM64)에서 빌드해서 잘 돌아가던 이미지가 GKE 노드(Intel/AMD, AMD64)에 배포되자마자 실행되지 않고 죽는 exec format error가 발생했습니다.
해결 : Docker의 Buildx
이를 해결하기 위해 Docker의 Buildx 기능을 도입했습니다. 위 코드의 platforms: linux/amd64,linux/arm64 설정이 핵심입니다. 이 설정 덕분에 제 맥북에서 빌드하든, Github Actions 서버에서 빌드하든 상관없이 GKE 서버에서 완벽하게 돌아가는 호환성 높은 이미지를 만들 수 있게 되었습니다.
결과 : 배포 자동화로 얻은 자유
이제 저는 코드를 수정하고 git push만 누르면 됩니다.
Github Actions가 자동으로 테스트를 돌리고, 멀티 아키텍처 이미지를 빌드하고, GKE 클러스터에 배포까지 완료해줍니다.
[배포 스트레스 해방] 이전에는 배포할 때마다 "혹시 명령어 실수해서 서버 죽으면 어떡하지?"라며 긴장해야 했습니다. 하지만 이제는 모든 과정이 스크립트로 자동화되어 사람의 실수가 개입할 여지가 사라졌습니다.
[롤백의 용이성] 만약 배포한 코드에 문제가 생겨도 당황할 필요가 없습니다. 쿠버네티스의 기능을 이용해 명령어 한 줄이면 이전 버전으로 되돌릴 수 있기 때문입니다.
kubectl rollout undo deployment/stock-analyze-deployment
(아직 트래픽이 끊기지 않는 완벽한 무중단 배포 설정은 튜닝이 더 필요합니다. 이는 추후 고도화 과제로 남겨두었습니다.)
지금까지 '데이터 수집 -> 전처리 -> AI 모델링 -> 서버 구축 -> 트러블 슈팅 -> 모니터링 -> CI/CD'로 이어지는 AI 백엔드 개발의 과정을 기록했습니다.
처음에는 단순히 "주린이들에게 도움이 되고 싶어서" 시작했던 프로젝트였습니다. 하지만 이 모델을 실제 사용자가 쓰는 서비스로 만들기 위해 FastAPI로 서버를 띄우고, Docker로 포장하고, Kubernetes로 배포하고, Prometheus로 감시하는 과정을 거치며 '서비스를 지탱하는 전체 아키텍처'를 경험할 수 있었습니다.
이 과정에서 겪은 수많은 에러와 삽질들은 저를 단순한 '코더'에서 '문제를 해결하는 엔지니어'로 성장시켜 주었습니다. 저는 포기하지 않았으니까요.
처음 주식쌤을 만들었을 때의 모습입니다.


실력 좋은 프론트엔드와 작업을 하면서 현재는 이렇게 더 좋은 모습으로 개발되었습니다


2025년 11월 26일부터 실사용자 40명 정도를 받아 운영해 보았는데, 몇 가지 수정할 에러들이 눈에 띄었고 최근 주식 관련 AI 백엔드 현직자분께 고도화할 점과 조언을 받았습니다.

다음 글에서는 "실사용자 피드백을 통해 발견한 버그를 수정하고 서비스를 고도화하는 과정"을 다루겠습니다.
'모의투자' 카테고리의 다른 글
| ~AI가 멍때리지 않게 감시하기 : PLG 모니터링~ 스톡잇! 개발기 #10 (1) | 2025.12.26 |
|---|---|
| ~서버가 로그 없이 죽었다 : 쿠버네티스를 디버거로 쓴 사연~ 스톡잇! 개발기 #9 (1) | 2025.12.26 |
| ~파이썬 AI, 웹 서버가 되다 : MSA와 FastAPI 아키텍처에 대한 고찰~ 스톡잇! 개발기 #8 (0) | 2025.12.26 |
| ~세상의 모든 주식을 분석하다 : 조회에서 예측으로~ 스톡잇! 개발기 #7 (0) | 2025.12.26 |
| ~투자 성향을 캐릭터로 만들다: 페르소나 매칭 설계~ 스톡잇! 개발기 #6 (0) | 2025.12.26 |