본문 바로가기
도커&쿠버네티스

[도커/쿠버네티스] 9장 퍼시스턴트 볼륨(PV)과 퍼시스턴트 볼륨 클레임(PVC)

by bzerome240 2022. 3. 8.

DB처럼 포드 내부에 특정 데이터를 보유해야 하는 상태가 있는(Stateful) 애플리케이션에서는 데이터를 어떻게 관리할까?

디플로이먼트를 삭제하면 포드가 삭제되며 포드의 데이터가 함께 삭제된다

-> 해결법: 퍼시스턴트 볼륨, 퍼시스턴트 볼륨 클레임

 


로컬볼륨

 

1) hostPath

: 호스트의 디렉터리를 포드와 공유해 데이터를 저장하는 것

목적: 호스트와 볼륨을 공유하기 위해

 

 

호스트와 디렉터리를 공유하는 포드를 생성하는 YAML

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
    - name: my-container
      image: busybox
      args: [ "tail", "-f", "/dev/null" ]
      volumeMounts:
      - name: my-hostpath-volume
        mountPath: /etc/data
  volumes:
    - name: my-hostpath-volume
      hostPath:
        path: /tmp

volumes 항목에 볼륨 정의 -> containers에서 해당 볼륨을 참조

hostPath를 /tmp를 포드의 /etc/data에 마운트

 

포드생성 후 포드의 컨테이너 내부에 들어가서 /etc/data에 파일을 생성하면 호스트의 /tmp 디렉토리에 파일이 저장된다.

 

But, hostpath를 사용하는 것은 보안 및 활용성 측면에서 바람직하지 않으므로 고려하기

 

2) emptyDir

: 포드가 실행되는 도중에만 필요한 휘발성 데이터를 각 컨테이너가 함께 사용할 수 있도록 임시 저장 공간 생성

목적: 포드의 컨테이너 간에 볼륨을 공유하기 위해

비어있는 상태로 디렉터리가 생성되며, 포드가 삭제되면 저장된 데이터도 함께 삭제된다.

 

 

아파치 웹 서버를 실행하는 포드를 생성하는 YAML

아파치 웹 서버의 루트 디렉터리를 emptyDir에 마운트함과 동시에 이 디렉터리를 컨테이너의 /data 디렉터리와 공유

apiVersion: v1
kind: Pod
metadata:
  name: emptydir-pod
spec:
  containers:
  - name: content-creator
    image: alicek106/alpine-wget:latest
    args: ["tail", "-f", "/dev/null"]
    volumeMounts:
    - name: my-emptydir-volume
      mountPath: /data                      # 1. 이 컨테이너가 /data 에 파일을 생성하면

  - name: apache-webserver
    image: httpd:2
    volumeMounts:
    - name: my-emptydir-volume
      mountPath: /usr/local/apache2/htdocs/  # 2. 아파치 웹 서버에서 접근 가능합니다.

  volumes:
    - name: my-emptydir-volume
      emptyDir: {}                             # 포드 내에서 파일을 공유하는 emptyDir

 

포드생성 후 포드의 컨테이너 내부에 들어가서 /data에 파일을 생성하면 아파치 웹 서버 컨테이너의 htdocs 디렉터리에도 동일하게 파일이 저장된다.

 

다양한 활용법

ex) 깃허브 소스코드를 받아와 emptyDir을 통해 애플리케이션 컨테이너에 공유해주는 사이드카 컨테이너

ex) 설정 파일을 동적으로 갱신하는 컨테이너를 포드에 포함시키기

 


네트워크 볼륨

네트워크 볼륨은 클러스터 내부, 외부 아무데나 존재해도 된다.

ex) NFS, EBS, GlusterFS

 

네트워크 볼륨의 종류는 많기 때문에 데이터의 읽기 쓰기 속도, 마운트 방식, 구축 비용등을 고려하여 적합한 솔루션을 사용하면된다.

 


 

NFS 네트워크 볼륨 특징

  • 여러개의 클라이언트가 동시에 마운트해 사용할 수 있다.
  • 클러스터링하는 솔루션에 비해서는 안정성이 떨어짐
  • 로컬스토리처럼 하나의 서버로만 간편하게 사용 가능

 

