문서 이력: 주말에 잠깐 심심하길래 이 글을 써서는 월요일에 회사 블로그에 옮겨적었다. 회사 블로그를 좀 띄워볼 요량으로 이 블로그에는 며칠 늦게 올린다.
Kubernetes에서 컨테이너에 Persistent Volume을 붙이는 방법은 몇가지 있다. 여기서는 Kafka 서비스를 예로 삼아 주요 접근방법을 간단히 알아본다.
Kubernetes v1.4.0를 기준으로 문서를 작성한다.
Static
말이 Static이지 수동 마운트를 뜻한다. 기본적으로 관리자가 EBS 볼륨을 만들고
특정 Pod에 그 볼륨을 붙이는 작업을 한다. Volumes 문서에 나오는대로 하면 간단하다.
apiVersion: v1
kind: Service
metadata:
name: kafka1
labels:
app: kafka1
tier: backend
spec:
ports:
# the port that this service should serve on
- port: 9092
name: port
targetPort: 9092
protocol: TCP
selector:
app: kafka1
tier: backend
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kafka1
spec:
replicas: 1
template:
metadata:
labels:
app: kafka1
tier: backend
spec:
containers:
- name: kafka1
image: wurstmeister/kafka
imagePullPolicy: Always
volumeMounts:
- mountPath: "/kafka"
name: kafka1volume
ports:
- containerPort: 9092
volumes:
- name: kafka1volume
awsElasticBlockStore:
volumeID: vol-688d7099
fsType: ext4
여기서 핵심은 다음의 두 줄 뿐이다.
awsElasticBlockStore:
volumeID: vol-688d7099
Dynamic
수동으로 볼륨을 붙이는 방법은 간단해서 좋다. 하지만 Autoscaling하는 서비스에 넣기에는 아무래도 무리다. 서비스가 뜰 때 요구사항에 맞는 볼륨을 스스로 만들어 붙이는 방법도 있다. Kubernetes Persistent Volumes를 참고해 작업해본다.
우선 Kubernetes 생성할 EBS 볼륨의 사양을 정한다.
# storages.yaml
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: default1a
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
zone: ap-northeast-1a
iopsPerGB: "10"
---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: default1c
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
zone: ap-northeast-1c
iopsPerGB: "10"
default1a
를 선택하면 ap-northeast-1a Availablity Zone에 기가바이트당 IOPS는 10인 General SSD EBS 볼륨을 생성한다. 이제 다시 Kafka의 돌아가면
apiVersion: v1
kind: Service
metadata:
name: kafka1
labels:
app: kafka1
tier: backend
spec:
ports:
# the port that this service should serve on
- port: 9092
name: port
targetPort: 9092
protocol: TCP
selector:
app: kafka1
tier: backend
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: kafka1
spec:
replicas: 1
template:
metadata:
labels:
app: kafka1
tier: backend
spec:
containers:
- name: kafka1
image: wurstmeister/kafka
imagePullPolicy: Always
volumeMounts:
- mountPath: "/kafka"
name: kafka1volume
ports:
- containerPort: 9092
volumes:
- name: kafka1volume
persistentVolumeClaim:
claimName: kafka1volumeclaim
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: kafka1volumeclaim
annotations:
volume.beta.kubernetes.io/storage-class: "default1a"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 300Gi
이제 awsElasticBlockStore
가 아닌 PersistentVolumeClaim
을 통해 볼륨을 할당받는다. kafka1volumeclaim
은 default1
을 기준으로 스토리지 정책을 정하므로
- Availablity Zone: ap-northeast-1a
- IOPS: 기가바이트당 10
- General SSD
- 300Gi 이상
인 스토리지를 원한다는 요구사항을 기술한다. 위의 설정은 이러한 스토리지에 부합하는 EBS 볼륨을 생성하여 kafka1
Pod에 할당한다.
분석
Dynamic은 Autoscaling에는 적합하나 kubectl delete [service]
또는 kubectl delete [deployment]
등의 명령을 수행하여 서비스를 내렸다가 다시 올린 경우에 기존에 쓰던 볼륨을 마운트하지 않고 새 볼륨을 만드는 문제가 있다. 물론 delete
를 하지 않고 서비스를 업데이트만 하는 경우에는 볼륨이 유지되지만 이래선 아무래도 문제의 소지가 많다.
그래서 또다른 시나리오를 고민해볼 수는 있다. 짧게 설명하자면
- 관리자가 Volumn Pool을 만들어놓고 Autoscaling 서비스가 이 풀 안에서 볼륨을 할당받게 한다. 이러면 앞서 본 두 가지 방식의 장점을 골고루 흡수할 수 있다.
flocker
또는glushterfs
같은 스토리지 관리 서비스를 활용해도 좋다. 하지만 배보다 배꼽이 큰 것 같은 느낌이 들지도 모르겠다.