티스토리 뷰
개요
Kubernetes가 대세로 자리 잡은 이후 다양한 3rd Party 솔루션과의 연동이슈는 끊임없이 발생하고 있다. Container Orchestrator(CO)와의 단일화된 인터페이스를 제공하기 위해 CRI(Container Runtime Interface), CNI(Container Network Interface), CSI(Container Storage Interface)가 등장하고 발전해 오고 있다.
CSI의 등장이전에는 특정 볼륨에 대한 연결 방식을 Kubernetes가 제공하는 방식으로 구현되었다. 하지만 새로운 볼륨 플러그인이 지속적으로 추가되고, 특히 특정 볼륨을 제공하는 솔루션의 버전 변화에 일일이 대응하기에는 어려움이 있었다. 또한 볼륨 스토리지와의 연결을 위해 SDK 코드가 Kubernetes 바이너리에 추가되어야 했으며, 이는 안정성 및 보안 문제를 야기했으며, 테스트와 관리의 어려움이 발생하였다.
CSI는 Kubernetes와 같은 컨테이너 오케스트레이션 시스템의 컨테이너화된 워크로드에 임의의 블록 및 파일 스토리지 시스템을 노출하기 위한 표준으로 개발되었다. Container Storage Interface의 채택으로 Kubernetes 볼륨 계층은 무한한 확장이 가능한 상태로 발전하였다. 이제 볼륨 확장을 위해서는 Kubernetes와의 직접적인 연계 없이 구현할 수 있으며, 이미 정의된 인터페이스를 통해 통신하며, 이는 CSI 등장 이전에 문제점으로 제시되었던, 관리의 어려움, 안정성의 문제, 보안 문제를 모두 해소할 수 있게 되었다.
이번 포스팅에서 살펴볼 StorageClass는 CSI의 구현체를 가리키는 오브젝트이다. StorageClass를 통해 대표적으로 많이 사용되는 볼륨인 AWS EBS와 NFS 연동 과정에 대해 살펴보도록 하자.
Dynamic Provisioning
CSI는 Container Orchestrator와 다양한 Storage Provider간의 인터페이스를 담당하며, PersistentVolume을 자동으로 생성할 수 있다.
CSI는 아래와 같은 다양한 스토리지 Provider를 지원한다. Kubernetes 내에 이미 Provisioner를 제공하거나, 필요 시 deployment, statefulset 등으로 배포하여 볼륨과 연동한다.
[주요 스토리지의 Privisioner]
- AWS EBS - provisioner: kubernetes.io/aws-ebs
- GCE PD - provisioner: kubernetes.io/gce-pd
- Glusterfs - provisioner: kubernetes.io/glusterfs
- NFS - provisioner: example.com/external-nfs
- OpenStack Cinder - provisioner: kubernetes.io/cinder
- vSphere - provisioner: csi.vsphere.vmware.com / provisioner: kubernetes.io/vsphere-volume
- Ceph RBD - provisioner: kubernetes.io/rbd
- Quobyte - provisioner: kubernetes.io/quobyte
- Azure Disk - provisioner: kubernetes.io/azure-disk
- Azure File - provisioner: kubernetes.io/azure-file
- Portworx Volume - provisioner: kubernetes.io/portworx-volume
- ScaleIO - provisioner: kubernetes.io/scaleio
- StorageOS - provisioner: kubernetes.io/storageos
- Local - provisioner: kubernetes.io/no-provisioner
해당 Provisioner를 사용하여 개별 정의된 Parameter를 통해 세부 연결 방식을 정의한다. 세부적인 환경 구성은 아래를 참고한다.
https://kubernetes.io/ko/docs/concepts/storage/storage-classes/
[동작 순서]
- 1. PersistentVolumeClaim은 StorageClass를 사용하여 동적 프로비저닝 트리거
- 2. Dynamic Provisioning은 PersistentVolumeClaim에 의해 트리거
- 3. 볼륨 프로비저닝이 호출되면 Parameter type의 value와 CreateVolume 호출을 volume provisioner로 전달
- 4. volume provisioner는 새 볼륨을 생성한 후 생성한 볼륨을 나타내는 PersistentVolume 개체를 자동으로 생성
- 5. Kubernetes는 새로운 PersistentVolume 개체를 PersistentVolumeClaim에 바인딩
- 6. Pod는 PersistentVolumeClaim을 추가하여 volume 사용
AWS EBS
먼저 살펴볼 볼륨은 aws ebs이다. ebs는 aws managed service로 대표적인 블록 스토리지이다.
[storageclass-aws.yaml]
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: aws-sc-ebs
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
fsType: ext4
aws-ebs의 StorageClass를 추가할 경우 다음과 같은 parameter를 함께 구성한다.
- type : io1, gp2, sc1, st1, default(gp2)
- iopsPerGB : io1 볼륨 전용. 1초당 GiB에 대한 I/O 작업 수. AWS 볼륨 플러그인은 요청된 볼륨 크기에 곱셈하여 볼륨의 IOPS를 계산하고 이를 20,000 IOPS로 제한한다.
- fsType : fsType은 쿠버네티스에서 지원된다. default("ext4")
- encrypted : EBS 볼륨의 암호화 여부
- kmsKeyId : 선택 사항. 볼륨을 암호화할 때 사용할 키의 전체 Amazon 리소스 이름.
provisioner를 통해 aws-ebs와 연결하는 storageclass임을 알 수 있다. parameters.type이 gp2이며, aws ebs volume type은 다음을 참조한다.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f storageclass-aws.yaml
storageclass.storage.k8s.io/aws-sc-ebs created
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
aws-sc-ebs kubernetes.io/aws-ebs Delete Immediate false 8s
gp2 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 34h
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
위와 같이 storageclass 추가 후 aws-sc-ebs를 조회한 결과이다. 이미 eks 설치 시점에 gp2라는 aws-ebs provisioner가 default로 추가되어 있는 것을 확인할 수 있지만, 본 포스팅에서는 aws-sc-ebs를 활용하도록 한다.
[persistentvolumeclaim-aws.yaml]
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: aws-sc-ebs-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: aws-sc-ebs
aws-sc-ebs-pvc PersistentVolumeClaim은 aws-sc-ebs storageclass를 사용하여 Dynamic Provisioning을 위한 트리거를 동작한다. storage 크기는 5Gi로 생성한다.
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f persistentvolumeclaim-aws.yaml
persistentvolumeclaim/aws-sc-ebs-pvc created
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
aws-sc-ebs-pvc Bound pvc-f64695d3-a6a2-4857-80ac-2bb9d344a55d 5Gi RWO aws-sc-ebs 7s
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
위와 같이 persistentvolumeclaim 추가 후 aws-sc-ebs-pvc를 조회한 결과이다.
마지막으로 Dynamic Provisioning으로 생성된 PersistentVolume을 확인해 보자.
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-f64695d3-a6a2-4857-80ac-2bb9d344a55d 5Gi RWO Delete Bound default/aws-sc-ebs-pvc aws-sc-ebs 10s
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
위와 같이 자동으로 생성된 PV를 확인할 수 있다. 이제 Application을 생성하여 볼륨이 정상적으로 생성되고 공유되는지 확인해 보자.
[namespace.yaml]
apiVersion: v1
kind: Namespace
metadata:
name: app-test
[nginx-service.yaml]
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- nodePort: 30380
port: 80
protocol: TCP
type: NodePort
selector:
run: my-nginx
[nginx-deployment.yaml]
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: aws-sc-ebs-pvc-nginx
mountPath: /data
volumes:
- name: aws-sc-ebs-pvc-nginx
persistentVolumeClaim:
claimName: aws-sc-ebs-pvc
위와 같이 생성한 yaml 파일 반영 후 pv 볼륨을 확인해 보자. 자세한 Deployment 내 Volume 구성 방법은 아래 URL을 참고한다.
https://waspro.tistory.com/580?category=831751
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME READY STATUS RESTARTS AGE
my-nginx-87f6dbffb-p2647 1/1 Running 0 106s
my-nginx-87f6dbffb-twvkf 1/1 Running 0 106s
[root@ip-192-168-78-195 aws-sc (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-87f6dbffb-p2647 /bin/bash
root@my-nginx-87f6dbffb-p2647:/# cd /data
root@my-nginx-87f6dbffb-p2647:/data# ls
lost+found
root@my-nginx-87f6dbffb-p2647:/data# touch test
root@my-nginx-87f6dbffb-p2647:/data# ls -la
total 20
drwxr-xr-x 3 root root 4096 Apr 2 15:52 .
drwxr-xr-x 1 root root 51 Apr 2 15:45 ..
drwx------ 2 root root 16384 Apr 2 15:45 lost+found
-rw-r--r-- 1 root root 0 Apr 2 15:52 test
root@my-nginx-87f6dbffb-p2647:/data#
deployment replicas에 의해 my-nginx pod는 2개 배포되어 있다. 그 중 7로 끝나는 pod에 접속하여 pvc에 정의한 mount point인 /data 하위에 test라는 파일을 생성한다.
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-87f6dbffb-twvkf /bin/bash
root@my-nginx-87f6dbffb-twvkf:/# cd /data
root@my-nginx-87f6dbffb-twvkf:/data# ls -la
total 20
drwxr-xr-x 3 root root 4096 Apr 2 15:52 .
drwxr-xr-x 1 root root 51 Apr 2 15:45 ..
drwx------ 2 root root 16384 Apr 2 15:45 lost+found
-rw-r--r-- 1 root root 0 Apr 2 15:52 test
root@my-nginx-87f6dbffb-twvkf:/data#
다음으로 f로 끝나는 pod에 접속하여 방금 생성한 test 파일이 생성되었는지 여부를 확인한다. 위와 같이 정상적으로 파일 볼륨 생성 및 파일공유가 이뤄지는 것을 확인할 수 있다.
NFS
다음으로 NFS(Network File System)을 동적 프로비저닝하는 방법에 대해 알아보자. Kubernetes는 NFS Provisioning을 처리하기 위해 외부 프로비저닝 도구를 구성해야 한다.
nfs-subdir-external-provisioner는 기 구성되어 있는 NFS 서버를 PersistentVolumeClaim, StorageClass를 사용하여 PersistentVolume을 자동으로 프로비저닝하기 위한 provisioner이다.
본 테스트를 위해 NFS 서버는
https://waspro.tistory.com/586
를 참고하여 구성하며, NFS-UTIL과 PORTMAP을 구성하였다.
1. github repository clone
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
[root@ip-192-168-78-195 nfs (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
Cloning into 'nfs-subdir-external-provisioner'...
remote: Enumerating objects: 7221, done.
remote: Counting objects: 100% (6023/6023), done.
remote: Compressing objects: 100% (3024/3024), done.
remote: Total 7221 (delta 3193), reused 5570 (delta 2790), pack-reused 1198
Receiving objects: 100% (7221/7221), 7.42 MiB | 10.60 MiB/s, done.
Resolving deltas: 100% (3838/3838), done.
[root@ip-192-168-78-195 nfs (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
2. Setup Authorization
[root@ip-192-168-78-195 nfs (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# cd nfs-subdir-external-provisioner/
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# NS=$(kubectl config get-contexts|grep -e "^\*" |awk '{print $5}')
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# NAMESPACE=${NS:-default}
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# echo $NS
default
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# echo $NAMESPACE
default
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# sed -i'' "s/namespace:.*/namespace: $NAMESPACE/g" ./deploy/rbac.yaml ./deploy/deployment.yaml
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# kubectl create -f deploy/rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
3. Configure nfs-subdir-external-provisioner
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /root/nfs
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.78.195
- name: NFS_PATH
value: /root/nfs
volumes:
- name: nfs-client-root
nfs:
server: 192.168.78.195
path: /root/nfs
nfs-client-provisioner 컨테이너를 배포하여 재정의된 nfs-subdir-external-privisioner를 구성한다. 유의할 점은 env tag 내 정보들을 환경에 맞게 수정 반영한다.
- PROVISIONER_NAME : PROVISIONER 이름을 지정하며, StorageClass에서 provisioner로 동일한 이름을 지정
- NFS_SERVER : NFS SERVER IP
- NFS_PATH : NFS Server Root Path
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/deployment.yaml
deployment.apps/nfs-client-provisioner created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-86cd8c4768-nkxvb 1/1 Running 0 11s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
4. StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}" # waits for nfs.io/storage-path annotation, if not specified will accept as empty string.
onDelete: delete
Storage Class의 provisioner를 nfs-client-provisioner의 PROVISIONER_NAME과 매핑한다. nfs-client의 StorageClass를 추가할 경우 다음과 같은 parameter를 함께 구성한다.
- onDelete : delete일 경우 디렉터리 삭제. retain일 경우 디렉토리 유지.
- archiveOnDelete : false일 경우 디렉토리를 삭제. onDelete존재하는 경우 archiveOnDelete 무시.
- pathPattern : label, annotation, name, namepsace와 같은 PVC 메타데이터를 통해 디렉토리 경로를 생성하기 위한 템플릿을 지정. 사용방법 - ${.PVC.<metadata>}
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/class.yaml
storageclass.storage.k8s.io/nfs-client created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp2 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 47h
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 8s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
위와 같이 storageclass를 추가하고 상태를 확인한다.
5. PersistentVolumeClaim
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
다음으로 Dynamic Provisioning을 트리거 하기 위한 PersistentVolumeClaim을 생성한다.
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/test-claim.yaml
persistentvolumeclaim/test-claim created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim Bound pvc-d5483f0f-eda5-4d7e-bdda-d8febaa39696 1Mi RWX nfs-client 9s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-d5483f0f-eda5-4d7e-bdda-d8febaa39696 1Mi RWX Delete Bound default/test-claim nfs-client 2m
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
위와 같이 pvc 생성 시 자동으로 pv를 생성하고 pvc가 Bound 되는 것을 확인할 수 있다.
6. Pod deploy
이제 Pod를 생성하고, 볼륨의 동작에 대해 확인해 보도록 하자.
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:stable
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
위와 같이 test-pod는 pod 내 mount path인 "/mnt" 하위에 SUCCESS라는 파일을 생성하고 Pod를 완료한다.
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k apply -f deploy/test-pod.yaml
pod/test-pod created
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-86cd8c4768-nkxvb 1/1 Running 0 115s
test-pod 0/1 ContainerCreating 0 5s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-86cd8c4768-nkxvb 1/1 Running 0 119s
test-pod 0/1 Completed 0 9s
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
Pod의 상태가 Complete으로 변경되면 아래와 같이 NFS Server를 확인해 보자.
[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# ls -la
total 0
drwxrwxrwx 2 root root 21 Apr 3 00:03 .
drwxr-xr-x 3 root root 21 Apr 1 16:48 ..
-rw-r--r-- 1 nfsnobody nfsnobody 0 Apr 3 00:00 SUCCESS
[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
SUCCESS 파일이 생성된 것을 확인할 수 있다.
7. deployment deploy
다음으로 nginx pod를 생성하여 volume을 사용하는 deployment를 배포해 보자.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
해당 deployment는 replicas를 2로 구성하고 각 pod간 데이터가 공유되는지, NFS에는 저장이 되는지 확인해 보자.
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k get pods
NAME READY STATUS RESTARTS AGE
my-nginx-95b4dc9cc-hkshf 1/1 Running 0 37s
my-nginx-95b4dc9cc-jt5ml 1/1 Running 0 37s
nfs-client-provisioner-86cd8c4768-nkxvb 1/1 Running 0 21m
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-95b4dc9cc-hkshf /bin/bash
root@my-nginx-95b4dc9cc-hkshf:/# cd /mnt
root@my-nginx-95b4dc9cc-hkshf:/mnt# touch nfstest
root@my-nginx-95b4dc9cc-hkshf:/mnt# ls -la
total 0
drwxrwxrwx 2 root root 36 Apr 3 00:20 .
drwxr-xr-x 1 root root 39 Apr 3 00:18 ..
-rw-r--r-- 1 nobody nogroup 0 Apr 3 00:00 SUCCESS
-rw-r--r-- 1 nobody nogroup 0 Apr 3 00:20 nfstest
root@my-nginx-95b4dc9cc-hkshf:/mnt#
위와 같이 f로 끝나는 nginx pod에 접속하여 "/mnt" 하위에 nfstest 파일을 생성한다.
[root@ip-192-168-78-195 nfs-subdir-external-provisioner (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# k exec -it my-nginx-95b4dc9cc-jt5ml /bin/bash
root@my-nginx-95b4dc9cc-jt5ml:/# cd /mnt
root@my-nginx-95b4dc9cc-jt5ml:/mnt# ls -la
total 0
drwxrwxrwx 2 root root 36 Apr 3 00:20 .
drwxr-xr-x 1 root root 39 Apr 3 00:18 ..
-rw-r--r-- 1 nobody nogroup 0 Apr 3 00:00 SUCCESS
-rw-r--r-- 1 nobody nogroup 0 Apr 3 00:20 nfstest
root@my-nginx-95b4dc9cc-jt5ml:/mnt#
다음으로 l로 끝나는 Pod에 연결하여 "/mnt" 경로 하위를 확인한다.
마지막으로 NFS Server를 직접 확인한다.
[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]# ls -la
total 0
drwxrwxrwx 2 root root 36 Apr 3 00:20 .
drwxr-xr-x 3 root root 21 Apr 1 16:48 ..
-rw-r--r-- 1 nfsnobody nfsnobody 0 Apr 3 00:20 nfstest
-rw-r--r-- 1 nfsnobody nfsnobody 0 Apr 3 00:00 SUCCESS
[root@ip-192-168-78-195 default (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:default)]#
위와 같이 NFS 서버에 정상적으로 추가된 것을 확인할 수 있다.
결론
서두에 이야기한 것처럼 Kubernetes와 연결하여 사용되는 수많은 볼륨들은 이제 CSI 표준에 따라 구성되며, 손쉬운 확장과 통합을 지원하게 되었다. 그 확장성의 측면에서 Kubernetes의 부담을 줄이고, 볼륨을 제공하는 Provider 측면에서 인터페이스를 개발하여 제공하게 됨으로써 유연함을 확보할 수 있다.
여전히 Kubernetes에서 직접 연결하는 방식에 대해 제공되고 있지만, Provider를 제공하는 Volume에 대해서는 CSI Provisioner에 의해 구현된 StorageClass, PersistentVolume에 의해 자동으로 프로비저닝을 관리하는 것이 보다 효과적일 것이다.
'③ 클라우드 > ⓚ Kubernetes' 카테고리의 다른 글
Kubernetes Multi Container Design Pattern (0) | 2022.06.26 |
---|---|
어플리케이션 & 클러스터 통합 모니터링 (Kuberhealthy & Prometheus) (0) | 2022.04.07 |
Kubernetes 네트워크 ACL "NetworkPolicy" (0) | 2022.03.19 |
Kubernetes 보안 강화를 위한 오픈소스 소프트웨어 활용 (0) | 2022.03.14 |
Polaris - Kubernetes 워크로드 모범 사례 적용 검증 (0) | 2022.03.13 |
- Total
- Today
- Yesterday
- kubernetes
- Da
- TA
- k8s
- 쿠버네티스
- 아키텍처
- 마이크로서비스 아키텍처
- node.js
- aws
- MSA
- jeus
- OpenStack
- JBoss
- 오픈스택
- wildfly
- webtob
- Docker
- git
- SA
- SWA
- openstack token issue
- JEUS6
- JEUS7
- Architecture
- 마이크로서비스
- nodejs
- aa
- openstack tenant
- apache
- API Gateway
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |