CKA #8 Storage
Index
- CKA #2 Core Concepts, #3 Scheduling
- CKA #4 Logging & Monitoring, #5 Application LifeCycle Management
- CKA #6 Cluster Maintenance
- CKA #7 Security
- CKA #8 Storage
- CKA #9 Networking
Storage Drivers vs. Volume Drivers
Docker Storage Driver와 파일 시스템
Docker는 로컬 파일 시스템을 어떻게 저장하는가?
도커를 설치하면 /var/lib/docker/docker/
디렉토리가 생성된다. 도커는 기본적으로 모든 데이터를 이 디렉토리에 저장한다. 데이터란 호스트에서 실행되는 이미지 및 컨테이너 관련 파일을 말한다.
모든 파일은 컨테이너 폴더에 저장되고 이미지와 관련된 파일은 이미지 폴더에 저장된다. 도커 컨테이너에 의해 생성된 모든 볼륨은 볼륨 폴더 아래에 저장된다.
도커가 자신의 파일과 포맷을 어디에 저장하는지 이해해보자.
도커의 레이어 구조를 이해해야 한다. 도커는 이미지를 구축할 때 레이어드 아키텍쳐에 구축한다. 도커 파일의 각각의 명령어는 레이어를 생성한다.
그리고, 이미지를 컨테이너로 실행하면, 이미지 위에 컨테이너 레이어를 얹는다. 이미지 레이어의 파일들은 ReadOnly이다. 컨테이너 레이어는 Read와 Write가 가능하다. 이미지 레이어는 여러 컨테이너 사이에서 공유될 수 있기 때문이다. 이미지 레이어의 파일을 수정하고 싶다면, CopyOnWrite 형태로, 이미지 레이어의 파일은 컨테이너 레이어로 가져와서 수정할 수 있게 된다.
컨테이너를 지우면, 컨테이너 레이어가 삭제되면서 컨테이너 레이어 내의 모든 파일이 삭제된다. 만약 이 파일들을 유지하고 싶다면, 볼륨을 추가할 수 있다.
docker volume create data_volume
# /var/lib/docker/volumes/docker_volume 디렉토리가 생성됨
docker run -v data_volume:/var/lib/mysql mysql
docker run -v 볼륨이름:컨테이너디렉토리 이미지이름
docker run --mount type=bind, source=볼륨위치, target=컨테이너내부디렉토리 이미지이름
Docker’s Storage Drivers
- AUFS, ZFS, BTRFS, DeviceMapper, Overlay, Overlay2
- Docker의 기본 스토리지 드라이버는 AUFS
- 그러나 OS에 따라 달라지는데 Fedora, CentOS 등에서는 불가능하므로, DeviceMapper를 선택할 수도 있음
- 스토리지 드라이버마다 다른 성능과 안정성 특성을 가지고 있으므로, 요구사항에 맞춰 부합하는 걸 선택하는게 중요하다.
Docker’s Volume Drivers
- 볼륨은 Storage Driver가 처리하지 않는다. 볼륨 드라이버 플러그인이 처리한다.
- 디폴트값은 Local Volume Plugin. 로컬 볼륨 플러그인은 도커 호스트의 볼륨 생성을 돕고,
/var/lib/docker/volumes
디렉토리에 볼륨이 생성되도록 한다. - 종류: Azure File Storage, Convoy, GCE-docker, RexRay Storage (AWS EBS, S3…)
docker run -it \
--name mysql
--volume-driver rexray/ebs
--mount src=ebs-vol, target=/var/lib/mysql
mysql
Rex-Ray EBS를 쓰면 아마존 EBS를 볼륨으로 쓸 수 있다.
Container Storage Interface
- Volume RPC
- Create Volume
- Delete Volume
- ControllerPublishVolume
Volumes in k8s
Docker 컨테이너는 일시적인 용도로 사용된다. 데이터 처리가 필요할 때 호출되고, 끝나면 폐기된다. 컨테이너 안의 데이터도 마찬가지다. 컨테이너의 데이터는 파괴되는 것이 보통이다. 볼륨을 이용하면 컨테이너의 데이터를 영구적으로 보존할 수 있다. 컨테이너가 삭제되어도 데이터는 남아 있다. 쿠버네티스에서는 어떻게 동작할까?
쿠버네티스에서 생성된 파드는 일시적이다. 파드가 데이터를 처리하고 파드가 삭제될 때 데이터도 삭제된다. 파드에 볼륨을 부착하여 이를 해결한다. 파드에서 생성된 데이터가 볼륨에 저장되고 파드가 삭제되도 볼륨은 남아있다.
apiVersion: v1
kind: Pod
metadata:
name: random-number-generator
spec:
containers:
- image: alpine
name: alpine
command: ["/bin/sh", "-c"]
args: ["shuf -i 0-100 -n 1 >> /opt/number.out;"]
volumes:
- name: data-volume
hostPath:
path: /data
type: Directory
이미지 출처: Certified Kubernetes Administrator (CKA) with Practice Tests(Udemy)
싱글 노드에서 로컬 디렉토리로 볼륨을 마운트한다. 이제 파드가 삭제되어도 노드에 볼륨 데이터가 남아있다.
그런데 다중 노드 클러스터에서 이 방법을 쓸 수 없다. 파드가 각기 다른 노드에서 /data
디렉토리를 쓰면서 동일한 데이터가 저장되어 있길 기대하기 때문이다.
그래서 쿠버네티스 레벨에서는 다양한 유형의 저장소 솔루션을 지원한다.
volumes:
- name: data-volume
awsElasticBlockStore:
volumeID: <volume-id>
fsType: ext4
Persistent Volumes
앞선 방법은 파드 정의 yaml 파일에 volumes에 대한 구성 정보가 들어가게 된다. 그런데 큰 환경에서 많은 파드를 배포한다고 가정했을 때, 파드에 따라 매번 저장소를 구성하고 설정해주어야 하는 문제가 발생한다. 사용자는 해당 파드를 배포할 때 파드 정의 파일에 저장소를 구성해야 한다. 수정사항도 작성해주어야 하는 문제가 있다.
이러한 문제를 해결하고자, 중앙에서 거대한 저장소 하나를 관리하는 방법이 있다. 이것이 Persistent Volume이다.
이미지 출처: Certified Kubernetes Administrator (CKA) with Practice Tests(Udemy)
# pv-definition.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-vol1
spec:
persistentVolumeReclaimPolicy: Retain
accessModes:
- ReadWriteOnce # (ReadOnlyMany, ReadWriteOnce, ReadWriteMany)
capacity:
storage: 1Gi
hostPath:
path: /tmp/data # <Node Local Directory>를 적는 곳. 상용에서는 안씀
awsElasticBlockStore: # 실제로는 이런 것을 위주로 ...
volumeID: <volume-id>
fsType: ext4
kubectl create -f pv-definition.yaml
kubectl get persistentvolume
Persistent Volume Claims
Persistent Volume을 사용하기 위해 Persistent Volume Claims를 만든다.
Persistent Volume Claim이 생성되면 쿠버네티스는 Persistent Volume Claim의 요청과 속성을 읽고, Persistent Volume Claim을 Persistent Volume에 Bind한다. 모든 PVC은 단일 PV에 바인딩된다. 쿠버네티스는 요구대로 충분한 Capacity를 확보하고자 한다.
요구사항에는 다음과 같은 것들이 있다.
- Sufficient Capacity
- Access Modes
- Volume Modes
- Storage Class
특정한 볼륨을 쓰고 싶다면, 라벨과 셀렉터를 이용해 바인딩할 수 있다.
# in PV
labels:
name: my-pv
# in PVC
selector:
matchLabels:
name: my-pv
- PV와 PVC는 1:1로 엮인다. 따라서 하나의 PV에 PVC를 바인딩하고 나서 PV에 공간이 남았다고 하더라도, 다른 PVC를 추가로 바인딩할 수 없다.
- PVC가 바인딩할 수 있는 PV가 없다면, PVC는 Pending 상태로 남는다. 새로운 볼륨이 클러스터에 추가되기 전까지 Pending되며, 새 볼륨이 추가되면 자동으로 바인딩된다.
# pvc-definition.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
--
# pv-definition.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-vol1
spec:
storageClassName: local-storage
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
awsElasticBlockStore:
volumeID: <volume-id>
fsType: ext4
kubectl create -f pvc-definition.yaml
PVC가 생성되면 쿠버네티스는 PV 리스트를 확인하고, 할당가능한 볼륨을 바인딩한다.
kubectl delete persistentvolumeclaim myclaim
만약 PVC를 삭제한다면, PV는 어떻게 될까? → 옵션 선택에 따라 달라진다.
persistentVolumeReclaimPolicy: Retain | Delete | Recycle
- Retain으로 설정하면 PVC 바인드를 해제하더라도 PV는 별도의 작업이 있기 전까지, 다른 PVC를 바인딩할 수 없다.
- Delete로 설정하면 PVC가 삭제되는 순간, 볼륨도 삭제된다.
- Recylce로 설정하면 새 PVC가 할당되면 삭제된다.
Using PVC in Pods
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
이미지 출처: Certified Kubernetes Administrator (CKA) with Practice Tests(Udemy)
Storage Class
만약 클라우드 플랫폼의 스토리지를 사용하려고 한다면, PV가 생성되기 전에 클라우드 플랫폼의 디스크를 프로비저닝해야 한다는 문제가 있다.
gcloud beta compute disks create --size 1GB --region us-east1 pd-disk
이러한 작업을 정적 프로비저닝 볼륨이라고 한다. 그런데 자동으로 프로비저닝시킬 수 있다면? 그게 바로 Storage Class다.
구글 클라우드 같은 곳에서 저장소를 자동으로 프로비저닝하고, 요구사항에 따라 파드에 연결하는 것을 볼륨의 동적 프로비저닝이라고 한다.
# sc-definition.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: google-storage
provisioner: kubernetes.io/gce-pd
StorageClass가 있어서 PV가 필요하지 않아졌다. StorageClass가 알아서 다 생성해줄 것이기 때문. PVC가 PV가 아닌 StorageClass를 쓰려면 정의 파일에 storageClassName을 추가해주어야 한다.
# pvc-definition.yaml
...
spec:
storageClassName: google-storage
...
PVC가 생성되면, PVC에 적힌 스토리지 클래스는 프로비저너를 이용해 클라우드 플랫폼에 요구되는 사이즈의 새 디스크를 프로비저닝하고, PV를 생성해서 PV를 PVC와 연결한다.
여기서 중요한 것은, PV를 자동으로 생성한다는 점이다. PV를 정의하지 않았다고 해서 쓰지 않는 것이 아니다. 여전히 PV를 사용한다.
프로비저너는 여러 종류가 있다. AzureFile, AzureDisk, Cinder, AWSElasticBlockStore, GCEPersistentDisk…