NFS 네트워크 볼륨 사용하기

1. NFS 서버와 NFS 클라이언트가 각각 필요하다. 

  • NFS 서버: 영속적인 데이터가 실제로 저장되는 서버
  • NFS 클라이언트: NFS 서버에 마운트해 스토리지에 파일을 읽고 쓰는 역할 (워커 노드의 기능을 사용)

 

2. NFS 서버를 위한 디플로이먼트 생성하기

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-server
spec:
  selector:
    matchLabels:
      role: nfs-server
  template:
    metadata:
      labels:
        role: nfs-server
    spec:
      containers:
      - name: nfs-server
        image: gcr.io/google_containers/volume-nfs:0.8
        ports:
          - name: nfs
            containerPort: 2049
          - name: mountd
            containerPort: 20048
          - name: rpcbind
            containerPort: 111
        securityContext:
          privileged: true

 

3. NFS 서버를 위한 서비스 생성하기

apiVersion: v1
kind: Service
metadata:
  name: nfs-service
spec:
  ports:
  - name: nfs
    port: 2049
  - name: mountd
    port: 20048
  - name: rpcbind
    port: 111
  selector:
    role: nfs-server

 

4. NFS서버를 컨테이너에 마운트하는 포드 생성하기

apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod
spec:
  containers:
    - name: nfs-mount-container
      image: busybox
      args: [ "tail", "-f", "/dev/null" ]
      volumeMounts:
      - name: nfs-volume
        mountPath: /mnt           # 포드 컨테이너 내부의 /mnt 디렉터리에 마운트합니다.
  volumes:
  - name : nfs-volume
    nfs:                            # NFS 서버의 볼륨을 포드의 컨테이너에 마운트합니다.
      path: /
      server: {NFS_SERVICE_IP}

NFS 서버의 네트워크 볼륨은 포드 컨테이더의 mountPath에 정의한 경로에 마운트 된다.

ex) /mnt 경로에 파일을 저장하면 실제로는 NFS 서버에 데이터가 저장된다

 


 

퍼시스턴트 볼륨 PV

: 워커 노드들이 네트워크상에서 스토리지를 마운트해 영속적으로 데이터를 저장할 수 있는 볼륨

ex) NFS, EBS, GlusterFS

 

 

퍼시스턴트 볼륨 클레임 PVC

: 포드가 데이터를 영송적으로 저장해야하므로 마운트할 수 있는 외부 볼륨이 필요하다는 의미

 

 

PV, PVC를 사용하는 이유

위에서처럼 YAML에 네트워크 볼륨을 명시할경우, 다른 부서에서 사용하거나, 웹상에 공유하게 되면 항상 해당 네트워크 볼륨을 이용해야하기 때문에 만약 다른 서버를 사용하고싶을 경우 별도의 YAML 파일을 만들어야하는 문제가 생긴다.

-> PV, PVC 오브젝트는 포드가 볼륨의 세부적인 사항을 몰라도 볼륨을 사용할 수 있도록 추상화해준다.

 

 

 

PV의 사용 흐름

https://blog.naver.com/alice_k106/221348788068

1. 인프라 관리자는 네트워크 볼륨의 정보를 이용해 퍼시스턴트 볼륨 리소스를 미리 생성해둔다.

2. 개발자는 포드를 정의하는 YAML파일에 퍼시스턴트 볼륨 클레임을 명시하고 생성한다.

3. 쿠버네티스는 PV 속성과 PVC 요구사항이 일치한다면 두 리소스를 매칭시켜 바인드 한다. 포드는 PVC를 사용함으로써 포드의 컨테이너 내부에 볼륨이 마운트된 상태로 생성된다.

 

개발자는 디플로이먼트의 YAML 파일에 볼륨의 상세 스펙을 정의하지 않아도 된다.

 

 

PV, PVC 리소스 출력하기

kubectl get pv, pvc

 


 

