본문 바로가기

IT

쿠버네티스[EKS] gp2, gp3 마이그레이션

728x90

다음은 Amazon EBS 볼륨 유형 gp2와 gp3의 비교 지표이다.

gp2, gp3 비교 지표

 

2020년 12월에 출시된 gp3를 사용하면 스토리지 크기를 느리지 않고도 IOPS와 처리량을 독립적으로 프로비저닝할 수 있어 GB당 최대 20% 비용을 절감할 수 있다고 한다. 즉 저렴한 비용으로 고성능을 유지하면서 더 적은 볼륨을 프로비저닝 할 수 있다. gp3의 최고 성능은 gp2의 볼륨의 최대 처리량보다 4배 빠르며 gp2 볼륨이 적용될만한 모든 케이스에서 gp3 볼륨을 사용할 수 있다고 하니 gp3를 사용하지 않을 이유가 없는 거 같다고 생각한다. 

 

gp3로 마이그레이션할 때 IOPS와 처리량에 대해서는 위 포스팅을 참고하도록 하자. 

https://aws.amazon.com/ko/blogs/korea/migrate-your-amazon-ebs-volumes-from-gp2-to-gp3-and-save-up-to-20-on-costs/

 

Amazon EBS 볼륨을 gp2에서 gp3으로 마이그레이션하고 최대 20% 비용 절감하기 | Amazon Web Services

업데이트 (4/27/2022): EBS gp2-gp3 마이그레이션 비용 절감 계산기를 다운로드하면 EBS gp2 볼륨을 gp3로 마이그레이션할 때 비용을 얼마나 절감할 수 있는지 알 수 있습니다. 범용 SSD (gp2) Amazon EBS 볼륨

aws.amazon.com

AWS 관리 콘솔에서도 변경 가능하며 AWS CLI로도 애플리케이션 중단없이 변경이 가능하다.

aws ec2 modify-volume --volume-type gp3 --iops 4000 --throughput 250 --volume-id vol-11111111111111111

 

하지만 그렇게 변경하게 되면 EKS 클러스터에서는 PV 사용 시 여전히 gp2로 보이게 될 것이다. PersistentVolume(PV)의 스토리지 클래스 정보가 그대로 gp2로 남아 있기 때문이다. Kubernetes에서 PV 생성 시 스토리지 클래스와 볼륨 타입이 결정되기에 새 PV/PVC를 생성하거나 Helm 차트 등의 배포 과정에서 storageClassName을 gp3로 지정해 재프로비저닝하는 절차가 필요하다. 

 

EKS의 Default StorageClass가 gp2로 프로비저닝 하기에 default 스토리지 클래스를 gp3로 변경하는게 좋지만 기존에 프로비저닝 된 볼륨의 유형을 바꾸는 과정을 기록해보려고 한다. 옳은 방법, 더 쉬운 방법은 있을 것 같고 계속 고민해 볼 필요는 있을 것 같다. 

 

eks csi-driver 설치 참조

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/ebs-csi.html#managing-ebs-csi

 

본격적인 마이그레이션 전에 VolumeSnapshot 관련 CRD 및 Controller 등을 설치 해야한다. 

 

CRD 설치

curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f snapshot.storage.k8s.io_volumesnapshots.yaml,snapshot.storage.k8s.io_volumesnapshotclasses.yaml,snapshot.storage.k8s.io_volumesnapshotcontents.yaml

 

Snapshot Controller 설치

curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
curl -s -O https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
kubectl apply -f rbac-snapshot-controller.yaml,setup-snapshot-controller.yaml
kubectl get deploy -n kube-system snapshot-controller
kubectl get pod -n kube-system -l app=snapshot-controller

 

Snapshot-controller

 

마지막으로 VolumSnapshotClass를 설치하자. 스토리지 제공자별로 스냅샷 생성 방식을 정의하며, 어느 드라이버를 사용할지, 스냅샷 생성 시 어떤 옵션을 적용할지를 지정한다. 

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: ebs-csi-aws
driver: ebs.csi.aws.com
deletionPolicy: Delete
kubectl apply -f volumesnapshot.yaml

 

 

마이그레이션 시나리오를 간략히 설명하자면 다음과 같다. 

현재 gp3로 마이그레이션 하고자 하는 PV가 속해있는 EBS 볼륨 ID를 조회하여 스냅샷을 생성한다. 이 스냅샷을 기반으로 gp3로 프로비저닝 할 수 있다. (사실 이 부분에서 스냅샷 한 시점부터 동기화되지 않기 때문에 찝찝한 마음이 들긴 하다.)

 

스냅샷이 생성되면 이를 기반으로 VolumeSnapshotContent 오브젝트를 만든다. 이 오브젝트는 생성된 스냅샷의 정보를 담고 있고 실제 스냅샷과의 바인딩 역할을 한다고 볼 수 있다.

 

