[CI/CD] GitHub Actions를 활용한 자동화 파이프라인 구축
지금까지는 코드를 수정할 때마다 개발자가 직접 docker build를 실행하고 이미지를 Docker Hub에 푸시한 뒤,
클러스터에서 수동으로 배포를 했을 것이다.
하지만 서비스 규모가 커지고 배포 빈도가 늘어나면 이런 수동 작업은 점점 비효율적이고 실수 가능성이 높아진다.
그래서 이번 프로젝트에서는 GitHub Actions를 이용해 코드를 푸시하면 자동으로
빌드 → 테스트 → Docker 이미지 푸시 → GitOps 리포지토리 업데이트까지
이어지는 완전 자동화 CI/CD 파이프라인을 구성했다.
🧱 1. CI/CD란?
| CI (Continuous Integration) | 지속적 통합 | 코드를 변경할 때마다 자동으로 빌드·테스트를 실행해 코드 품질을 유지 |
| CD (Continuous Deployment) | 지속적 배포 | 빌드된 결과물을 자동으로 배포 환경에 반영 |
이번 프로젝트에서는 이 두 가지를 모두 구현한다:
코드가 main 브랜치에 push될 때마다 자동 빌드 & 테스트 (CI)
자동으로 Docker 이미지를 빌드하고 Docker Hub에 푸시 (CD 1단계)
GitOps 레포지토리(lunch-gitops)를 업데이트하여 ArgoCD가 자동으로 쿠버네티스에 배포 (CD 2단계)
🛠️ 2. Dockerfile을 이용한 이미지 빌드 자동화
CI/CD 파이프라인에서 가장 중요한 건 “코드를 실행 가능한 이미지로 만드는 과정”이다.
백엔드(Spring Boot)와 프론트엔드(React)는 각각 별도의 Dockerfile로 관리한다.
📁 백엔드: Dockerfile.backend
# ---------- build ----------
FROM gradle:8.7-jdk21 AS build
WORKDIR /app
COPY . .
RUN chmod +x gradlew
RUN ./gradlew bootJar -x test
# ---------- run (with chromium) ----------
FROM eclipse-temurin:21-jre-jammy
# ✅ Chrome + 필수 라이브러리 설치
RUN apt-get update && \
apt-get install -y wget gnupg ca-certificates fonts-noto-cjk \
libnss3 libxss1 libgbm1 libasound2 libatk-bridge2.0-0 libgtk-3-0 libdrm2 libxshmfence1 && \
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \
apt-get update && apt-get install -y google-chrome-stable && rm -rf /var/lib/apt/lists/*
ENV CHROME_BIN=/usr/bin/google-chrome
WORKDIR /app
COPY --from=build /app/build/libs/*.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]
✅ 포인트
Gradle 이미지에서 JAR를 빌드한 뒤, 실제 런타임 환경에는 JDK 대신 JRE만 포함시켜 경량화
Selenium 크롤러 실행을 위해 Chrome 및 관련 라이브러리를 이미지 안에 포함
📁 프론트엔드: Dockerfile.frontend
# ---------- build ----------
FROM node:20-alpine AS build
WORKDIR /app
COPY src/main/front/package*.json ./
RUN npm ci
COPY src/main/front/ ./
# API 요청 기본 경로 설정
ARG REACT_APP_API_BASE=/api
ENV REACT_APP_API_BASE=${REACT_APP_API_BASE}
RUN npm run build
# ---------- run ----------
FROM nginx:1.25-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
✅ 포인트
React 앱을 빌드하여 정적 파일 형태로 서빙
nginx.conf에서 /api 경로를 백엔드로 프록시 설정 → 프론트-백엔드 통신 문제 해결
🔄 3. GitHub Actions로 CI/CD 자동화
Dockerfile만 준비되면, 이제 남은 건 푸시 → 빌드 → Docker Hub 업로드 → GitOps 업데이트를 자동화하는 일이다.
이를 담당하는 것이 .github/workflows/deploy.yml(아래 예제)이다.
⚙️ GitHub Actions 설정 (.github/workflows/deploy.yml)
name: Build & Push (Docker Hub) & Update GitOps
on:
push:
branches: [ "main" ]
workflow_dispatch: {} # 수동 실행도 가능
env:
IMAGE_BACKEND: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/lunch-backend
IMAGE_FRONTEND: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/lunch-frontend
GITOPS_REPO: ${{ secrets.GITOPS_REPO }}
KUSTOMIZE_PATH: base
🏗️ 백엔드 이미지 빌드 & 푸시
jobs:
build-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build & Push Backend Image
run: |
docker build -f Dockerfile.backend -t $IMAGE_BACKEND:${{ github.sha }} .
docker tag $IMAGE_BACKEND:${{ github.sha }} $IMAGE_BACKEND:latest
docker push $IMAGE_BACKEND:${{ github.sha }}
docker push $IMAGE_BACKEND:latest
✅ 이 단계에서 하는 일
코드를 체크아웃하고
Docker Hub에 로그인한 다음
백엔드 이미지를 빌드하고 latest 및 커밋 해시 태그로 푸시한다.
🏗️ 프론트엔드 이미지 빌드 & 푸시
build-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build & Push Frontend Image
run: |
docker build -f Dockerfile.frontend \
--build-arg REACT_APP_API_BASE="/api" \
-t $IMAGE_FRONTEND:${{ github.sha }} .
docker tag $IMAGE_FRONTEND:${{ github.sha }} $IMAGE_FRONTEND:latest
docker push $IMAGE_FRONTEND:${{ github.sha }}
docker push $IMAGE_FRONTEND:latest
✅ 이 단계에서 하는 일
프론트엔드 React 앱을 빌드
Docker Hub로 자동 업로드
🔁 GitOps 저장소 자동 업데이트
CI/CD의 마지막 단계는 ArgoCD가 자동으로 반영할 수 있도록 GitOps 저장소를 업데이트하는 것이다.
update-gitops:
needs: [ build-backend, build-frontend ]
runs-on: ubuntu-latest
steps:
- name: Clone GitOps repo
uses: actions/checkout@v4
with:
repository: ${{ env.GITOPS_REPO }}
token: ${{ secrets.GITOPS_TOKEN }}
path: gitops
- name: Update image tags in kustomization.yaml
run: |
cd gitops/${{ env.KUSTOMIZE_PATH }}
yq -i "(.images[] | select(.name == \"$IMAGE_BACKEND\")).newTag = \"${{ github.sha }}\"" kustomization.yaml
yq -i "(.images[] | select(.name == \"$IMAGE_FRONTEND\")).newTag = \"${{ github.sha }}\"" kustomization.yaml
- name: Commit & Push changes
run: |
cd gitops
git config user.name "github유저이름"
git config user.email "github이메일"
git add -A
git commit -m "Update images to $GITHUB_SHA" || echo "✅ No changes"
git push
✅ 이 단계에서 하는 일
GitOps 저장소(lunch-gitops)를 클론 (이 내용은 다음 게시글)
kustomization.yaml 내 이미지 태그를 최신 SHA로 업데이트
커밋 & 푸시 → ArgoCD가 이를 감지하고 자동 배포
'2025 현대오토에버 모빌리티 SW 스쿨(클라우드 2기) > 미니프로젝트' 카테고리의 다른 글
| [클라우드] GitOps + ArgoCD를 이용한 EC2 배포 과정 (+HA) (0) | 2025.09.30 |
|---|---|
| [React] 프론트엔드 설계 (0) | 2025.09.27 |
| [Spring Boot] 백엔드 설계 (0) | 2025.09.27 |
| [프로젝트 설계] 주제 선정 및 프로젝트 설계 (0) | 2025.09.27 |