[EKS] AWS EBS 볼륨을 K8S PV로 사용
Pod 간 공유 가능한 스토리지를 만들어야 했습니다.
그러던 중 PV, PVC 라는 k8s 개념이 있어서 공부한 것을 정리해 보겠습니다.
물리 스토리지를 쿠버네티스 클러스터에 표현한 것이 PV이고, Pod의 볼륨과 PV를 연결하는 관계가 PVC 입니다.
EKS 1.23버전 이후부터는 AWS EBS CSI Driver(https://github.com/kubernetes-sigs/aws-ebs-csi-driver)를 설치 하지 않으면 EBS를 PV로 사용할 수 없습니다.
참고: https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/kubernetes-versions.html#kubernetes-1.23
Provisioning
PV를 프로비저닝 할 수 있는 방법에는 정적(static) 프로비저닝과 동적(dynamic) 프로비저닝이 있습니다.
1. Static Provisioning
정적 프로비저닝은 관리자가 수동으로 물리 디스크를 생성한 후 PV를 생성하고 PVC에 바인딩 한 후에, Pod에서 사용할 수 있습니다.
미리 준비된 스토리지가 있다면 PV를 수동으로 생성하는 정적 프로비저닝을 사용하면 되지만 클라우드를 사용하고 있다면 미리 준비하지 않고 필요시에 스토리지를 생성하면 되기 때문에 동적 프로비저닝을 사용합니다.
2. Dynamic Provisioning
동적 프로비저닝을 사용하면 관리자가 사전에 물리 디스크와 PV를 수동으로 생성할 필요가 없이 PVC만 정의하면 이에 맞는 물리 디스트 생성 및 PV 생성을 자동화합니다. PVC는 StorageClass를 요청해야 하며 관리자는 동적 프로비저닝이 발생하도록 해당 클래스를 생성하고 구성해야 합니다.
1. Static Provisioning
외부에서 생성한 물리적 볼륨을 k8s 내에서 사용하기 위해 PV와 연결합니다.
실행 순서는 1. AWS EBS 생성 2. pv.yaml 생성 3. pvc.yaml 생성 4. pod에 정의 입니다.
PV용 AWS EBS 프로비저닝
- EBS 볼륨은 PV를 연결하려는 pod가 생성되는 node와 동일한 리전 및 가용성 영역에 있어야 합니다.
$ aws ec2 create-volume --region ap-northeast-2 --availability-zone ap-northeast-2a --size 5 --volume-type gp2
node에 label 부여
- pod가 생성될 node를 지정하기 위함
$ kubectl label nodes <ap-northeast-2a에 생성된 노드 이름> <레이블 키>=<레이블 값>
ex) kubectl label nodes ip-192-168-11-22.ap-northeast-2.compute.internal az=a
PersistentVolume (PV)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-1
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
capacity:
storage: 5Gi
csi:
driver: ebs.csi.aws.com
fsType: ext4
volumeHandle: vol-xxxxxxxxxxxxx
persistentVolumeReclaimPolicy: Retain
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: topology.ebs.csi.aws.com/zone
operator: In
values:
- ap-northeast-2a
|
cs |
csi
- driver: 드라이버 이름 지정
- volumeHandle: Disk 볼륨 ID
- readOnly: 볼륨을 읽기 전용으로 "ControllerPublished" (연결)할지 여부를 나타내는 선택적인 불리언(boolean) 값. 기본적으로 false 이다.
- fsType: 만약 PV의 VolumeMode 가 Filesystem 인 경우에 이 필드는 볼륨을 마운트하는 데 사용해야 하는 파일시스템을 지정하는 데 사용될 수 있다.
https://kubernetes.io/ko/docs/concepts/storage/volumes/#csi
PersistentVolumeClaim (PVC)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app: wordpress
name: pvc-1
spec:
storageClassName: "" # Empty string must be explicitly set otherwise default StorageClass will be set
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
volumeMode: Filesystem
volumeName: pv-1
|
cs |
AccessMode
PV에 대한 동시에 Pod에서 접근할 수 있는 정책을 정의합니다. (AWS EBS는 ReadWriteOnce 만 가능)
- ReadWriteOnce: 하나의 노드에서 해당 볼륨이 읽기-쓰기로 마운트 될 수 있다. ReadWriteOnce 접근 모드에서도 파트가 동일 노드에서 구동되는 경우에는 복수의 파드에서 볼륨에 접근할 수 있다.
- ReadWriteMany: 볼륨이 다수의 노드에서 읽기 전용으로 마운트 될 수 있다.
- ReadWriteOncePod: 볼륨이 단일 파드에서 읽기-쓰기로 마운트 될 수 있다. 전체 클러스터에서 단 하나의 파드만 해당 PVC를 읽거나 쓸 수 있어야 하는 경우 ReadWriteOncePod 접근 모드를 사용한다. 이 기능은 CSI 볼륨과 쿠버네티스 버전 1.22+ 에서만 지원된다.
Wordpress 배포
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: frontend
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:5.5.3-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_PASSWORD
value: password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: ebs-volume
mountPath: /data
volumes:
- name: ebs-volume
persistentVolumeClaim:
claimName: pvc-1
nodeSelector:
az: a
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
labels:
app: wordpress
spec:
type: NodePort
ports:
- port: 80
nodePort: 30000
selector:
app: wordpress
tier: frontend
|
cs |
워드프레스에 PVC를 붙여 배포해보겠습니다.
server ip:30000
워드프레스 기본 이미지가 잘 나옵니다.
해당 파드에 들어가 EBS 볼륨이 붙었는지 확인해보겠습니다.
$ kubectl exec -it <pod name> -- bash
/data 경로에 마운트가 된 것을 확인할 수 있습니다.
2. Dynamic Provisioning
동적 프로비저닝을 사용하면 관리자가 사전에 물리 디스크와 PV를 수동으로 생성할 필요가 없이 PVC만 정의하면 이에 맞는 물리 디스트 생성 및 PV 생성을 자동화합니다. PVC는 StorageClass를 요청해야 하며 관리자는 동적 프로비저닝이 발생하도록 해당 클래스를 생성하고 구성해야 합니다.
StorageClass
- PVC에서 EBS 볼륨 및 관련 PV를 자동으로 생성합니다. 볼륨 생성에 대한 세분화된 제어를 위해 StorageClass를 통해 매개변수를 전달할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
parameters:
csi.storage.k8s.io/fstype: ext4
type: gp3
allowedTopologies:
- matchLabelExpressions:
- key: topology.ebs.csi.aws.com/zone
values:
- ap-northeast-2a
- ap-northeast-2b
- ap-northeast-2c
- ap-northeast-2d
|
cs |
provisioner로 aws ebs csi driver를 지정합니다.
https://github.com/kubernetes-sigs/aws-ebs-csi-driver
volumeBindingMode
- Immediate(디폴트): PVC가 생성되면 볼륨 바인딩과 동적 프로비저닝이 즉시 발생하는 것을 나타낸다.
- WaitForFirstConsumer: PVC를 사용하는 파드가 생성될 때까지 PV의 바인딩과 프로비저닝을 지연시킨다.(사용 가능한 프로바이저가 따로 있음)
Reclaim Policy
PV는 연결된 PVC가 삭제된 후 다시 다른 PVC에 의해서 재사용이 가능한데, 재사용 시에 디스크의 내용을 지울지 유지할지에 대한 정책을 Reclaim Policy를 이용하여 설정이 가능합니다. (디스크의 특성에 따라 적용 가능한 Policy가 다릅니다)
- Retain: 삭제하지 않고 PV의 내용을 유지합니다. 삭제할 때는 수동으로 삭제해야 합니다.
- Recycle: 기본 볼륨 플러그인에서 지원하는 경우 Recycle 반환 정책은 볼륨에서 기본 스크럽(rm -rf /thevolume/*)을 수행하고 새 클레임에 다시 사용할 수 있도록 합니다.
- Delete: 볼륨의 사용이 끝나면, 해당 볼륨은 삭제됩니다. AWS EBS, GCE PD, Azure Disk 등이 이에 해당합니다.
https://kubernetes.io/ko/docs/concepts/storage/persistent-volumes/#%EB%B0%98%ED%99%98-reclaiming
PersistentVolumeClaim (PVC)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app: nginx
name: pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: ebs-sc
|
cs |
storageClassName을 지정해 줍니다.
volumeBindingMode를 WaitForFirstConsumer으로 사용했기 때문에 바로 PV가 생기지 않고 Pod에서 요청하면 생깁니다.
Nginx 배포
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: ebs-volume
mountPath: /data
volumes:
- name: ebs-volume
persistentVolumeClaim:
claimName: pvc
nodeSelector:
az: a
|
cs |
PVC의 상태가 Bound가 되었고 PV가 생성된 것을 확인할 수 있습니다.
Pod->PVC->SC->EBS 생성 및 PV생성!
주의 사항
AWS EBS는 특정 가용영역에 생성되어 EC2에 붙는 스토리지로서 AccessMode가 ReadWriteOnce입니다.
그러므로 동일한 노드에 배포된 Pod끼리만 공유가 가능합니다.
서로 다른 노드에 배포된 Pod에서 동일한 스토리지를 공유하고 싶다면 EFS를 사용합니다.
+ EFS는 EBS보다 가격도 비싸고 IO도 느립니다..
+ EFS를 사용하려면 동적 프로비저닝이아닌 정적 프로비저닝 방식으로 PVC를 붙여야합니다.
참고
https://kubernetes.io/ko/docs/concepts/storage/persistent-volumes/
https://kubernetes.io/ko/docs/concepts/storage/storage-classes/
https://github.com/kubernetes-sigs/aws-ebs-csi-driver/tree/master/examples/kubernetes