티스토리 뷰

728x90
반응형

How to building real world sample step by step - Part 2

게시글 참고

이 게시글은 KUDO Blog 샘플을 기준으로 테스트하면서 발생한 문제점들을 처리하고 동작을 검증하면서 정리한 내용입니다.

  • PART 1에서는 부트스트랩 노드 구성
  • PART 3에서는 사용하지 않는 부트스트랩을 제거하고, 외부 접속을 위한 서비스를 생성하며, 안전한 Scale Up/Down 처리 구성

이 문서는 KUDO Blog 샘플을 기준으로 테스트하면서 발생한 문제점들을 해결하고 동작을 검증하면서 정리한 내용으로 초기 구성된 Galera Cluster의 부트스트랩을 이용해서 클러스터에 노드들이 참여할 떄 사용할 서비스와 설정등을 구성하고 StatefulSet을 구성하는 방법을 정리한다.

Cluster에 참여하는 Node를 위한 초기 설정 구성

operator.yaml 파일에 아래와 같이 firstboot_config라는 Step과 Task를 추가하도록 한다.

apiVersion: kudo.dev/v1beta1
appVersion: 0.1.0
kubernetesVersion: 0.16.0
kudoVersion: 0.17.2
maintainers:
- email: ccambo@gmail.com
  name: ccambo
name: galera-operator
operatorVersion: 0.1.0
plans: 
  deploy:
    strategy: serial
    phases:
      - name: deploy
        strategy: serial
        steps:
          - name: bootstrap_config
            tasks:
              - bootstrap_config
          - name: bootstrap_service
            tasks:
              - bootstrap_service
          - name: bootstrap_deploy
            tasks:
              - bootstrap_deploy
          - name: firstboot_config    # 추가
            tasks:
              - firstboot_config
tasks:
  - name: bootstrap_config
    kind: Apply
    spec:
      resources:
        - bootstrap_config.yaml
  - name: bootstrap_service
    kind: Apply
    spec:
      resources:
        - bootstrap_service.yaml
  - name: bootstrap_deploy
    kind: Apply
    spec:
      resources:
        - bootstrap_deploy.yaml
  - name: firstboot_config      # 추가
    kind: Apply
    spec:
      resources:
        - galera_config.yaml

참고

위의 예제에서는 deploy Phase에서 개별적인 여러 개의 Step들을 정의했고, 이 Step들은 KUDO에 의해서 순차적으로 실행된다.
작업한 몇 개의 Step들은 서로 결과를 공유하는 등의 의존성이 없고, 이론적으로는 하나의 Step내에 여러 개의 Task를 지정해서 처리하는 것도 가능하고 Phase 자체를 병렬로 처리하게 하는 것도 가능하다.

위의 firstboot_config Task에서 사용할 templates/galera_config.yaml 파일을 생성하고 아래와 같이 구성한다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Name }}-nodeconfig
  namespace: {{ .Namespace }}
data:
  galera.cnf: |
    [galera]
    wsrep_on = ON
    wsrep_provider = /usr/lib/galera/libgalera_smm.so
    wsrep_sst_method = mariabackup
    wsrep_cluster_address = gcomm://{{ .Name }}-bootstrap-svc,{{ $.Name }}-{{ $.OperatorName }}-0.{{ $.Name }}-hs{{ range $i, $v := untilStep 1 (int .Params.NODE_COUNT) 1 }},{{ $.Name }}-{{ $.OperatorName }}-{{ $v }}.{{ $.Name }}-hs{{end}}
    wsrep_sst_auth = "{{ .Params.SST_USER }}:{{ .Params.SST_PASSWORD }}"
    binlog_format = ROW
  innodb.cnf: |
    [innodb]
    innodb_autoinc_lock_mode = 2
    innodb_flush_log_at_trx_commit = 0
    innodb_buffer_pool_size = 122M

노드가 Galera Cluster에 참여할 때 처리되어야 하는 두 개의 설정을 포함하는 ConfigMap을 구성한 것이다.

  • galera.cnf: Galera Cluster와 연동을 위한 설정
  • innodb.cnf: Galera 사용할 시에 InnoDB Engine에 권장되는 설정

