Storage
- Container File System
- ephemeral. 컨테이너를 삭제하거나 재실행하면 컨테이너 file system의 데이터도 같이 삭제됨.
컨테이너가 계속 사용해야 하는 데이터라면 Volumes를 사용하는 편이 좋다.
- Volumes
- Runtime에는 컨테이너가 접근 가능한 outside-container storage.
- real time change - 컨테이너가 참조하고 있는 파일 값이 변경될 경우 external storage의 값도 같이 바뀐다.
- Persistent Volumes
- 보다 추상화된 형태. k8s object처럼 Persistent Volumes를 생성해서 pod이 사용할 수 있게 한다.
runtime 때, 컨테이너는 storage에 직접 접근하는 대신 Persistent Volume에 요청 후 접근한다. 컨테이너가 재실행되더라도 Persistent Volume 객체는 그대로이므로, container의 data consistency는 유지할 수 있다.
Volume에는 여러 타입이 있고, 각 타입별로 '어디에 어떻게' volume이 생성되는지 결정되기 때문.
K8s Volumes
- volume: pod의 specification. 구체적인 volumeType을 지정하고, 데이터를 어디에 저장할 것인지 명시한다.
- 예시의 경우 hostPath가 volumeType이고, 어디에 저장할 것인지는 path에 지정했다.
- volumeMount: container 단위의 specification. pod의 spec을 참조하고 실제 mountPath를 지정한다.
- 예시의 경우 pod에서 정의한 volume과 동일한 name으로 지정했고, mountPath를 지정한다.
예시의 yaml을 실행하게 되면
- sample-vol 이라는 이름의 volume을 생성하고, node의 /data 경로를 hostPath로 지정한다.
- 컨테이너는 host machine에 /data/output 경로를 생성하고, 해당 경로의 file system을 사용한다.
- 컨테이너를 재시작해도 /data/output 경로의 데이터는 소멸하지 않는다.
- EmptyDir volume: pod가 생성될 때 만들어지고, Pod가 사라지면 같이 삭제된다.
- 해당 Pod에 있는 Multiple Container가 동일한 volume을 참조할 수 있게 됨. 동일한 데이터를 여러 container에서 read / write할 수 있게 된다.
- container가 정의한 mountPath 경로와 관계없이, 같은 파일을 읽고 쓸 수 있게 됨
물론 emptyDir만 shared Volume 구조를 지원하는 건 아니다. hostPath도 shared Volume을 지원함.
컨테이너 간 데이터 공유가 가능하기 때문에, data processing in multiple format일 때 특히 유용하다.
아래의 yaml 파일로 pod를 생성한 결과.
- 노드의 /var/tmp 디렉토리가 존재하는지 확인
- yaml파일로 pod 생성
- /var/tmp 디렉토리에 새 파일 output.txt 파일이 생성됨
- 파일을 확인해보면 로그가 계속 기록되는 것을 볼 수 있음.
- restart policy를 따로 설정하지 않으면 기본적으로 restart가 적용되기 때문. pod 명령이 끝나고 자동으로 컨테이너가 삭제되고, policy 때문에 다시 생성되어 명령어를 실행하기 때문에 로그가 계속 기록된다.
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
volumes:
- name: hostpath-vol
hostPath:
path: /var/tmp # k8s node의 경로. k8s에 이 경로가 반드시 존재해야만 volumes가 제대로 작동함.
containers:
- name: hostpath-pod
image: 'k8s.gcr.io/busybox'
command: ["/bin/sh", "-c", "echo Hello Team, This is Sample File for HostVolume - $(date) >> /output/output.txt"]
volumeMounts:
- name: hostpath-vol
mountPath: /output
- 또한
kubectl delete
로 pod 자체를 삭제한 뒤 다시 apply로 생성했을 때, output.txt 파일의 마지막 줄에서부터 새 로그가 쌓이는 걸 볼 수 있다. - pod 자체를 삭제하고 재시작한다 해도, mount된 파일의 consistency는 유지하는 것을 확인할 수 있다.
emptyDir 예시
- 아래의 yaml 파일로 pod를 생성하고, kubectl exec로 pod에 직접 들어가서 /data/redis 디렉토리에 파일을 하나 생성한다.
apiVersion: v1
kind: Pod
metadata:
name: redis-emptydir
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {} # dynamically created dir. host machine에서 알아서 경로를 지정한다.
- 만약 Pod를 삭제한 뒤 다시 생성하면, emptyDir에 생성해뒀던 output.txt 파일이 사라진 걸 확인할 수 있다.
- emptyDir은 pod가 persistent할 때에만 접근 가능한 volume이며, pod가 삭제될 경우 데이터가 같이 삭제됨.
- container의 재실행 여부와는 관계없이 volume의 데이터가 유지된다.
apiVersion: v1
kind: Pod
metadata:
name: shared-multi-container
spec:
volumes:
- name: html
emptyDir: {}
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
- name: debian-container
image: debian
volumeMounts:
- name: html
mountPath: /html
command:
- /bin/sh
- '-c'
args:
- while true; do date >> /html/index.html; sleep 5; done
# 5초마다 date를 index.html에 저장.
- nginx의 /usr/share/nginx/html을 emptyDir Volume에 마운트.
- debian의 /html 경로를 mount.
- 결과적으로, debian에서 업데이트한 index.html 파일이 nginx에서도 그대로 적용됨.
- emptyDir 특성상 같은 volume을 공유하고 있다면 common Directory.
- nginx가 mount한 경로에 index.html 파일이 있는데, debian에서 해당 경로의 index.html 파일을 5초마다 업데이트하기 때문.
curl로 접근하면, Port 80인 Nginx 컨테이너에 요청을 보냈을 때 리턴값으로 default html 파일이 아니라 date 로그가 쌓인 걸 확인할 수 있다.
Persistent Volumes
- k8s에서 제공하는 Object로, storage를 일종의 리소스처럼 사용할 수 있게 해 주는 기능.
- 예시처럼 kind에 PersistentVolume을 명시해주며, spec에 capacity 같은 설정을 추가할 수 있다.
- hostPath를 지정하면, 해당 경로에 Persistent Volume이 생성된다.
Storage Class
- k8s에서 제공하는 Storage Service의 종류를 규정하는 Object.
- provisioner에 no-provisioner를 지정하면, 해당 object를 생성한 k8s node가 provisioning 권한을 갖는다. (local machine이라고 생각하면 쉬움)
- volumeBindingMode: 해당 storage가 생성되면 어디에 binding할 것인지 지정. 어느 pod에 지정될 것인지 지정하는 거라고 생각하면 됨.
- slow / fast : 적용할 수 있는 storageClass 종류들. cloud storage를 provisioner에 지정할 수 있으며 (각각 aws / gcp), 목적에 맞게 설정하면 된다.
- 생성한 뒤 resize가 가능한지 여부를 설정하는 옵션 값.
- overview에서 언급한 것처럼, pod이 Persistent Volume에 접근하기 위해서는 persistent Volume Claim을 통해야 한다.
- 만약 Persistent Volume Claim 객체가 사라질 경우의 대응방식을 설정할 수 있음.
PersistentVolumeClaim
- user가 Persistent Volume을 사용하기 위해 요청을 날리는 대상 object
- PVC는 정의한 조건에 맞는 PV가 있는지 찾아보고, 없으면 직접 조건에 맞는 PV를 생성한 뒤 연결한다.
StorageClass 생성.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner # created on local machine running on k8s
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
PersistentVolume 생성.
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-persistnt-vol
spec:
storageClassName: local-storage # 미리 StorageClass를 정의해뒀으니 그 설정을 그대로 쓰지만, 만약 해당 class명이 없을 경우 storageClass를 생성한다.
persistentVolumeReclaimPolicy: Recycle
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /var/tmp
PersistentVolumeClaim 생성.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: local-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
# 이 기준을 충족하는 PV가 존재하므로, 직전에 생성한 PV를 그대로 사용한다.
status를 확인해보면 PVC의 상태가 pending이다. PV에 요청을 보낼 client를 기다리는 상태.
따라서 client 역할을 할 pod를 생성해준다.
apiVersion: v1
kind: Pod
metadata:
name: my-pv-pod
spec:
restartPolicy: Never
containers:
- name: busybox
image: busybox
command: ["sh", "-c", "echo Hello Team, This is Persistnent Volume Claim >> /output/success.txt"]
## output 경로에 success.txt 파일 생성
volumeMounts:
- mountPath: /output
name: my-pv
volumes:
- name: my-pv
persistentVolumeClaim:
claimName: my-pvc # 생성해뒀던 pvc를 연결한다.
pod를 생성한 뒤 pv의 상태를 확인하면,
- 이전의 Available 상태와 달리 Bound가 되어 있다.
- claim 필드도 my-pvc가 등록되어 있다.
pvc의 상태를 확인하면
- status가 bound로 변경되었다
- capacity, access mode 등 storage 정보가 활성화되어 있다.
PV가 PVC를 통해 pod에 연결되었다는 의미.
'학습일지 > kubernetes' 카테고리의 다른 글
CKA 대비 kubernetes 스터디 - 2. Scheduler (0) | 2022.02.27 |
---|---|
CKA 대비 kubernetes 스터디 - 1. Core Concept (0) | 2022.02.25 |
Kubernetes Deep Dive - (7). Service (0) | 2021.10.03 |
Kubernetes Deep Dive - (6). Network (0) | 2021.10.02 |
Kubernetes Deep Dive - (5). Deployment (0) | 2021.09.30 |