본문으로 건너뛰기
버전: 1.0.3

6.1. 스토리지

어떨 때 보는가

  • 데이터베이스나 파일 저장이 필요한 애플리케이션을 배포할 때
  • 파드가 Pending 에서 넘어가지 않을 때
  • 저장 공간이 모자랄 때

컨테이너의 저장 공간 문제

컨테이너는 이미지에서 만들어지고, 안에서 파일을 고쳐도 그 변경은 컨테이너가 사라지면 함께 사라집니다.

상황컨테이너 안의 파일
애플리케이션이 다시 시작사라집니다
파드가 다른 노드로 이동사라집니다
새 버전 배포사라집니다

이 성질은 의도된 것 입니다. 어느 컨테이너를 띄워도 같은 상태에서 시작하므로 배포가 단순해집니다.

하지만 데이터베이스처럼 남겨야 하는 데이터가 있으면 곤란합니다. 그래서 컨테이너 밖에 있는 저장 공간을 안에 붙여 씁니다.

볼륨이란

컨테이너에 붙이는 저장 공간을 볼륨 이라고 합니다. 컨테이너의 특정 경로에 붙이면(마운트) 그 경로에 쓴 파일이 볼륨에 저장됩니다.

볼륨에는 여러 종류가 있습니다.

종류수명쓰임
emptyDir파드와 함께 사라짐컨테이너끼리 파일을 주고받을 때
ConfigMap · Secret설정과 함께설정 파일 주입 (3.4 장)
PersistentVolume파드와 무관하게 유지데이터 보관

이 장에서 다루는 것은 세 번째입니다.

PV 와 PVC 로 나눈 이유

Kubernetes 는 저장 공간을 두 자원으로 나눕니다.

자원누가 다루나무엇을 담나
PersistentVolume (PV)운영 담당자실제 저장 공간. 어느 저장 장치의 어느 영역인지
PersistentVolumeClaim (PVC)애플리케이션 담당자요청. 얼마나 필요한지

나눈 이유는 관심사가 다르기 때문 입니다.

애플리케이션을 배포하는 사람은 "10GB 가 필요하다" 만 알면 됩니다. 그 10GB 가 NFS 인지 SAN 인지, 어느 서버의 어느 경로인지는 알 필요도 없고 알아서도 곤란합니다. 환경마다 다르기 때문에 그것까지 적으면 같은 배포 정의를 다른 클러스터에 쓸 수 없습니다.

PVC 를 만들면 조건에 맞는 PV 가 자동으로 연결됩니다(바인딩).

저장 공간을 쓰는 방식

저장 공간을 쓰는 방식

PersistentVolumeClaim

스토리지 > 영구 볼륨 클레임 로 들어갑니다.

PVC 목록
설명
이름PVC 이름
네임스페이스속한 네임스페이스
상태Bound 는 연결 완료, Pending 은 대기 중
용량요청한 크기
접근 모드여러 파드가 동시에 쓸 수 있는지
스토리지 클래스어떤 기준으로 공간을 만들지

상세 화면에서 어떤 파드가 이 PVC 를 쓰고 있는지 확인할 수 있습니다. PVC 를 지우기 전에 반드시 확인하십시오.

PVC 는 네임스페이스 단위 자원입니다. 다른 네임스페이스의 파드는 쓸 수 없습니다.

접근 모드

모드쓰는 곳
ReadWriteOnce (RWO)노드 하나에서만 읽기·쓰기데이터베이스. 가장 널리 지원됩니다
ReadOnlyMany (ROX)여러 노드에서 읽기만공용 참조 데이터
ReadWriteMany (RWX)여러 노드에서 읽기·쓰기여러 파드가 같은 파일을 쓸 때

ReadWriteMany 는 지원하는 저장소에서만 됩니다. NFS 계열은 되지만 블록 스토리지는 안 됩니다. 지원하지 않는 클래스에 요청하면 PVC 가 Pending 에 머뭅니다.

ReadWriteOnce PVC 를 쓰는 파드는 한 노드에만 배치됩니다. 그래서 복제본을 여러 노드에 퍼뜨리려면 파드마다 PVC 를 따로 두는 StatefulSet 을 씁니다(3.2 장).

만들고 파드에 붙이기 — YAML

PVC 만들기

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
namespace: my-app
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-client # 스토리지 클래스 화면의 이름
resources:
requests:
storage: 10Gi
항목설명
accessModes위 "접근 모드" 참고. 스토리지 클래스가 지원하는 것만 됩니다
storageClassName스토리지 클래스 화면의 이름을 그대로 씁니다. 생략하면 기본 클래스가 쓰입니다
storage요청 용량. Gi(기가) · Mi(메가)

storageClassName 을 아예 빼는 것과 빈 문자열("")로 두는 것은 다릅니다. 빼면 기본 클래스를 쓰고, 빈 문자열이면 동적 생성을 하지 않고 미리 만들어 둔 PV 를 찾습니다. 없으면 계속 Pending 에 머뭅니다.

파드에 붙이기

볼륨 선언과 마운트 두 곳에 적어야 합니다.

containers:
- name: app
image: registry.example.com/my-app:1.0
volumeMounts:
- name: data # ② 아래 volumes 의 이름
mountPath: /var/lib/app # 컨테이너 안에서 이 경로에 연결됩니다
volumes:
- name: data # ① 파드가 쓸 볼륨
persistentVolumeClaim:
claimName: app-data # PVC 이름

StatefulSet 에서는 다르게 씁니다

