Notice
Recent Posts
Recent Comments
Link
관리 메뉴

look-forest

볼륨(Volume)을 활용해 DB 띄워보기 본문

Infra/Kubernetes

볼륨(Volume)을 활용해 DB 띄워보기

studyHub 2026. 2. 1. 17:13

볼륨(Volume)이란?

파드(Pod)가 가진 문제점

파드로 실행 중인 프로그램에 기능이 추가되면, 쿠버네티스는 기존 파드에서 변경된 부분을 수정하지 않고,

새로운 파드를 만들어서 통째로 갈아끼우는 방식으로 교체를 한다. 이게 효율적이라고 생각했기 때문이다.

 

이런 특징 때문에 파드를 교체하면, 기존 파드 내부에 있던 데이터도 같이 삭제되어 버린다.

만약 이 파드가 MySQL을 실행시키는 파드였다면 저장된 데이터도 같이 삭제 돼버린다.

 

따라서 파드 내부에 데이터가 삭제되면 안되는 경우에는 볼륨(Volume)이라는 개념을 활용해야 한다.

 

쿠버네티스의 볼륨(Volume)이란?

볼륨이란 데이터를 영속적으로 저장하기 위한 방법이다.

쿠버네티스의 볼륨은 크게 2가지 종류로 나뉜다.

 

1. 로컬 볼륨

파드 내부의 공간 일부를 볼륨으로 활용하는 방식.

이 방식은 파드가 삭제되는 즉시 데이터도 함께 삭제되기 때문에, 잘 사용하지 않는다.

 

2. 퍼시스턴트 볼륨(Persistent Vloume, PV)

파드 외부의 공간 일부를 볼륨으로 활용하는 방식.

파드가 삭제되는 것과 상관없이 데이터를 영구적으로 사용할 수 있어 주로 사용된다.

쿠버네티스 내부의 공간 일부를 사용하는 경우 (hostPath 타입)
외부 저장소(AWS EBS 등)를 사용하는 경우

 

퍼시스턴트 볼륨 클레임(Persistent Volume Claim, PVC)이란?

실제로는 파드(Pod)가 퍼시스턴트 볼륨(PV)에 직접 연결할 수 없다.

아래 구조와 같이 퍼시스턴트 볼륨 클레임(PVC)이라는 중개자가 있어야 한다.

퍼시스턴트 볼륨 클레임(PVC)은 파드(Pod)와 퍼시스턴트 볼륨(PV) 사이에서 중개자 역할을 한다.

 

만약 Pod가 PV를 직접 쓴다면? 파드가 죽었을 때, PV에 어떤 새 파드를 연결할지 충돌이 생길 수 있다.

따라서 PVC는 안전장치이자, Pod(short)와 PV(long)의 생명주기를 분리하기 위한 추상화이다.

 

파드는 PV에 직접 연결할 수 없으며, PVC를 통해 필요한 스토리지의 특정 용량과 접근 모드를 요청하고, 

PVC가 적절한 PV에 바인딩되어 연결된다.

 


[예제] 볼륨(Volume)을 활용해 MySQL 실행시키기

1. 퍼시스턴트 볼륨(PV), 퍼시스턴트 볼륨 클레임(PVC) 정의하기

apiVersion: v1
kind: PersistentVolume

# PersistentVolume 기본 정보
metadata:
  name: mysql-pv # PersistentVolume 이름

# PersistentVolume 세부 정보
spec:
  storageClassName: my-storage # PV와 PVC의 storageClassName이 같다면 볼륨이 연결된다.
  capacity: 
    storage: 1Gi # 볼륨이 사용할 용량을 설정
  accessModes:
    - ReadWriteOnce # 아래 hostPath 타입 활용 시 이 옵션만 사용 가능
  hostPath: # hostPath 타입을 활용 (hostPath : 쿠버네티스 내부 공간을 활용)
    path: "/mnt/data" # 쿠버네티스 내부의 공간에서 /mnt/data의 경로를 볼륨으로 사용
  • 저장한 경로 지정
apiVersion: v1
kind: PersistentVolumeClaim

# PersistentVolumeClaim 기본 정보
metadata:
  name: mysql-pvc # PersistentVolumeClaim 이름
  
# PersistentVolumeClaim 세부 정보
spec:
  storageClassName: my-storage # PV와 PVC의 storageClassName이 같다면 볼륨이 연결된다.
  accessModes:
    - ReadWriteOnce # 볼륨에 접근할 때의 권한
  resources: # PVC가 PV에 요청하는 리소스의 양을 정의
    requests: # 필요한 최소 리소스
      storage: 1Gi # PVC가 PV에 요청하는 스토리지 양 (PV가 최소 1Gi 이상은 되어야 한다.)

 

2. 디플로이먼트에 반영

apiVersion: apps/v1
kind: Deployment

# Deployment 기본 정보
metadata:
  name: mysql-deployment # Deployment 이름

