emeraldgoose / kubernetes_study

Kubernetes In Action
0 stars 0 forks source link

6장. 볼륨: 컨테이너에 디스크 스토리지 연결 #6

Open emeraldgoose opened 7 months ago

emeraldgoose commented 7 months ago

6.1 볼륨 소개

볼륨은 파드 스펙에서 정의되는 파드의 구성 요소로 다음의 유형들이 존재한다.

emeraldgoose commented 7 months ago

6.2 볼륨을 사용한 컨테이너 간 데이터 공유

가장 간단한 emptyDir 볼륨을 사용하는 예제이다. emptyDir 볼륨은 동일 파드에서 실행 중인 컨테이너 간 파일을 공유할 때 유용하다. emptyDir 볼륨을 사용하기 위해 다음과 같이 매니페스트를 구성한다.

apiVersion: v1
kind: Pod
metadata:
  name:
spec:
  containers:
  - image:
    name:
    volumeMounts: # html이란 이름의 볼륨을 컨테이너의 /var/htdocs에 마운트한다
    - name: html
      mountPath: /var/htdocs
  - image: nginx:alphine
    name:
    volumeMounts: # html이란 이름의 볼륨을 /usr/share/nginx/html에 마운트한다
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: true
    ports:
    - containerPort: 80
      protocol: TCP
volumes: # html이란 단일 emptyDir 볼륨을 위의 컨테이너 두 개에 마운트한다
- name: html
  emptyDir: {}

emptyDir을 디스크가 아닌 메모리를 사용하는 tmpfs 파일시스템으로 생성하도록 요청하려면 emptyDir의 medium을 Memory로 지정한다

volumes:
- name: html
  emptyDir:
    medium: Memory

gitRepo 볼륨은 기본적으로 emptyDir 볼륨이며 파드가 시작되면 깃 리포지터리를 복제하고 특정 리비전을 체크아웃해 데이터로 채운다. 그리고 깃 동기화 프로세스가 Nginx 웹 서버와 동일 컨테이너에서 실행되면 안 되며 사이드카 컨테이너에서 실행돼야 한다.

volumes:
- name: html
  gitRepo:
    repository: https://github.com/path.git
    revision: master # master 브랜치를 체크아웃한다
    directory: . # 볼륨의 루트 디렉터리에 리포지터리를 복제한다
emeraldgoose commented 7 months ago

6.3 워커 노드 파일시스템의 파일 접근

hostPath 볼륨은 노드 파일시스템의 특정 파일이나 디렉터리를 가리킨다. 같은 노드에서 실행중인 파드가 hostPath 볼륨의 동일 경로를 사용 중이라면 같은 파일이 표시된다. 단, hostPath 볼륨을 데이터베이스의 데이터 디렉터리를 저장할 위치로 사용하지 말아야 한다. 데이터베이스 파드가 다시 스케줄링되면 더 이상 이전 데이터를 볼 수 없기 때문이다. 보통 노드의 로그파일이나 kubeconfig(쿠버네티스 구성 파일), CA 인증서를 접근하기 위해 hostPath 볼륨을 사용한다.

emeraldgoose commented 7 months ago

6.4 퍼시스턴트 스토리지 사용

파드에서 실행 중인 애플리케이션이 디스크에 데이터를 유지해야 하고 다른 노드로 재스케줄링되어도 동일한 데이터를 사용하려면 퍼시스턴트 스토리지를 사용해야 한다.

GCE 퍼시스턴트 디스크 볼륨을 사용하려면 다음과 같이 정의한다.

apiVersion: v1
kind: Pod
metadata:
  name:
spec:
  volumes:
  - name: mongodb-data
    gcePersistentDisk:
      pdName: mongodb # 퍼시스턴트 디스크의 이름은 이전에 생성한 퍼시스턴트 디스크의 이름과 일치해야 한다
      fsType: ext4
  containers:
  - image: mongo
    name: mongodb
    volumeMounts:
    - name: mongodb-data
      mountPath: /data/db
  ports:
  - containerPort: 27017
    protocol: TCP

awsElasticBlockStore를 사용하려면 다음과 같이 정의한다.

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  volumes:
  - name: mongodb-data
    awsElasticBlockStore:
      volumeId: my-volume # 생성한 EBS 볼륨의 ID를 지정한다
      fsType: ext4
ontainers:
- ...

nfs 볼륨을 사용하려면 다음과 같이 정의한다.

volumes:
- name: mongodb-data
  nfs:
    server: 1.2.3.4 # NFS 서버의 IP이다
    path: /some/path # 서버의 익스포트된 경로다
emeraldgoose commented 7 months ago

6.5 기반 스토리지 기술과 파드 분리

