kubernetes Volume

EBAB!·2023년 7월 25일
0

kubernetes

목록 보기
8/9

쿠버네티스도 결국 컨테이너로 실행되므로 도커와 비슷한 문제점을 가집니다. 컨테이너 삭제 시 컨테이너 내부 데이터가 사라지게 됩니다.

도커에서는 데이터를 저장할 컨테이너를 만들거나 호스트에 바인드마운트 하는 방식, 클라우드의 DB서비스에 접근하는 방식 등이 있었습니다.
도커 또는 컴포즈를 이용한다는 것은 결국 어떤 어플리케이션이 머신에서 실행된다는 것이고, 저장되는 방식이 어찌되었든 머신 어딘가에 저장되는 것은 분명합니다.

쿠버네티스는 도커와 다르게 더 유연한 볼륨을 가집니다. 쿠버네티스는 다양한 드라이버와 유형이 있어 데이터가 저장되는 위치를 완벽하게 제어할 수 있습니다.
예를 들어, AWS, 자체 데이터 센터 등 어디든 데이터 저장 방법을 제시할 수 있고, 나아가 어떤 클라우드 프로바이더의 서비스를 사용할지, 특정 머신의 하드 드라이브에 저장할지 가능합니다.

쉽게 말해, 도커 볼륨 시스템을 어느정도 활용하지만 더 많은 기능과 구성 옵션을 가지고 있습니다.

약간의 차이라면, 도커에선 컨테이너의 삭제가 데이터의 삭제가 되었지만, 쿠버네티스는 컨테이너가 중지, 삭제되더라도 데이터는 유지합니다.

Pod의 삭제에서만 내부데이터가 삭제됩니다.

