예시: StatefulSet으로 Cassandra 배포하기

예시: StatefulSet으로 Cassandra 배포하기

이 튜토리얼은 Kubernetes에서 Apache Cassandra를 실행하는 방법을 보여줘요. Cassandra는 데이터베이스로, 데이터 내구성(애플리케이션 상태)을 제공하기 위해 영구 스토리지가 필요해요. 이 예시에서 커스텀 Cassandra seed provider가 데이터베이스가 Cassandra 클러스터에 새 인스턴스가 합류할 때 그것을 발견하게 해줘요.

StatefulSet은 유상태(stateful) 애플리케이션을 Kubernetes 클러스터에 배포하는 것을 더 쉽게 만들어요. 이 튜토리얼에서 사용된 기능에 대한 더 많은 정보는 StatefulSet을 참고해요.

Cassandra와 Kubernetes는 둘 다 클러스터의 구성원을 가리킬 때 node라는 용어를 사용해요. 이 튜토리얼에서 StatefulSet에 속한 파드는 Cassandra 노드이며, Cassandra 클러스터(ring이라고 함)의 구성원이에요. 그 파드들이 Kubernetes 클러스터에서 실행될 때, Kubernetes 컨트롤 플레인은 그 파드들을 Kubernetes 노드에 스케줄링해요.

Cassandra 노드가 시작되면 seed 목록을 사용해 ring의 다른 노드 발견을 부트스트랩해요. 이 튜토리얼은 새 Cassandra 파드가 Kubernetes 클러스터 안에 나타날 때 데이터베이스가 그것을 발견하게 하는 커스텀 Cassandra seed provider를 배포해요.

출처: 문서

본문

목표 (Objectives)

시작하기 전에

Kubernetes 클러스터가 있어야 하고 kubectl 명령줄 도구가 클러스터와 통신하도록 구성되어 있어야 해요. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 최소 두 개 있는 클러스터에서 실행하는 것을 권장해요. 아직 클러스터가 없다면 minikube를 이용해 만들거나, 아래 Kubernetes 플레이그라운드 중 하나를 사용할 수 있어요.

이 튜토리얼을 완료하려면 파드, 서비스, StatefulSet에 대한 기본적인 친숙함이 있어야 해요.

추가 Minikube 설정 지침

Minikube는 기본적으로 2048MB 메모리와 2 CPU로 동작해요. 기본 리소스 구성으로 Minikube를 실행하면 이 튜토리얼 중 리소스 부족 오류가 발생해요. 이런 오류를 피하려면 다음 설정으로 Minikube를 시작해요.

minikube start --memory 5120 --cpus=4

Cassandra용 헤드리스 서비스 생성

Kubernetes에서 서비스는 같은 작업을 수행하는 파드 집합을 설명해요.

다음 서비스는 Cassandra 파드와 클러스터 안의 클라이언트 사이의 DNS 조회에 사용돼요.

apiVersion: v1
kind: Service
metadata:
  labels:
    app: cassandra
  name: cassandra
spec:
  clusterIP: None
  ports:
  - port: 9042
  selector:
    app: cassandra

cassandra-service.yaml 파일에서 모든 Cassandra StatefulSet 구성원을 추적하는 서비스를 만들어요.

kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml

검증 (선택 사항)

Cassandra 서비스를 가져와요.

kubectl get svc cassandra

응답은 다음과 같아요.

NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
cassandra   ClusterIP   None         <none>        9042/TCP   45s

cassandra라는 이름의 서비스가 보이지 않는다면 생성이 실패한 것이에요. 흔한 문제 해결법은 서비스 디버깅을 읽어보세요.

StatefulSet으로 Cassandra ring 만들기

아래 포함된 StatefulSet 매니페스트는 세 개의 파드로 구성된 Cassandra ring을 만들어요.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 3
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      terminationGracePeriodSeconds: 500
      containers:
      - name: cassandra
        image: gcr.io/google-samples/cassandra:v13
        imagePullPolicy: Always
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command:
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "K8Demo"
          - name: CASSANDRA_DC
            value: "DC1-K8Demo"
          - name: CASSANDRA_RACK
            value: "Rack1-K8Demo"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5
        # These volume mounts are persistent. They are like inline claims,
        # but not exactly because the names need to match exactly one of
        # the stateful pod volumes.
        volumeMounts:
        - name: cassandra-data
          mountPath: /cassandra_data
  # These are converted to volume claims by the controller
  # and mounted at the paths mentioned above.
  # do not use these in production until ssd GCEPersistentDisk or other ssd pd
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
  type: pd-ssd

cassandra-statefulset.yaml 파일에서 Cassandra StatefulSet을 만들어요.

# Use this if you are able to apply cassandra-statefulset.yaml unmodified
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml

클러스터에 맞게 cassandra-statefulset.yaml을 수정해야 한다면, https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml을 다운로드한 다음, 수정한 버전을 저장한 폴더에서 그 매니페스트를 적용해요.

# Use this if you needed to modify cassandra-statefulset.yaml locally
kubectl apply -f cassandra-statefulset.yaml

Cassandra StatefulSet 검증

  • Cassandra StatefulSet을 가져와요. 응답은 비슷해야 해요. StatefulSet 리소스는 파드를 순차적으로 배포해요.
  • 파드를 가져와 순서대로 생성됨 상태를 봐요. 응답은 비슷해야 해요. 세 파드가 모두 배포되려면 몇 분이 걸릴 수 있어요. 배포되면 같은 명령이 다음과 비슷한 출력을 반환해요.
  • 첫 파드 안에서 Cassandra nodetool을 실행해 ring의 상태를 표시해요. 응답은 대략 이렇게 보여야 해요.

Cassandra StatefulSet 수정

kubectl edit을 사용해 Cassandra StatefulSet의 크기를 수정해요.

  • 다음 명령을 실행해요. 이 명령은 터미널에서 편집기를 열어요. 변경해야 할 줄은 replicas 필드예요. 다음 샘플은 StatefulSet 파일의 발췌문이에요.
  • replicas 수를 4로 변경한 다음 매니페스트를 저장해요. 이제 StatefulSet은 4개 파드로 실행되도록 확장돼요.
  • Cassandra StatefulSet을 가져와 변경을 확인해요. 응답은 비슷해야 해요.

정리

StatefulSet을 삭제하거나 축소해도 StatefulSet과 연결된 볼륨은 삭제되지 않아요. 이 설정은 데이터가 관련된 모든 StatefulSet 리소스를 자동으로 지우는 것보다 더 가치 있기 때문에, 안전을 위한 것이에요.

  • 다음 명령(단일 명령으로 연결)을 실행해 Cassandra StatefulSet의 모든 것을 삭제해요.
  • 다음 명령으로 Cassandra용으로 설정한 서비스를 삭제해요.

Cassandra 컨테이너 환경 변수

이 튜토리얼의 파드들은 Google 컨테이너 레지스트리의 gcr.io/google-samples/cassandra:v13 이미지를 사용해요. 위 Docker 이미지는 debian-base를 기반으로 하며 OpenJDK 8을 포함해요.

이 이미지는 Apache Debian 저장소의 표준 Cassandra 설치를 포함해요. 환경 변수를 사용해 cassandra.yaml에 삽입되는 값을 변경할 수 있어요.

환경 변수 기본값
CASSANDRA_CLUSTER_NAME 'Test Cluster'
CASSANDRA_NUM_TOKENS 32
CASSANDRA_RPC_ADDRESS 0.0.0.0

다음 단계

더 알아보기 (Learn more)