인프라스트럭처 관련 처리는 클러스터 관리자만의 영역이어야 한다. 먼저, 관리자는 쿠버네티스 API 서버로 퍼시스턴트볼륨 리소스를 생성해 쿠버네티스에 등록한다. 다음, 사용자는 퍼시스턴트볼륨클레임 매니페스트를 쿠버네티스 API 서버에 게시한다. 쿠버네티스는 적절한 퍼시스턴트볼륨클레임을 찾아 클레임에 볼륨을 바인딩한다. 퍼시스턴트볼륨클레임은 파드 내부의 볼륨 중 하나로 사용될 수 있고 퍼시스턴트볼륨클레임의 바인딩을 삭제해 릴리스될 때까지 다른 사용자는 동일한 퍼시스턴트볼륨을 사용할 수 없다.

MongoDB 예제에서 관리자는 퍼시스턴트볼륨을 생성하기 위해 다음과 같이 정의한다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mongodb-pv
spec:
  capacity: # 퍼시스턴트볼륨의 사이즈를 지정한다
    storage: 1Gi
  accessModes: # 이 PV는 단일 클라이언트의 읽기/쓰기용이나 여러 클라이언트를 위한 읽기 전용으로 마운트한다
  - ReadWriteOnce
  - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain # 클레임이 해제된 후 퍼시스턴트볼륨은 유지돼야 한다(삭제되면 안된다)
  gcePersistentDisk: # 퍼시스턴트볼륨은 이전에 생성한 GCE 퍼시스턴트 디스크를 기반으로 한다
    pdName: mongodb
    fsType: ext4

퍼시스턴트볼륨을 생성할 때 관리자는 쿠버네티스에게 용량이 얼마가 되는지 단일 노드나 동시에 다수 노드에 읽기/쓰기가 가능한지 여부를 알려야한다. 또한 쿠버네티스에게 퍼시스턴트볼륨이 해제되면 어떤 동작을 해야 할지 알려야한다. 마지막으로 퍼시스턴트볼륨을 지원하는 실제 스토리지의 유형, 위치, 속성 정볼르 지정해야 한다. 이제 파드 볼륨에서 GCE PD를 참조하도록 다음과 같이 정의한다.

spec:
  volumes:
  - name: mongodb-data
    gcePersistentDisk:
      pdName: mongodb
      fsType: ext4

개발자는 퍼시스턴트볼륨을 사용하기 위해 퍼시스턴트볼륨클레임을 먼저 생성해야한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc
spec:
  resources:
    requests: # 1GiB의 스토리지를 요청한다
      storage: 1Gi
  accessModes: # 단일 클라이언트를 지원하는 스토리지다(읽기/쓰기를 모두 수행한다)
  - ReadWriteOnce
  storageClassName: "" # 동적 프로비저닝과 관련된 부분이다

퍼시스턴트볼륨클레임이 생성되면 쿠버네티스는 적절한 퍼시스턴트볼륨을 찾고 클레임에 바인딩한다. kubectl get pvc를 통해 VOLUME과 STATUS를 확인하여 바인딩되었는지 확인할 수 있다. ACESSMODES에서 RWO(ReadWriteOnce, 단일 노드만 읽기/쓰기용으로 볼륨을 마운트할 수 있다), ROX(ReadOnlyMany, 다수 노드가 읽기용으로 볼륨을 마운트할 수 있다), RWX(ReadWriteMany, 다수 노드가 읽기/쓰기용으로 볼륨을 마운트할 수 있다)라는 접근모드를 확인할 수 있다.

파드에서 퍼시스턴트볼륨클레임을 사용하기 위해 다음과 같이 정의한다.

apiVersion: v1
kind: Pod
metadata:
  name:
spec:
  containers:
  - image:
    name:
    volumeMounts:
    - name: mongodb-data
      mountPath: /data/db
    ports:
    - containerPort:
      protocol:
  volumes:
  - name: mongodb-data
    persistentVolumeClaim:
      claimName: mongodb-pvc

퍼시스턴트볼륨클레임을 삭제 후 다시 생성해도 바인딩되지 않는다. 클러스터 관리자가 볼륨을 완전히 비우지 않으면 새로운 클레임에 바인딩할 수 없다. 쿠버네티스에 persistentVolumeClaimPolicy를 Retain으로 설정하면 수동으로 다시 클레임할 수 있다. 퍼시스턴트볼륨을 수동으로 재사용할 수 있는 유일한 방법은 퍼시스턴트볼륨 리소스를 삭제하고 다시 생성하는 것이다. 퍼시스턴트볼륨이 다시 클레임될 수 있도록 하는 리클레임 정책은 Recycle과 Delete가 있다.

emeraldgoose commented 7 months ago

6.6 퍼시스턴트볼륨의 동적 프로비저닝