공식 문서(https://kubernetes.io/docs/concepts/storage/volumes/)에서 볼 수 있듯이 정말 많은 볼륨 서비스를 제공합니다. 특정 클라우드 프로바이더의 특정 볼륨 서비스를 모두 맞춤으로 작성할 수 있습니다.

Vloume 정의 (.yaml)

컨테이너와 묶이면서 재시작 하더라도 같은 볼륨을 사용해야 하므로 컨테이너와 같은 레벨에 정의하게 됩니다.

# 베이스 yaml 파일

# [deployment.yaml]

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <deployment_name>
spec: 
  replicas: <number>
  selector:
    matchLabels:
      <key>:<value>
  template:
    metadata:
      labels:
       <key>:<value>
    spec:
      containers:
        - name: <container_name>
          image: <image_name> # ex. Sonjh/testimage:1
          
---

# [service.yaml]

apiVersion: v1
kind: Service
metadata:
  name: <service-name>
spec:
  selector: 
    <key>:value
  type: LoadBalancer
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 3000

emptyDir 유형

emptyDir 볼륨은 Pod가 재시작할 때 마다 빈 디렉토리를 생성합니다. Pod가 살아있는 한 활성 상태를 유지하고 데이터로 채웁니다.
단, Pod가 제거되면 같이 제거되고 재생성되면 같이 빈 디렉토리로 생성됩니다.

컨테이너가 재시작 하더라도 살아남는 디렉토리를 제공하는데 초점을 둔 방식입니다.

      containers:
        - name: <container_name>
          image: <image_name> # ex. Sonjh/testimage:1
          volumeMounts:
            - mountPath: <mount-path> # ex. /app/story
              name: <volume-name>
            
      volumes:
        - name: <volume-name>
          emptyDir: {}
              

/app/story 데이터를 mount-path 경로에 저장하고 volume-name라는 이름으로 명명하고, 빈 디렉토리에 저장합니다.


hostPath 유형

만약 replicas가 2개인 경우라면 따로 관리하기가 복잡해지고 그 이상이라면 더 복잡해집니다.
이런 경우 다른 드라이버로 Pod당 새로운 빈 디렉토리를 생성하는 방식을 사용하고 이것이 hostPath 유형입니다.

물론 이 방법으로 여러 노드 시스템의 문제를 해결할 수는 없습니다. 결국 여전히 하나의 호스트 머신에 특정되기 때문입니다. 하지만 복제본으로 작업하는 개발방식에서 emptyDir보다 유용할 수 있습니다.

      containers:
        - name: <container_name>
          image: <image_name> # ex. Sonjh/testimage:1
          volumeMounts:
            - mountPath: <mount-path> # ex. /app/story
              name: <volume-name>
            
      volumes:
        - name: <volume-name>
          hostPath:
            path:<dir-path> # ex. /data
            type: DirectoryOrCreate
              

/app/story 데이터를 mount-path 경로에 저장하고 volume-name라는 이름으로 명명하고, dir-path 디렉토리에 저장하고 없다면 생성합니다.

여기서 dir-path는 호스트의 경로이므로 Pod의 외부에 존재하는 것으로 보면됩니다.


CSI(Container Storage Interface) 유형

이 유형부터는 Pod와 별개로 저장되므로 영구 볼륨(PV, Persistent Volume)이라 불립니다.

위에서는 하나의 호스트에서 진행된다고 했습니다. 이유는 로컬에서의 개발환경, minikube의 구조 때문입니다. minikube는 앞서 얘기한 것처럼 하나의 가상머신에서 마스터노드와 워커노드가 통합된 단일 노드 환경이였기에 가능한 구조였습니다. 이런 단일 노드 환경을 벗어나 다중 노드 환경에서 사용해볼 수 있는 유형입니다.

다중 노드 환경이라면 여러 호스트가 존재하므로 데이터 통합이 더욱 어려워집니다(비효율 상승).
그래서 클라우드 프로바이더를 통해 영구적이고 개별적인 데이터 저장소를 활용해볼수 있습니다.
AWS EBS, AzureDisc, AzureFile, NFS 등이 있습니다.

아래 파일에 대한 자세한 설명은 공식 문서를 참고하면 됩니다.
공식 문서: https://kubernetes.io/docs/concepts/storage/persistent-volumes/

# [host-pv]

apiVersion: v1
kind: PersistentVolume
mratadatra:
  name: <host-name> # ex. host-hv
spec:
  capacity:
    storage: <storage-size> # ex. 1Gi
  volumeMode: <mode> ex. Block or Filesystem
  accessModes:
    - ReadWriteOnce # 단일 노드에 의한 읽기/쓰기 볼륨으로 마운트. 여러 Pod에서 수행, 모두 동일한 노드
    - ReadOnlyMany # 읽기 전용, 여러 노드에서 요청 가능(서로 다른 노드의 여러 Pod가 동일한 영구 볼륨 요청 가능)
    - ReadWriteMany # 여러 노드에 의한 읽기/쓰기 볼륨으로 마운트.
  hostPath:
    path: <dir-path> # ex. /data
    type: DirectoryOrCreate

VM 내부의 파일시스템에 폴더가 있기 때문에 로컬에서는 volumeMode에서 Filesystem 사용

로컬에선 ReadWriteOnce 사용 (minikube는 단일 노드이므로)

PVC (Persistent Volume Clame)

CSI로 PV를 정의했다면 이것을 클러스터가 알아야하고 Pod가 PV에 도달하여 볼륨을 얻을 수 있도록 해야합니다.

클레임은 볼륨을 사용하려는 Pod에서 만들어야 합니다. 이 구성을 위해 클레임을 구성하고, 호스트 영구 볼륨을 위한 yaml파일을 추가해야 합니다.

그리고 쿠버네티스에 스토리지 클래스 개념이 있고 minikube에는 standard라는 디폴트 스토리지 클래스가 있습니다. 일반적으로 사용하기 좋은 스토리지 클래스이므로 standard를 사용합니다.

# [host-pvc.yaml]

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: <claim-name> # ex. host-pvc
spec:
  volumeName: <used to PV-name> # CSI yaml파일의 <host-name>
  storageClassName: standard # minikube의 스토리지클래스
  accessModes:
    - ReadWriteOnce # 공식문서에서 더 유연하고 다양한 모드 참고
  resource:
    requests:
      storage: 1Gi # capacity에게 요청. 즉, capacity가 가진 용량이 요청 최대 용량

그리고 deployment.yamlvolumes도 이에 맞게 작성되어야 합니다.
이전에 hostPath를 사용해서 호스트를 볼륨으로 사용했다면 이제 PVC로 바꿔줍니다(Pod와 PV를 연결해주는 다리가 PVC이니까).

  hostPath:
    path: <dir-path> # ex. /data
    persistentVolumeClaim:
      claimName: <claim-name> # 위 예시에 맞추면 `host-pvc`

이제 다음 순서로 적용할 수 합니다.

1.kubectl apply -f host-pv.yaml : PV 생성
2. kubectl apply -f host-pvc.yaml : PVC 적용
3. kubectl apply -f deployment.yaml : 볼륨 설정을 PVC로 설정하여 적용
4. kubectl get pvc & kubectl get deployments : 적용 확인



단순하게 작동하는 작은 앱이라면 PV까지 사용하지 않아도 될 것입니다. 하지만 규모가 커지거나, 작지만 수평 확장을 고려한다면 영구 볼륨을 사용하는 것이 좋습니다.

그러므로 자신에게 맞는 형태를 생각하면서 선택하여 볼륨을 사용해야 합니다.

profile
공부!

0개의 댓글