그 다음 VolumeSnapshot 오브젝트를 생성한다. 사용자가 스냅샷 생성을 요하는 오브젝트라고 생각하면 될 것 같다. 이 오브젝트를 생성하면 Kubernetes 컨트롤러가 VolumeSnapshotClass에 정의된 정책을 참고하여 실제 스냅샷(VolumeSnapshotContent)를 생성하고, 둘을 연결(binding)한다.

 

결과적으로 사용자는 VolumeSnapshot을 통해 생성된 스냅샷을 참조하고 활용할 수 있게 된다. 이 때 VolumeSnapshot과 VolumeSnapshotContent는 이상하게 보일 수 있지만 양방향 매핑이 필요하다.

This seems odd but is necessary for the bidirectional binding of VolumeSnapshotContent and VolumeSnapshot for preexisting snapshots!

 

VolumeSnapshotContent 생성

$ cat vsc-csi.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
  name: imported-aws-snapshot-content
spec:
  volumeSnapshotRef:
    kind: VolumeSnapshot
    name: imported-aws-snapshot
    namespace: default
  source:
    snapshotHandle: snap-06fb1faafc1409cc5 # <-- snapshot to import
  driver: ebs.csi.aws.com
  deletionPolicy: Delete
  volumeSnapshotClassName: ebs-csi-aws

$ kubectl apply -f vsc-csi.yaml
volumesnapshotcontent.snapshot.storage.k8s.io/imported-aws-snapshot-content created

$ kubectl get volumesnapshotcontent imported-aws-snapshot-content
NAME                            READYTOUSE   RESTORESIZE   DELETIONPOLICY   DRIVER            VOLUMESNAPSHOTCLASS   VOLUMESNAPSHOT          VOLUMESNAPSHOTNAMESPACE   AGE
imported-aws-snapshot-content   true         1073741824    Delete           ebs.csi.aws.com   ebs-csi-aws           imported-aws-snapshot   default                   12s

 

 

VolumeSnapshot 생성

$ cat vs-csi.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: imported-aws-snapshot
  namespace: default
spec:
  volumeSnapshotClassName: ebs-csi-aws
  source:
    volumeSnapshotContentName: imported-aws-snapshot-content

$ kubectl apply -f  vs-csi.yaml
volumesnapshot.snapshot.storage.k8s.io/imported-aws-snapshot created

$ kubectl get volumesnapshot imported-aws-snapshot
NAME                    READYTOUSE   SOURCEPVC   SOURCESNAPSHOTCONTENT           RESTORESIZE   SNAPSHOTCLASS   SNAPSHOTCONTENT                 CREATIONTIME   AGE
imported-aws-snapshot   true                     imported-aws-snapshot-content   1Gi           ebs-csi-aws     imported-aws-snapshot-content   33m            60s

 

이렇게 VolumSnapshot을 만들면 이를 기반으로 PVC(PersistenVolumeClaim)을 만들 수 있다. 

$ cat pvc-vs-csi.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: imported-aws-snapshot-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: gp3
  resources:
    requests:
      storage: 1Gi
  dataSource:
    name: imported-aws-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io

 

이를 기반으로 pod에서 PVC claimName을 변경해주어 적용할 수 있다. 

$ cat test-pod-snap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-imported-snapshot-csi
spec:
  containers:
  - name: app
    image: centos
    args:
    - sleep
    - "10000"
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: imported-aws-snapshot-pvc

 

실제로 pod가 사용하는 PVC를 변경하는 건 다음과 같은 방향으로 가능하지만 helm chart 등으로 주어진 환경마다 다를 수 있다. 해당 글에서는 helm chart로 구성된 grafana의 볼륨을 교체하는 과정에서 기존 PVC를 삭제하고 동일한 이름의 PVC를 VolumeSnapshot으로 부터 생성하였다고 한다. 필자의 경우는 다음과 같이 VolumeClaimTemplate의 Datasource를 추가하여 마이그레이션 하기도 했다.

마이그레이션 예제

 

 

이 또한 절대 좋은 방법이 아님을 느낀 것은 1. 재배포가 필요하였고 2. 스냅샷을 만든 시점부터는 데이터 동기화가 안되기에 실시간으로 데이터가 유지되어야한다면 다른 방법을 고민해 볼 필요가 있을 것이다. 

 

 

 

참고

https://aws.amazon.com/ko/blogs/storage/simplifying-amazon-ebs-volume-migration-and-modification-using-the-ebs-csi-driver/

https://aws.amazon.com/ko/blogs/containers/migrating-amazon-eks-clusters-from-gp2-to-gp3-ebs-volumes/

https://aws.amazon.com/ko/blogs/korea/migrate-your-amazon-ebs-volumes-from-gp2-to-gp3-and-save-up-to-20-on-costs/