Kubernetes에 EBS 볼륨 붙이기

문서 이력: 주말에 잠깐 심심하길래 이 글을 써서는 월요일에 회사 블로그에 옮겨적었다. 회사 블로그를 좀 띄워볼 요량으로 이 블로그에는 며칠 늦게 올린다.

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을 통해 볼륨을 할당받는다. kafka1volumeclaimdefault1을 기준으로 스토리지 정책을 정하므로

  • 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 같은 스토리지 관리 서비스를 활용해도 좋다. 하지만 배보다 배꼽이 큰 것 같은 느낌이 들지도 모르겠다.

최 재훈

블로그, 페이스북, 트위터 고성능 서버 엔진, 데이터베이스, 지속적인 통합 등 다양한 주제에 관심이 많다.
Close Menu