Galera Cluster에 추가될 노드는 부트스트랩 노드의 서비스 주소와 클러스터에 포함될 노드들의 주소 정보가 필요하다.

wsrep_cluster_address 설정은 KUDO에서 지원하는 Sprig 템플릿 방식을 사용해서 다음과 같이 표현된다.

wsrep_cluster_address = gcomm://{{ .Name }}-bootstrap-svc,{{ $.Name }}-{{ $.OperatorName }}-0.{{ $.Name }}-hs{{ range $i, $v := untilStep 1 (int .Params.NODE_COUNT) 1 }},{{ $.Name }}-{{ $.OperatorName }}-{{ $v }}.{{ $.Name }}-hs{{end}}
  • 노드들은 StatefulSet이 될 것이기 때문에 파드의 이름을 .Name-.OperatorName-number 형식이 될 것으로 유추할 수 있다. 여기서 .Name과 .OperatorName은 KUDO에서 생성된 변수이고 번호는 인스턴스화된 StatefulSet의 Replicas의 순서에 기반해서 Kubernetes가 할당한 값이 된다.
  • 노드들에 접속하기 위한 Headless 서비스를 만들고 유일함을 보장하기 위해 .Name-hs 형식의 이름을 가질 것이다. 뒤에서 다시 언급할 것이기는 하지만 StatefulSet의 각 노드들에 대한 DNS 항목들은 예측 가능한 .Name-OperatorName-number.Name-hs 포맷의 이름이 된다.

위와 같은 가정을 기준으로 연결 문자열을 구성할 수 있다.

우선 부트스트랩 노드의 서비스 주소를 추가하고 다음 연결 문자열을 위해 ',' 로 연계한다.

gcomm://{{ .Name }}-bootstrap-svc,

노드는 최소한 1개 이상이 존재해야 하기 때문에 0 순번의 노드가 고정되어 있는다는 것을 알기 때문에 DNS 항목을 추가할 수 있다.

gcomm://{{ .Name }}-bootstrap-svc, {{ $.Name }}-{{ $.OperatorName }}-0.{{ $.Name }}-hs

Galera Cluster에 참여할 노드들을 구성하기 위한 NODE_COUNT 파라미터를 params.yaml파일에 아래와 같이 가장 마지막에 추가한다.

apiVersion: kudo.dev/v1beta1
parameters:
  ...
  - name: NODE_COUNT
    description: "Number of nodes to create in the cluster"
    default: "3"

그 다음은 params.yaml 에 정의된 NODE_COUNT 파라미터의 값을 참고해서 나머지 노드들을 처리할 수 있다. 이를 활용하는 Sprig 템플릿은 아래와 같다.

{{ range $i, $v := untilStep 1 (int .Params.NODE_COUNT) 1 }}, {{ $.Name }}-{{ $.OperatorName }}-{{ $v }}.{{ $.Name }}-hs{{ end }}

위의 내용은 표준 Go 템플릿의 Range 함수를 사용해서 인덱스 ($i)와 값 ($v)을 제공하고 Sprig의 untilStep 함수를 사용해서 생성된 범위 값을 전달한다. 이를 통해서 1 부터 시작해서 NODE_COUNT 까지 1 단위로 증가한 정수 목록을 받아서 사용하게 된다. NODE_COUNT가 3이라면 정수 범위는 1, 2 가 된다.

주의

  • params.yaml 정의된 NODE_COUNT 파라미터는 문자열로 기본처리가 되므로 사용하기 전에 (int .Params.NODE_COUNT)와 같이 int 형식으로 캐스팅해 줘야 한다.
  • Ranage 함수가 호출되면 변수들이 함수 내로 Scope 조정이 되기 때문에 최 상위 컨텍스트를 참조하기 위해서는 $ 접두사를 이용해서 파라미터들에 접근해야 한다.

위의 템플릿 범위 함수를 통해서 ','로 분리되는 형식의 클러스터의 모든 노드들에 대한 DNS 엔트리를 구성할 수 있다.

참고

복잡한 템플릿을 작업을 하는 것은 상당히 어려울 수 있기 때문에 테스트를 수행할 수 있는 go 코드를가지고 검증하는 것이 유용할 수 있다. 따라서 Template example 과 같이 템플릿을 stdout으로 출력하는 것과 같은 코드를 잘 활용하는 것이 좋다.

