예시: 카산드라를 스테이트풀셋으로 배포하기

이 튜토리얼은 쿠버네티스에서 아파치 카산드라를 실행하는 방법을 소개한다. 데이터베이스인 카산드라는 데이터 내구성을 제공하기 위해 퍼시스턴트 스토리지가 필요하다(애플리케이션 상태). 이 예제에서 사용자 지정 카산드라 시드 공급자는 카산드라가 클러스터에 가입할 때 카산드라가 인스턴스를 검색할 수 있도록 한다.

스테이트풀셋 은 상태있는 애플리케이션을 쿠버네티스 클러스터에 쉽게 배포할 수 있게 한다. 이 튜토리얼에서 이용할 기능의 자세한 정보는 스테이트풀셋을 참조한다.

목적

  • 카산드라 헤드리스 Service를 생성하고 검증한다.
  • 스테이트풀셋(StatefulSet)을 이용하여 카산드라 링을 생성한다.
  • 스테이트풀셋을 검증한다.
  • 스테이트풀셋을 수정한다.
  • 스테이트풀셋과 포함된 파드를 삭제한다.

시작하기 전에

쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.

이 튜토리얼을 완료하려면, 파드, 서비스, 스테이트풀셋에 대한 기본 지식이 있어야 한다.

추가적인 Minikube 설정 요령

카산드라를 위한 헤드리스 서비스 생성하기

쿠버네티스 에서 서비스는 동일 작업을 수행하는 파드의 집합을 기술한다.

다음의 서비스는 클러스터에서 카산드라 파드와 클라이언트 간에 DNS 찾아보기 용도로 사용한다.

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

cassandra-service.yaml 파일에서 카산드라 스테이트풀셋 노드를 모두 추적하는 서비스를 생성한다.

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

검증하기(선택)

카산드라 서비스 살펴보기

kubectl get svc cassandra

결과는 다음과 같다.

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

cassandra 서비스가 보이지 않는다면, 이와 다른 응답이라면 서비스 생성에 실패한 것이다. 일반적인 문제에 대한 서비스 디버깅하기를 읽어보자.

카산드라 링을 생성하는 스테이트풀셋 이용하기

스테이트풀셋 매니페스트에는 다음을 포함하는데 3개 파드로 구성된 카산드라 링을 생성한다.

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: 1800
      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.yaml을 수정하지 않은 경우에 이것을 사용한다.
kubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml

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

# cassandra-statefulset.yaml을 로컬에서 수정한 경우에 사용한다.
kubectl apply -f cassandra-statefulset.yaml

카산드라 스테이트풀셋 검증하기

  1. 카산드라 스테이트풀셋 얻기

    kubectl get statefulset cassandra
    

    응답은 다음과 유사하다.

    NAME        DESIRED   CURRENT   AGE
    cassandra   3         0         13s
    

    StatefulSet리소스는 순차적으로 파드를 배포한다.

  2. 순차적으로 생성된 현황을 보기 위해 파드를 살펴보자.

    kubectl get pods -l="app=cassandra"
    

    응답은 다음과 유사하다.

    NAME          READY     STATUS              RESTARTS   AGE
    cassandra-0   1/1       Running             0          1m
    cassandra-1   0/1       ContainerCreating   0          8s
    

    모든 3개 파드가 배포되기까지 몇 분이 소요될 수 있다. 배포 후, 동일 명령은 다음과 유사하게 응답한다.

    NAME          READY     STATUS    RESTARTS   AGE
    cassandra-0   1/1       Running   0          10m
    cassandra-1   1/1       Running   0          9m
    cassandra-2   1/1       Running   0          8m
    
  3. 첫 번째 파드 내부에 링의 상태를 보여주는 카산드라 nodetool을 실행하자.

    kubectl exec -it cassandra-0 -- nodetool status
    

    이 응답은 다음과 비슷하게 보일 것이다.

    Datacenter: DC1-K8Demo
    ======================
    Status=Up/Down
    |/ State=Normal/Leaving/Joining/Moving
    --  Address     Load       Tokens       Owns (effective)  Host ID                               Rack
    UN  172.17.0.5  83.57 KiB  32           74.0%             e2dd09e6-d9d3-477e-96c5-45094c08db0f  Rack1-K8Demo
    UN  172.17.0.4  101.04 KiB  32           58.8%             f89d6835-3a42-4419-92b3-0e62cae1479c  Rack1-K8Demo
    UN  172.17.0.6  84.74 KiB  32           67.1%             a6a1e8c2-3dc5-4417-b1a0-26507af2aaad  Rack1-K8Demo
    

카산드라 스테이트풀셋 수정하기

kubectl edit를 사용하여 카산드라 스테이트풀셋의 크기를 수정한다.

  1. 다음 명령어를 실행한다.

    kubectl edit statefulset cassandra
    

    이 명령은 터미널에서 편집기를 연다. 변경해야할 행은 replicas 필드이다. 다음 예제는 스테이트풀셋 파일에서 발췌했다.

    # 다음의 오브젝트를 수정한다. '#'로 시작하는 행은 무시되고,
    # 빈 파일은 편집을 중단한다. 저장할 때 오류가 발생하면 이 파일이
    # 관련 실패와 함께 다시 열린다.
    #
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      creationTimestamp: 2016-08-13T18:40:58Z
      generation: 1
      labels:
      app: cassandra
      name: cassandra
      namespace: default
      resourceVersion: "323"
      uid: 7a219483-6185-11e6-a910-42010a8a0fc0
    spec:
      replicas: 3
    
  2. 레플리카 개수를 4로 바꾸고, 매니페스트를 저장한다.

    스테이트풀셋은 4개의 파드를 실행하기 위해 스케일 한다.

  3. 검증하기 위해 카산드라 스테이트풀셋을 살펴보자

    kubectl get statefulset cassandra
    

    결과는 다음과 유사하다.

    NAME        DESIRED   CURRENT   AGE
    cassandra   4         4         36m
    

정리하기

스테이트풀셋을 삭제하거나 스케일링하는 것은 스테이트풀셋에 연관된 볼륨을 삭제하지 않는다. 당신의 데이터가 스테이트풀셋의 관련된 모든 리소스를 자동으로 제거하는 것보다 더 가치있기에 이 설정은 당신의 안전을 위한 것이다.

  1. 다음 명령어(한 줄로 연결된)를 실행하여 카산드라 스테이트풀셋을 모두 제거하자.

    grace=$(kubectl get pod cassandra-0 -o=jsonpath='{.spec.terminationGracePeriodSeconds}') \
      && kubectl delete statefulset -l app=cassandra \
      && echo "Sleeping ${grace} seconds" 1>&2 \
      && sleep $grace \
      && kubectl delete persistentvolumeclaim -l app=cassandra
    
  2. 다음 명령어를 실행하여 카산드라에 대해 설정한 서비스를 제거하자.

    kubectl delete service -l app=cassandra
    

카산드라 컨테이너 환경 변수

이 튜토리얼의 파드 는 구글의 컨테이너 레지스트리gcr.io/google-samples/cassandra:v13 이미지를 이용한다. 이 도커 이미지는 debian-base에 기반하였고 OpenJDK 8을 포함한다.

이 이미지는 아파치 데비안 리포의 표준 카산드라 설치본을 포함한다. 환경 변수를 이용하여 cassandra.yaml에 삽입된 값을 바꿀 수 있다.

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

다음 내용

최종 수정 May 18, 2022 at 9:43 AM PST: [ko] Update links heading to the Debugging section (f0386b499a)