# Deployment 세부 정보
spec:
  replicas: 1 # 생성할 파드의 복제본 개수
  selector:
    matchLabels:
      app: mysql-db # 아래에서 정의한 Pod 중 'app: backend-app'이라는 값을 가진 파드를 선택

  # 배포할 Pod 정의
  template:
    metadata:
      labels: # 레이블 (= 카테고리)
        app: mysql-db
    spec:
      containers:
        - name: mysql-container # 컨테이너 이름
          image: mysql # 컨테이너를 생성할 때 사용할 이미지
          ports:
            - containerPort: 3306  # 컨테이너에서 사용하는 포트를 명시적으로 표현
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-root-password
            - name: MYSQL_DATABASE
              valueFrom:
                configMapKeyRef:
                  name: mysql-config
                  key: mysql-database
          # 컨테이너 내에서 어떤 경로를 볼륨으로 사용할 지 지정
          volumeMounts:
	          - name: mysql-persistent-storage # 밑에서 설정할 volumes.name과 값이 같아야 함
	            mountPath: /var/lib/mysql # mysql 컨테이너 내부에 있는 경로
      # 파드가 사용할 볼륨을 지정
      volumes:
	      - name: mysql-persistent-storage # 위에서 설정할 volumeMounts.name과 일치해야 함
	        persistentVolumeClaim:
	          claimName: mysql-pvc # 연결시킬 PVC의 name과 동일해야 함
  • PVC의 spec에 PV 정보 기입
  • Deployment의 spec에 PVC 정보 기입
  • 마운트할 경로 지정

3. 매니페스트 파일 반영

$ kubectl apply -f mysql-pv.yaml
$ kubectl apply -f mysql-pvc.yaml
$ kubectl apply -f mysql-deployment.yaml

 

※ 확인

새로운 스키마를 생성하고 디플로이먼트를 재시작해도 스키마가 유지되어 있다.

$ kubectl rollout restart deployment mysql-deployment

 

 

※ 볼륨 생성 시 CrashLoopBackOff 발생 원인

더보기

볼륨 생성 시 오류가 발생하고, 반복적으로 재기동시마다 오류가 발생한 것인데, 근본 원인은 마운트할 공간이 부족해서였다.

 

PV의 hostPath: /mnt/data가 Docker Desktop 환경에서 135MB짜리 작은 ext4(/dev/sdd)에 매핑돼 있었고,
MySQL이 그 위에 /var/lib/mysql을 마운트하면서 init 시 디스크 부족(OS error 28)이 난 것.
그래서 MySQL 초기화가 실패 → 잔해 파일 생성 → CrashLoop가 반복됐다.

 

/mnt/data가 “작은 특수 파일시스템”에 매핑돼 있었고, 그 위에 MySQL이 올라가면서 디스크 부족이 발생한 것.

그래서 hostPath를 /var/lib/mysql-data 로 변경해줬더니 정상 실행되었다.


[예제] 백엔드(Spring Boot) 서버와 MySQL 연동하기

이미 MySQL 서버는 띄워진 상황이다. 백엔드 서버와 연결하는 방법을 알아보자.

1. application.yml에 DB 연결을 위한 정보 작성

spring:
  datasource:
    url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
    driver-class-name: com.mysql.cj.jdbc.Driver

 

2. 스프링 서버를 띄우기 위한 매니페스트 파일 작성 후 실행

어떤 host와 port로 연결하는지에 주목하자.

Service의 name만 입력하면 다른 서비스와 통신할 수 있다.

 

왜 30002번 포트가 아닌 3306 포트로 연결하는 것일까?

 

구조

쿠버네티스 외부에서 접속하는게 아니라, 내부에서 파드가 직접 mysql 서비스로 연결하기 때문이다.


보안을 위해 외부에서 MySQL 접근하지 못하도록 막기

기존 구성의 보안적인 문제점

30002번 포트로 MySQL에 직접적으로 접근할 수 있게끔 보안이 설정되어 있는 점이 문제다.

Service의 NodePort를 활용해 30002번 포트를 외부로 오픈해서 MySQL에 아무나 접근할 수 있는 것이다.

 

서비스의 종류 복습

  • NodePort : 쿠버네티스 내부에서 해당 서비스에 접속하기 위한 포트를 열고 외부에서 접속 가능하도록 한다.
  • ClusterIP : 쿠버네티스 내부에서만 통신할 수 있는 IP 주소를 부여. 외부에서는 요청할 수 없다.
  • LoadBalancer : 외부의 로드밸런서(AWS의 로드밸런서 등)를 활용해 외부에서 접속할 수 있도록 연결한다.

보안적인 문제점 해결

보안적인 문제점 해결을 위해 Service의 종류 중 NodePort를 사용하지 않고 ClusterIP를 활용해야 한다.

ClusterIP를 활용함으로써 외부에서 아무나 MySQL에 접근하지 못하게 막아야 한다.

 

구조

외부에서 DB에 접근하지 못하게 막고, 내부에서만 접근할 수 있게 한다.

 

DB를 관리하기 위해 접속해야 할 때는?

그런데 DB 관리를 위해 DataGrip 등 DB 툴을 써서 접근해야 할 때가 있다.

기존의 30002번 포트는 막아놔서, 해당 포트로는 DB 연결이 안된다.

 

이럴 때는 쿠버네티스의 포트 포워딩을 활용해서 접속하면 된다.

Port Forwarding은 로컬 머신의 포트를 클러스터 내부 파드의 포트에 연결하여 외부 노출 없이 안전하게 내부 서비스에 접근할 수 있도록 해주는 유용한 방법이다.

 

아래의 포트 포워딩 명령어를 사용하면 내 로컬 컴퓨터에서만 해당 파드와 연결을 허용시킬 수 있게 된다.

$ kubectl port-forward pod/[MySQL 파드명] 3306:3306

 

쿠버네티스를 실행한 내 로컬 컴퓨터에서는 접근이 가능하도록 포트 포워딩

 

DB tool 연결도 잘 된다.


참고 자료 & 이미지 출처
비전공자도 이해할 수 있는 쿠버네티스 입문/실전