구성된 KUDO Package를 kubectl kudo package verify 명령을 통해서 논리적인 오류는 검증할 수 없겠지만 구문 오류 등을 확인할 수는 있다.

KUDO CLI의 Package 관련 명령을 통해서 새로운 파라미터들과 Task들이 올바르게 정의되었는지 등의 YAML 구성에 대한 검증도 가능하다.

  • Package Plans 구성 검증

    $ kubectl kudo package list plans ./    # Operator 상대 경로 또는 Package 명 지정 (여기서는 로컬 디렉터리를 사용하므로 ~/kudo_sample/galera-operator/operator 경로 사용)
    
    plans
    └── deploy (serial)
        └── [phase]  deploy (serial)
            ├── [step]  bootstrap_config
            │   └── bootstrap_config
            ├── [step]  bootstrap_service
            │   └── bootstrap_service
            ├── [step]  bootstrap_deploy
            │   └── bootstrap_deploy
            └── [step]  firstboot_config
                └── firstboot_config
  • Package Tasks 구성 검증

    $ kubectl kudo package list tasks ./
    
    Name                    Kind    Resources               
    bootstrap_config        Apply   [bootstrap_config.yaml] 
    bootstrap_service       Apply   [bootstrap_service.yaml]
    bootstrap_deploy        Apply   [bootstrap_deploy.yaml] 
    firstboot_config        Apply   [galera_config.yaml]    
  • Package Paramters 구성 검증

    $ kubectl kudo package list parameters ./
    
    Name                    Default Required        Immutable
    IST_PORT                4568    true            false    
    MYSQL_PORT              3306    true            false    
    MYSQL_ROOT_PASSWORD     admin   true            false    
    REPLICATION_PORT        4567    true            false    
    SST_PASSWORD            admin   true            false    
    SST_PORT                4444    true            false    
    SST_USER                root    true            false    

