Spring Boot + Kubernetes 배포하기 - 컨테이너 오케스트레이션으로 확장성 확보

Docker를 사용하면 애플리케이션을 컨테이너로 패키징할 수 있지만, 여러 대의 서버와 수많은 컨테이너를 관리하기에는 한계가 있습니다. 이때 등장하는 것이 Kubernetes (쿠버네티스)입니다. 

 

Kubernetes란?

Kubernetes는 Google이 개발하고 CNCF가 관리하는 컨테이너 오케스트레이션 플랫폼입니다. 수십~수백 개의 Docker 컨테이너를 자동으로 배포, 스케일링, 복구하고, 서비스 간 트래픽을 효율적으로 분산시킵니다.

  • Pod: Kubernetes의 최소 실행 단위 (1개 이상의 컨테이너 포함)
  • Deployment: Pod의 배포, 업데이트, 롤백을 관리
  • Service: Pod 간 통신과 외부 노출(Load Balancer) 담당
  • Ingress: 외부 트래픽을 도메인 기반으로 라우팅

 

1. 준비 단계 — Docker 이미지 빌드

먼저 Spring Boot 애플리케이션을 Docker 이미지로 빌드합니다.

./gradlew bootJar
docker build -t springboot-k8s:latest .

이후 Kubernetes 클러스터에서 접근 가능한 Docker Registry(예: Docker Hub, AWS ECR, GCR 등)에 이미지를 푸시합니다.

docker tag springboot-k8s your-dockerhub-id/springboot-k8s:latest
docker push your-dockerhub-id/springboot-k8s:latest

 

2. Deployment 구성

Kubernetes에서 애플리케이션을 실행하기 위해 deployment.yaml 파일을 작성합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-app
  labels:
    app: springboot-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: springboot-app
  template:
    metadata:
      labels:
        app: springboot-app
    spec:
      containers:
        - name: springboot-container
          image: your-dockerhub-id/springboot-k8s:latest
          ports:
            - containerPort: 8080
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "prod"
          resources:
            limits:
              memory: "512Mi"
              cpu: "500m"
            requests:
              memory: "256Mi"
              cpu: "250m"

위 설정은 Spring Boot 컨테이너를 2개(Pod 2개) 실행하고, 자원 제한을 명시하여 안정적인 클러스터 운영을 보장합니다.

 

3. Service 구성

Pod는 동적으로 IP가 변경될 수 있기 때문에, Service를 통해 고정된 접근점을 제공합니다.

apiVersion: v1
kind: Service
metadata:
  name: springboot-service
spec:
  selector:
    app: springboot-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer

Service 타입을 LoadBalancer로 지정하면 클라우드 환경(AWS, GCP 등)에서 자동으로 외부 접근이 가능한 IP 또는 도메인이 생성됩니다.

 

4. Ingress로 도메인 라우팅 (선택 사항)

외부 도메인 이름을 이용해 트래픽을 라우팅하려면 Ingress를 구성합니다.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: springboot-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: demo.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: springboot-service
                port:
                  number: 80

Ingress Controller(Nginx Ingress Controller 등)를 통해, demo.example.com 도메인으로 들어오는 요청을 Spring Boot 서비스로 전달할 수 있습니다.

 

5. 리소스 배포 및 확인

모든 YAML 파일이 준비되면, kubectl 명령으로 Kubernetes에 리소스를 배포합니다.

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml

배포 상태는 아래 명령으로 확인할 수 있습니다.

kubectl get pods
kubectl get svc
kubectl get ingress

Service의 EXTERNAL-IP가 생성되면 해당 주소를 통해 애플리케이션에 접근할 수 있습니다.

 

6. 롤링 업데이트 및 복구

Kubernetes는 Deployment를 이용해 애플리케이션을 무중단으로 업데이트할 수 있습니다.

kubectl set image deployment/springboot-app springboot-container=your-dockerhub-id/springboot-k8s:v2

문제가 발생할 경우, 즉시 이전 버전으로 롤백할 수 있습니다.

kubectl rollout undo deployment/springboot-app

이렇게 Kubernetes는 안정적인 배포와 롤백, 스케일링을 모두 자동으로 처리합니다.

 

7. 오토스케일링 (HPA)

트래픽이 급증할 경우, Horizontal Pod Autoscaler(HPA)를 통해 자동으로 Pod 개수를 늘릴 수 있습니다.

kubectl autoscale deployment springboot-app --cpu-percent=70 --min=2 --max=5

CPU 사용률이 70%를 초과하면 최대 5개까지 Pod를 자동으로 확장합니다.

 

8. ConfigMap과 Secret으로 환경 분리

환경별 설정 값을 외부에서 주입하려면 ConfigMap과 Secret을 활용합니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  SPRING_PROFILES_ACTIVE: prod
  API_URL: https://api.example.com
---
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  DB_USER: admin
  DB_PASSWORD: securepass

Pod에서는 아래처럼 환경 변수로 주입할 수 있습니다.

envFrom:
  - configMapRef:
      name: app-config
  - secretRef:
      name: db-secret

 

주의할 점

  • 클러스터 시간 동기화(NTP) 불일치 시 로그 및 트레이싱 분석 어려움
  • 리소스 요청(requests)과 제한(limits)을 명확히 설정해야 안정적인 스케줄링 가능
  • 이미지 태그 latest 사용은 피하고, 버전 명시(v1, v2 등)로 추적성 확보
  • ConfigMap/Secret은 Git에 직접 커밋하지 않도록 주의
  • Ingress 사용 시 HTTPS 인증서 자동 갱신(Let’s Encrypt + cert-manager) 구성 권장

 


 

Spring Boot 애플리케이션을 Kubernetes에 배포하면, 확장성, 가용성, 복구력을 모두 확보할 수 있습니다. Docker만으로는 어려운 스케일링과 자동 복구를 Kubernetes가 대신 처리하므로, 대규모 트래픽을 다루는 서비스에 필수적인 기술입니다.