복제본마다 저장 공간이 따로 있어야 하면 PVC 를 직접 만들지 않고 템플릿 을 씁니다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
namespace: my-app
spec:
serviceName: db
replicas: 3
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: registry.example.com/db:1.0
volumeMounts:
- name: data
mountPath: /var/lib/db
volumeClaimTemplates: # 복제본마다 PVC 를 하나씩 만듭니다
- metadata:
name: data # volumeMounts 의 이름과 같아야 합니다
spec:
accessModes: [ReadWriteOnce]
storageClassName: nfs-client
resources:
requests:
storage: 20Gi

복제본이 3개면 data-db-0·data-db-1·data-db-2 세 PVC 가 만들어집니다. 파드가 다시 떠도 같은 번호의 PVC 에 다시 연결됩니다 — 그래서 데이터가 유지됩니다.

StatefulSet 을 지워도 이 PVC 들은 남습니다. 실수로 지웠을 때 데이터를 지키려는 설계입니다. 정말 지우려면 PVC 를 따로 지워야 합니다.

용량이 모자랄 때

스토리지 클래스가 확장을 지원하면 용량만 늘려 다시 적용 합니다.

spec:
resources:
requests:
storage: 20Gi # 10Gi → 20Gi

줄이는 것은 되지 않습니다. 늘리기만 됩니다. 확장을 지원하지 않는 클래스면 적용이 거부되므로, 새 PVC 를 만들어 데이터를 옮겨야 합니다.

PersistentVolume

실제 저장 공간입니다. 스토리지 > 영구 볼륨 에서 봅니다.

상태
Available아직 아무 PVC 에도 연결되지 않음
BoundPVC 에 연결되어 사용 중
ReleasedPVC 는 지워졌으나 공간이 아직 정리되지 않음
Failed정리에 실패

PV 는 클러스터 단위 자원입니다. 네임스페이스에 속하지 않아 목록에 다른 팀의 것도 함께 나옵니다.

Released 가 쌓이면 저장소 공간을 계속 차지합니다. 운영 담당자에게 정리를 요청하십시오.

스토리지 클래스란

어떤 방식으로 저장 공간을 만들지 정해 둔 설정입니다. 스토리지 > 스토리지 클래스 에서 봅니다.

스토리지 클래스 목록

클래스마다 성능·비용·기능이 다릅니다. 사용자는 이름만 고르면 됩니다.

항목설명
프로비저너공간을 만드는 담당 구성요소
회수 정책PVC 를 지울 때 데이터를 어떻게 할지
볼륨 바인딩 모드언제 실제 공간을 만들지
기본값PVC 에 클래스를 적지 않으면 쓰이는 클래스

동적 프로비저닝

옛날 방식에서는 운영 담당자가 PV 를 미리 만들어 두어야 했습니다. 개발자가 PVC 를 만들면 그중에서 맞는 것을 골라 연결하는 식입니다.

스토리지 클래스가 있으면 PVC 를 만드는 순간 PV 가 자동으로 만들어집니다. 이것을 동적 프로비저닝이라고 합니다.

정적 (옛 방식)동적
PV 준비운영자가 미리필요할 때 자동
크기미리 정한 것 중에서 선택요청한 만큼
대기 시간맞는 PV 가 없으면 무한 대기곧바로

지금은 대부분 동적 방식입니다. PVC 만 만들면 됩니다.

볼륨 바인딩 모드

모드동작
ImmediatePVC 를 만들면 곧바로 공간을 만듭니다
WaitForFirstConsumer파드가 배치될 노드가 정해진 뒤에 만듭니다

WaitForFirstConsumer 인 클래스에서는 PVC 가 Pending 이어도 정상입니다. 파드를 만들면 그때 연결됩니다.

이 모드가 있는 이유는 이렇습니다. 저장 공간이 특정 노드에만 있는 경우(로컬 디스크), 공간을 먼저 만들면 파드가 그 노드에만 갈 수 있습니다. 노드에 자리가 없으면 파드가 영영 뜨지 못합니다. 파드 배치를 먼저 정하고 그 노드에 공간을 만들면 이 문제가 없습니다.

회수 정책

정책PVC 를 지우면
Delete데이터가 함께 사라집니다
Retain데이터가 남습니다. 수동으로 정리해야 합니다

중요한 데이터에는 Retain 클래스를 쓰십시오. Delete 클래스에서 PVC 를 지우는 것은 되돌릴 수 없습니다.

클래스의 회수 정책을 나중에 바꿔도 이미 만들어진 PV 에는 적용되지 않습니다. 만들기 전에 확인하십시오.

Pending 에서 멈출 때

원인확인할 것
스토리지 클래스 이름이 틀림목록에 있는 이름과 같은지
남은 용량이 부족저장소의 남은 공간
접근 모드를 지원하지 않음ReadWriteMany 를 지원하는 클래스인지
네임스페이스 용량 상한에 걸림관리 > 리소스 할당량 (8.1 장)
볼륨 바인딩 모드가 WaitForFirstConsumer정상입니다. 파드를 만들면 연결됩니다

PVC 상세 화면의 이벤트 에 원인이 남습니다. 먼저 여기를 보십시오.

데이터를 지키려면

  • PVC 를 지우기 전에 쓰는 파드가 있는지 확인하십시오. 상세 화면에서 볼 수 있습니다.
  • Helm 릴리즈를 지워도 PVC 는 남는 경우가 있습니다. 반대로 지워지는 경우도 있으니 중요한 데이터는 미리 백업하십시오(9.1 장).
  • PVC 크기를 늘릴 수는 있어도 줄일 수는 없습니다. 클래스가 크기 변경을 지원해야 하고, 줄이는 것은 어떤 클래스도 지원하지 않습니다.
  • 백업은 Kubernetes 가 자동으로 해 주지 않습니다. 별도 백업 도구나 저장소 자체의 스냅숏 기능을 쓰십시오.