AWS에서 EBS를 퍼시스턴트 볼륨으로 생성하기 YAML

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ebs-pv
spec:
  capacity:
    storage: 5Gi         # 이 볼륨의 크기는 5G입니다.
  accessModes:
    - ReadWriteOnce    # 하나의 포드 (또는 인스턴스) 에 의해서만 마운트 될 수 있습니다.
  awsElasticBlockStore:
    fsType: ext4
    volumeID: <VOLUME_ID>

 

사용자(개발자)의 입장이 되어 PVC, 포드 생성하기 YAML

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-ebs-pvc                  # 1. my-ebs-pvc라는 이름의 pvc 를 생성합니다.
spec:
  storageClassName: ""
  accessModes:
    - ReadWriteOnce       # 2.1 속성이 ReadWriteOnce인 퍼시스턴트 볼륨과 연결합니다.
  resources:
    requests:
      storage: 5Gi          # 2.2 볼륨 크기가 최소 5Gi인 퍼시스턴트 볼륨과 연결합니다.
---
apiVersion: v1
kind: Pod
metadata:
  name: ebs-mount-container
spec:
  containers:
    - name: ebs-mount-container
      image: busybox
      args: [ "tail", "-f", "/dev/null" ]
      volumeMounts:
      - name: ebs-volume
        mountPath: /mnt
  volumes:
  - name : ebs-volume
    persistentVolumeClaim:
      claimName: my-ebs-pvc    # 3. my-ebs-pvc라는 이름의 pvc를 사용합니다.

 

 


 

PVC를 사용하면 실제로 볼륨이 어떤 스펙인지는 알 필요가 없지만,

볼륨의 크기가 최소 얼마여야하는지, 여러개의 포드에의해 마운트 될 수 있는지, 읽기 전용으로만 사용할 수 있는지 조건을 맞춰야한다.

-> AccessMode, 볼륨 크기, 스토리지클래스, 라벨 셀렉터

 

 

AccessMode 종류

accessModes kubectl get에서 출력되는 이름 설명
ReadWriteOnce RWO 1:1 마운트 가능, 읽기 쓰기 가능
ReadOnlyMany ROX 1:N 마운트 가능, 읽기 전용
ReadWriteMany RWX 1:N 마운트 가능, 읽기 쓰기 가능

 

 

Recliam Policy 종류

  • Retain : PVC와 연결이 끊기면 Released 상태로 전환된다.
  • Delete : PVC와 연결이 끊기면 PV도 삭제된다.
  • Recyle : PVC와 연결이 끊기면 Available 상태로 전환되고, PV는 재사용이 가능(Deprecated)

 

 

Status 항목을 통해 확인 가능한 PV의 상태 종류

  • Available: 사용 가능한 PV
  • Bound : PVC에 매핑된 PV
  • Released : PVC에 매핑이 해제된 PV

 

 

기본 PV 라이프사이클

  • PV의 Reclaim Policy가 Retain으로 설정
Avaliable -> Bound -> Released

 


 

 

앞서 PVC를 사용하기 위해서 PV가 무조건 선행되어야 한다라고 알아보았다.
PV가 없는 경우 PVC는 할당받지 못하고 PV가 있는지 확인해야하기 때문에 여러 가지 문제가 발생할 수 있다.
k8s에서는 이를 방지하기 위해 Dynamic Provisioning 기능을 제공한다.

 

 

다이나믹 프로비저닝

: PV를 PVC의 요청에 따라 자동으로 생성해주는 기능으로 요구 사항에 맞춰 PV가 생성된다.

 

 

 

요구 사항과 PV의 형태의 따라 StorageClass를 사용할 수 있다.

  1. fast는 SSD, slow는 HDD를 생성하도록 설정
  2. PVC에서는 StorageClass를 명시하여 생성하는데, AccessMode나 Capacity등 조건에 맞는 PV는 존재하지 않는 상태
  3. 조건에 일치하는 새로운 PV가 생성되고 StorageClass에 따라 SSD, HDD가 생성
  4. PVC-PV binding

Dynamic Provisioning을 사용하면 편리하지만 모든 스토리지에서 제공되는 기능이 아니기 때문에 제공 여부를 잘 확인해야 한다.

 

 

728x90
반응형

댓글