위의 검증을 통해서 올바르게 설정된 것이 확인 되었다면 지금까지 작업한 것을 기준으로 정상적으로 동작하는지 테스트를 하도록 한다.

  • KUDO 설치 (using init)

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --wait  # Webhook TLS를 자체 서명한 버전으로 처리
  • Galera Operator 설치 (using install)

    $ kubectl kudo install ./
  • 설치된 Operator Instance 확인

    $ kubectl kudo plan status --instance=galera-operator-instance
  • 설치된 ConfigMap 확인

    새로운 Step과 Task인 firstboot_config을 통해서 템플릿을 활용한 ConfigMap이 생성되었을 것이므로 템플릿이 제대로 동작했는지를 아래와 같이 확인해 본다.

    $ kubectl get configmaps
    
    NAME                                  DATA   AGE
    galera-operator-instance-bootstrap    1      27s
    galera-operator-instance-nodeconfig   2      12s
    
    $ kubectl describe configmap galera-operator-instance-nodeconfig
    
    Name:         galera-operator-instance-nodeconfig
    Namespace:    default
    Labels:       heritage=kudo
                  kudo.dev/instance=galera-operator-instance
                  kudo.dev/operator=galera-operator
    Annotations:  kudo.dev/last-applied-configuration:
                    {"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"galera-operator-instance-nodeconfig","namespace":"default","creationTimestamp":n...
                  kudo.dev/last-plan-execution-uid: 64db8c01-d078-404d-8344-1a6bd98733fe
                  kudo.dev/phase: deploy
                  kudo.dev/plan: deploy
                  kudo.dev/step: firstboot_config
    
    Data
    ====
    innodb.cnf:
    ----
    [innodb]
    innodb_autoinc_lock_mode = 2
    innodb_flush_log_at_trx_commit = 0
    innodb_buffer_pool_size = 122M
    
    galera.cnf:
    ----
    [galera]
    wsrep_on = ON
    wsrep_provider = /usr/lib/galera/libgalera_smm.so
    wsrep_sst_method = mariabackup
    wsrep_cluster_address = gcomm://galera-operator-instance-bootstrap-svc,galera-operator-instance-galera-operator-0.galera-operator-instance-hs,galera-operator-instance-galera-operator-1.galera-operator-instance-hs,galera-operator-instance-galera-operator-2.galera-operator-instance-hs
    wsrep_sst_auth = "root:admin"
    binlog_format = ROW
    
    Events:  <none>

    ConfigMap이 클러스터에 배포가 되었고, wsrep_cluster_address 정보를 통해서 NODE_COUNT 수 만큼 올바른 항목들이 생성되어 있는 것을 확인할 수 있다.

  • KUDO 및 Operator 삭제

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --upgrade --dry-run --output yaml | kubectl delete -f -

Cluster에 참여하는 Node들이 연결할 Service 구성

클러스터에 참여할 노드들을 StatefulSet에 배포할 예정이므로 이들을 연결할 방법인 서비스를 구성해야 한다.

operator.yaml 파일에 Steps, Tasks, Resources 를 아래와 같이 추가하도록 한다.

apiVersion: kudo.dev/v1beta1
appVersion: 0.1.0
kubernetesVersion: 0.16.0
kudoVersion: 0.17.2
maintainers:
- email: ccambo@gmail.com
  name: ccambo
name: galera-operator
operatorVersion: 0.1.0
plans: 
  deploy:
    strategy: serial
    phases:
      - name: deploy
        strategy: serial
        steps:
          - name: bootstrap_config
            tasks:
              - bootstrap_config
          - name: bootstrap_service
            tasks:
              - bootstrap_service
          - name: bootstrap_deploy
            tasks:
              - bootstrap_deploy
          - name: firstboot_config
            tasks:
              - firstboot_config
          - name: cluster_services    # 추가
            tasks:
              - cluster_services
tasks:
  - name: bootstrap_config
    kind: Apply
    spec:
      resources:
        - bootstrap_config.yaml
  - name: bootstrap_service
    kind: Apply
    spec:
      resources:
        - bootstrap_service.yaml
  - name: bootstrap_deploy
    kind: Apply
    spec:
      resources:
        - bootstrap_deploy.yaml
  - name: firstboot_config
    kind: Apply
    spec:
      resources:
        - galera_config.yaml
  - name: cluster_services      # 추가
    kind: Apply
    spec:
      resources:
        - hs-service.yaml

cluster_services Task에서 사용할 서비스 리소스인 templates/hs-service.yaml 파일을 생성하고 아래와 같이 구성한다.

apiVersion: v1
kind: Service
metadata:
  name: {{ .Name }}-hs
  namespace: {{ .Namespace }}
  labels:
    app: galera
    galera: {{ .Name }} 
spec:
  ports:
    - port: {{ .Params.MYSQL_PORT }}
      name: mysql
    - port: {{ .Params.SST_PORT }}
      name: sst
    - port: {{ .Params.REPLICATION_PORT }}
      name: replication
    - port: {{ .Params.IST_PORT }}
      name: ist
  clusterIP: None
  selector:
    app: galera
    instance: {{ .Name }}

ClusterIP를 가지지 않는 Headless 서비스를 생성한다. params.yaml에 정의된 Galera 구성에 필요한 모든 포트들을 설정하고 각 배포의 유일함을 보장하기 위해서 app와 instance라는 레이블을 선택하고 있다.

Headless Service인 이유는 Load balancing 주소가 필요하지 않고 StatefulSet의 각 노드에 때한 DNS 항목만 필요하기 때문이다.

지금까지 작업한 것을 기준으로 정상적으로 동작하는지 테스트를 하도록 한다.

  • KUDO 설치 (using init)

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --wait  # Webhook TLS를 자체 서명한 버전으로 처리
  • Galera Operator 설치 (using install)

    $ kubectl kudo install ./
  • 설치된 Operator Instance 확인

    $ kubectl kudo plan status --instance=galera-operator-instance
  • 설치된 Service 확인

    $ kubectl get services
    
    NAME                                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                               AGE
    galera-operator-instance-bootstrap-svc   ClusterIP   None         <none>        3306/TCP,4444/TCP,4567/TCP,4568/TCP   25s
    galera-operator-instance-hs              ClusterIP   None         <none>        3306/TCP,4444/TCP,4567/TCP,4568/TCP   9s
    kubernetes                               ClusterIP   10.96.0.1    <none>        443/TCP                               28d
    
    $ kubectl describe service galera-operator-instance-hs
    
    Name:              galera-operator-instance-hs
    Namespace:         default
    Labels:            app=galera
                      galera=galera-operator-instance
                      heritage=kudo
                      kudo.dev/instance=galera-operator-instance
                      kudo.dev/operator=galera-operator
    Annotations:       kudo.dev/last-applied-configuration:
                        {"kind":"Service","apiVersion":"v1","metadata":{"name":"galera-operator-instance-hs","namespace":"default","creationTimestamp":null,"label...
                      kudo.dev/last-plan-execution-uid: 89dc7134-f4ae-4fee-9fbf-ecee27b5a311
                      kudo.dev/phase: deploy
                      kudo.dev/plan: deploy
                      kudo.dev/step: cluster_services
    Selector:          app=galera,instance=galera-operator-instance
    Type:              ClusterIP
    IP:                None
    Port:              mysql  3306/TCP
    TargetPort:        3306/TCP
    Endpoints:         <none>
    Port:              sst  4444/TCP
    TargetPort:        4444/TCP
    Endpoints:         <none>
    Port:              replication  4567/TCP
    TargetPort:        4567/TCP
    Endpoints:         <none>
    Port:              ist  4568/TCP
    TargetPort:        4568/TCP
    Endpoints:         <none>
    Session Affinity:  None
    Events:            <none>

    서비스가 클러스터에 생성되었고, 올바른 Selector를 사용하고 있고, 역시 노드가 배포되지 않았기 때문에 Endpoints가 설정되지 않았다는 것을 확인할 수 있다.

  • KUDO 및 Operator 삭제

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --upgrade --dry-run --output yaml | kubectl delete -f -

Cluster에 참여할 Node 구성을 위한 StatefulSet 설정

위에서 클러스터에 참여할 노드들을 위한 ConfigMap과 Service가 정의되었기 때문에 StatefulSet을 operator.yaml에 Step과 Task로 설정한다.

apiVersion: kudo.dev/v1beta1
appVersion: 0.1.0
kubernetesVersion: 0.16.0
kudoVersion: 0.17.2
maintainers:
- email: ccambo@gmail.com
  name: ccambo
name: galera-operator
operatorVersion: 0.1.0
plans: 
  deploy:
    strategy: serial
    phases:
      - name: deploy
        strategy: serial
        steps:
          - name: bootstrap_config
            tasks:
              - bootstrap_config
          - name: bootstrap_service
            tasks:
              - bootstrap_service
          - name: bootstrap_deploy
            tasks:
              - bootstrap_deploy
          - name: firstboot_config
            tasks:
              - firstboot_config
          - name: cluster_services
            tasks:
              - cluster_services
          - name: statefulset    # 추가
            tasks:
              - statefulset
tasks:
  - name: bootstrap_config
    kind: Apply
    spec:
      resources:
        - bootstrap_config.yaml
  - name: bootstrap_service
    kind: Apply
    spec:
      resources:
        - bootstrap_service.yaml
  - name: bootstrap_deploy
    kind: Apply
    spec:
      resources:
        - bootstrap_deploy.yaml
  - name: firstboot_config
    kind: Apply
    spec:
      resources:
        - galera_config.yaml
  - name: cluster_services
    kind: Apply
    spec:
      resources:
        - hs-service.yaml
  - name: statefulset      # 추가
    kind: Apply
    spec:
      resources:
        - statefulset.yaml

주의

아래의 StatefulSet 설정은 실제 mariadb가 설치되어 동작하는 노드 컨테이너를 생성하는 것이기 때문에 Persistent Volume 구성이 필요하지만 샘플에서는 Kubernetes에 기본 생성되어 있는 Default Storage Class를 이용하는 것으로 되어 있고 Persistent Volume에 대한 언급이 없다.

Kubernetes Cluster를 구성하고 나면 (Test는 Openstack 베이스로 구성) Default Storage가 존재하지 않고, Galera Cluster에 여러 개의 Node들이 참여를 하고 각기 Persitentn Volume을 사용해야 하기 때문에 별도로 NFS (Network File System) 서버를 CentOS 8에 설치하고 Kubernetes에 Dynamic NFS Client Provisioner와 Storage Class를 구성한 것으로 적용했다.

참고 문서

이제 statefulset Task에서 사용할 리소스인 templates/statefulset.yaml 파일을 생성하고 아래와 같이 구성한다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Name }}-{{ .OperatorName }}
  namespace: {{ .Namespace }}
  labels:
    galera: {{ .OperatorName }}
    app: galera
    instance: {{ .Name }}
  annotations:
    reloader.kudo.dev/auto: "true"
spec:
  selector:
    matchLabels:
      app: galera
      galera: {{ .OperatorName }}
      instance: {{ .Name }}
  serviceName: {{ .Name }}-hs
  replicas: {{ .Params.NODE_COUNT }}
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: galera
        galera: {{ .OperatorName }}
        instance: {{ .Name }}
    spec:
      initContainers:
      # Stop the image bootstrap script from trying to set up single master
      - name: {{ .Name }}-init
        image: busybox:1.28
        command: ['sh', '-c', 'set -x; if [ ! -d /datadir/mysql ]; then mkdir /datadir/mysql; fi']
        volumeMounts:
          - name: {{ .Name }}-datadir
            mountPath: "/datadir"
      containers:
      - name: mariadb
        image: mariadb:latest
        args:
        - "--ignore_db_dirs=lost+found"
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: {{ .Params.MYSQL_ROOT_PASSWORD }}
        ports:
        - containerPort: {{ .Params.MYSQL_PORT }}
          name: mysql
        - containerPort: {{ .Params.SST_PORT }}
          name: sst
        - containerPort: {{ .Params.REPLICATION_PORT }}
          name: replication
        - containerPort: {{ .Params.IST_PORT }}
          name: ist
        livenessProbe:
          exec:
            command: ["mysqladmin", "-p{{ .Params.MYSQL_ROOT_PASSWORD }}", "ping"]
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          exec:
            # Check we can execute queries over TCP (skip-networking is off).
            command: ["mysql", "-p{{ .Params.MYSQL_ROOT_PASSWORD }}", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 2
          timeoutSeconds: 1
        volumeMounts:
        - name: {{ .Name }}-config
          mountPath: /etc/mysql/conf.d
        - name: {{ .Name }}-datadir
          mountPath: /var/lib/mysql
      volumes:
      - name: {{ .Name }}-config
        configMap:
          name: {{ .Name }}-nodeconfig
          items:
            - key: galera.cnf
              path: galera.cnf
            - key: innodb.cnf
              path: innodb.cnf
  volumeClaimTemplates:
    - metadata:
        name: {{ .Name }}-datadir
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: {{ .Params.VOLUME_SIZE }}

위의 StatefulSet 구성에는 몇 가지 주의해야할 부분들이 존재한다.

mySQL 데이터 디렉터리를 /var/lib/mysql 경로로 Persistent Volumes를 사용하고, /etc/mysql/conf.d에 configMap의 key/path 정보를 이용해서 설정 파일들을 시작할 때 사용할 수 있도록 마운트한다.

  volumeMounts:
  - name: {{ .Name }}-config
    mountPath: /etc/mysql/conf.d
  - name: {{ .Name }}-datadir
    mountPath: /var/lib/mysql
volumes:
- name: {{ .Name }}-config
  configMap:
    name: {{ .Name }}-nodeconfig
    items:
      - key: galera.cnf
        path: galera.cnf
      - key: innodb.cnf
        path: innodb.cnf

StatefulSet이므로 각 Replica들에 필요한 VolumeClaims들을 추가하는 VolumeClaimTemplate를 정의한다.

volumeClaimTemplates:
  - metadata:
      name: {{ .Name }}-datadir
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: {{ .Params.VOLUME_SIZE }}

MariaDB 컨테이너 이미지는 컨테이너가 처음 시작될 때 단일 노드 인스턴스를 설정하기 위한 부트스트랩 스크립트를 가지고 있다. 샘플에서는 이를 재 정의해서 /var/lib/mysql 경로를 확인해서 데이터베이스가 이미 구성되었다면 부트스트랩 과정을 생략하도록 한다.

init container를 이용해서 데이터 디렉터리를 마운트하고 스크립트가 실행되기 전에 디렉터리를 생성해서 ConfigMap에서 생성한 설정에 따라서 Galera 프로세스가 올바르게 실행되고, 클러스터에 동기화될 수 있도록 재 정의한다.

initContainers:
# Stop the image bootstrap script from trying to set up single master
- name: {{ .Name }}-init
  image: busybox:1.28
  command: ['sh', '-c', 'set -x; if [ ! -d /datadir/mysql ]; then mkdir /datadir/mysql; fi']
  volumeMounts:
    - name: {{ .Name }}-datadir
      mountPath: "/datadir"

NODE_COUNT 파라미터를 이용해서 StatefulSet내에 포함되어야할 Replica의 수를 설정했다.

replicas: {{ .Params.NODE_COUNT }}

PART 1 에서 정의했던 포트 관련 파라미터들을 사용해서 노드들의 mySQL에서 사용할 포트들을 정의했다.

ports:
  - containerPort: {{ .Params.MYSQL_PORT }}
    name: mysql
  - containerPort: {{ .Params.SST_PORT }}
    name: sst
  - containerPort: {{ .Params.REPLICATION_PORT }}
    name: replication
  - containerPort: {{ .Params.IST_PORT }}
    name: ist

새롭게 사용된 VOLUME_SIZE 라는 파라미터를 params.yaml에 추가하도록 한다.

apiVersion: kudo.dev/v1beta1
parameters:
  - name: SST_USER
    description: "User to perform SST as"
    default: "root"
  - name: SST_PASSWORD
    description: "Password for SST user"
    default: "admin"
  - name: MYSQL_PORT
    description: "MySQL port"
    default: "3306"
  - name: SST_PORT
    description: "SST port"
    default: "4444"
  - name: REPLICATION_PORT
    description: "Replication port"
    default: "4567"
  - name: IST_PORT
    description: "IST port"
    default: "4568"
  - name: MYSQL_ROOT_PASSWORD
    description: "MySQL root password"
    default: "admin"
  - name: NODE_COUNT
    description: "Number of nodes to create in the cluster"
    default: "3"
  - name: VOLUME_SIZE     # 추가
    description: "Size of persistent volume"
    default: "10M"

테스트를 위한 것이기 때문에 아주 작은 기본 크기를 추가했다.

지금까지 작업한 것을 기준으로 정상적으로 동작하는지 테스트를 하도록 한다. 테스트를 위한 것이기 때문에 params.yaml 파일에 정의된 NODE_COUNT 파라미터의 기본 값을 1로 변경하고 진행해도 상관없다. StatefulSet은 실제 노드 및 MariaDB도 구성하므로 시간이 오래 걸릴 수 있다.

  • KUDO 설치 (using init)

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --wait  # Webhook TLS를 자체 서명한 버전으로 처리
  • Galera Operator 설치 (using install)

    $ kubectl kudo install ./
  • 설치된 Operator Instance 확인

    $ kubectl kudo plan status --instance=galera-operator-instance
  • 설치된 Pod 확인

    $ kubectl get pods

    실행 중인 클러스터에 모든 인스턴스들이 생성된 것을 확인할 수 있다. 하나의 파드를 선택해서 로그 정보를 통해서 Galera가 정상적으로 동작하고 있는지를 확인한다.

    $ kubectl logs galera-operator-instance-galera-operator-0
  • KUDO 및 Operator 삭제

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --upgrade --dry-run --output yaml | kubectl delete -f -

Conclusion

지금까지의 작업으로 StatefulSet이 올바르게 설정되었고, 모든 노드가 Galera Cluster에 참여하고 있다는 것을 확인할 수 있다.

PART 3 에서는 이제 필요하지 않은 부트스트랩 노드를 제거하고, 클러스터를 외부에서 연결할 수 있도록 설정하고, 운영되는 동안 안정적으로 Scale Up/Down 할 수 있도록 기능을 추가할 것이다.

참고 자료

728x90
반응형
댓글
댓글쓰기 폼