본문 바로가기
개발

Kubernetes로 스프링 프로젝트 배포하기

by hxxyeoniii 2025. 10. 3.

Kubernetes(K8s)

> 컨테이너화된 애플리케이션을 자동 배포, 확장, 관리하는 오픈소스 플랫폼

> "컨테이너 오케스트레이션"으로 여러 노드(서버)에 걸쳐 컨테이너를 자동으로 배치하고 관리한다.

 

구성요소

1. Pod : 가장 작은 배포 단위로, 하나 이상의 컨테이너를 포함

2. Node : 컨테이너가 실행되는 물리적 또는 가상 머신

3. Cluster : 여러 노드의 집합으로, 쿠버네티스 환경 전체를 의미

4. Service : Pod에 대한 네트워크 접근을 제공하는 추상화 계층


1. Dockerfile 작성

FROM gradle:8.5-jdk17 AS builder
WORKDIR /app
COPY . .
RUN gradle clean bootJar --no-daemon

RUN echo "=== build/libs 폴더 내용 ==="
RUN ls -la /app/build/libs/
RUN echo "=== 모든 jar 파일 찾기 ==="
RUN find /app -name "*.jar" -type f

FROM eclipse-temurin:17-jre
WORKDIR /app

COPY --from=builder /app/build/libs/*.jar ./app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

 

 

 

2. Kubernetes에 배포하기 위한 매니페스트 파일 생성

 

2.1 backend.yaml

현재 내가 작성한 backend.yaml은 3개의 리소스로 구성되어 있다.

 

1) Deployment : 애플리케이션 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1 # Pod 1개만 실행(실제 프로덕션에서는 2~3개 권장)

 

 

2) Service : 네트워크 접근

apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  selector:
    app: backend # backend Deployment의 Pod 선택
  ports:
  - port: 80 # 서비스 내부 포트
    targetPort: 8080 # Pod의 실제 포트

-> 클러스터 내부에서 backend:80으로 접근

-> 트래픽을 Pod의 8080 포트로 전달

 

3) Ingress : 외부 트래픽 라우팅 (* ingress.yaml을 별도로 빼도 되나 한번에 작성하였다)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: backend
  annotations:
    kubernetes.io/ingress.class: nginx  # NGINX Ingress Controller 사용
spec:
  rules:
    - host: XXX배포 도메인 작성XXX
      http:
        paths:
          - path: /api  # /api로 시작하는 모든 요청
            pathType: Prefix
            backend:
              service:
                name: backend
                port:
                  number: 80

 

 

 

최종 backend.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: backend
        image: XXX도커이미지파일XXX
        ports:
        - containerPort: 8080
        envFrom:
          - configMapRef:
              name: backend-config
---
apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: backend
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: XXX배포 도메인XXX
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: backend
                port:
                  number: 80

 

 

 

 

2.2 kustomization.yaml

resources:
  - backend.yaml # 현재 디렉토리의 backend.yaml을 포함

bases:
  - ../mysql-k8s/base # MySQL 리소스 참조

configMapGenerator:
  - name: backend-config
    literals:
      - SPRING_PROFILES_ACTIVE=prod

-> configMapGenerator로 ConfigMap을 자동 생성해줬다.

-> backend.yaml에서 envForm으로 참조하는 backend-config가 여기서 생성됨 !


3. MySQL 연결 추가하기

 

동작 방식

1) StatefulSet이 Pod 생성

2) PVC 자동 생성 : AWS EBS 볼륨이 자동으로 생성됨

3) Pod가 삭제되어도 데이터 유지 : 새 Pod가 생성되면 같은 볼륨을 다시 마운트

 

 

 

3.1 statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-service # Service 이름과 일치해야 함!!
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:lts
          ports:
            - containerPort: 3306
          env:
            - name: MYSQL_ALLOW_EMPTY_PASSWORD
              value: "true"
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_USER
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_PASSWORD
            - name: MYSQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_DATABASE
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: mysql-data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi
        storageClassName: gp2

 

 

 

3.2 service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  type: ClusterIP
  selector:
    app: mysql
  ports:
    - name: mysql
      port: 3306
      targetPort: 3306

배포 완료

Pod 생성 확인 !!

 

 

 

 

* 전체 배포 파이프라인

Spring Boot 프로젝트 생성

-> Git으로 버전 관리

-> Jenkins 빌드 (Docker 이미지 빌드 후 ECR에 푸시) = CI

-> ArgoCD로 쿠버네티스에 배포 = CD