퍼시스턴트볼륨클레임을 사용하여 개발자가 실제 스토리지 기술을 처리할 필요 없이 쉽게 퍼시스턴트 스토리지를 사용할 수 있다. 그러나 여전히 클러스터 관리자는 실제 스토리지를 미리 프로비저닝해둬야 하는데 쿠버네티스는 퍼시스턴트볼륨의 동적 프로비저닝을 통해 이 작업을 자동으로 수행할 수 있다.

클러스터 관리자는 퍼시스턴트볼륨을 생성하는 대신 퍼시스턴트볼륨 프로비저너(provisioner)를 배포하고 사용자가 선택 가능한 퍼시스턴트볼륨의 타입을 하나 이상의 스토리지클래스(StorageClass) 오브젝트로 정의할 수 있다. 사용자가 퍼시스턴트볼륨클레임에서 스토리지클래스를 참조하면 프로비저너가 퍼시스턴트 스토리지를 프로비저닝할 때 이를 처리한다. 보통 클라우드 쿠버네티스는 인기있는 프로비저너들을 포함하여 배포할 필요가 없지만 온프레미스에 배포된 경우 사용자 정의 프로비저너가 배포돼야 한다.

관리자가 많은 퍼시스턴트볼륨을 미리 프로비저닝하는 대신 하나 혹은 그 이상의 스토리지클래스를 정의하면 시스템은 누군가 퍼시스턴트볼륨클레임을 통해 요청 시 새로운 퍼시스턴트볼륨을 생성한다.

사용자가 퍼시스턴트볼륨클레임을 생성하면 결과적으로 새로운 퍼시스턴트볼륨이 프로비저닝되므로 관리자는 하나 혹은 그 이상의 스토리지클래스 리소스를 생성해야 한다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/gce-pd # 퍼시스턴트볼륨 프로비저닝을 위해 사용되는 볼륨 플러그인이다
parameters: # 프로비저너로 전달되는 파라미터이다
  type: pd-ssd
  zone: europe-west1-b

스토리지클래스 리소스는 퍼시스턴트볼륨클레임이 스토리지클래스에 요청할 때 어떤 프로비저너가 퍼시스턴트볼륨을 프로비저닝하는 데 사용돼야 할지를 지정한다. 스토리지클래스에 정의된 파라미터들은 프로비저너에 전달되며, 파라미터는 각 프로비저너 플러그인마다 다르다.

스토리지클래스 리소스가 생성되면 사용자는 퍼시스턴트볼륨클레임의 이름에 스토리지클래스를 참조할 수 있다. 스토리지 클래스를 조회하려면 `kubectl get sc 명령을 사용한다. Mongodb-pvc를 동적 프로비저닝을 사용하도록 수정한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc
spec:
  storageClassName: fast # PVC는 사용자 정의 스토리지클래스를 요청한다
resources:
  requests:
    storage: 100Mi
  accessModes:
    - ReadWriteOnce

크기와 접근 모드를 지정하는 것 외에도 퍼시스턴트볼륨클레임에 사용할 스토리지클래스를 지정해야 한다. 클레임을 생성하면 fast 스토리지클래스 리소스에 참조된 프로비저너가 퍼시스턴트볼륨을 생성한다. 프로비저너는 수동으로 프로비저닝된 퍼시스턴트볼륨과 퍼시스턴트볼륨클레임을 매핑하는데도 사용한다. 만약 pvc에서 존재하지 않은 스토리지클래스를 참조하면 pv 프로비저닝은 실패한다. kubectl describe 명령을 통해 ProvisioningFailed 이벤트가 표시된다.

클러스터 관리자는 성능이나 기타 특성이 다른 여러 스토리지 클래스를 생성할 수 있고 개발자는 생성할 각 클레임에 가장 적합한 스토리지 클래스를 결정한다. 스토리지클래스의 좋은 점은 클레임 이름으로 이를 참조한다는 것이다. 다른 클러스터 간 스토리지클래스 이름을 동일하게 사용한다면 PVC 정의를 다른 클러스터로 이식 가능하다.

kubectl get sc ${storage_class_name} -o yaml명령을 통해 조회된 결과의 어노테이션에 storageClass.beta.kubernetes.io/is-default-class 값이 true라면 해당 스토리지 클래스가 기본값으로 설정되어 있는 것이다. 기본 스토리지 클래스는 퍼시스턴트볼륨클레임에서 명시적으로 어떤 스토리지 클래스를 사용할지 지정하지 않은 경우 퍼시스턴트볼륨을 동적 프로비저닝하는데 사용한다.

storageClassName을 빈 문자열로 지정하는 예시를 보자.

kind: PersistentVolumeClaim
spec:
  storageClassName: ""

storageClassName을 빈 문자열로 지정하면 PVC가 새로운 PV를 동적 프로비저닝하는 대신 미리 프로비저닝된 PV에 바인딩된다.