기본 콘텐츠로 건너뛰기

[Kubernetes - Operator] KUDO를 활용한 Galera Operator 단계별로 적용하기 - PART 1: Bootstrap Node 구성

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

게시글 참고

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

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

이 문서는 KUDO Blog 샘플을 기준으로 테스트하면서 발생한 문제점들을 해결하고 동작을 검증하면서 정리한 내용으로 Galera 클러스터 구성을 위한 Bootstap Node 설정을 다룬다.

참고

  • 이 문서는 KUDO에 대한 이해를 어느 정도 하고 있다는 것을 전제로 하며 MariaDB의 오픈 소스 클러스터링 솔루션인 Galera를 위한 Operator를 KUDO를 이용해서 만드는 과정을 정리한 것이다.
  • 이 문서는 KUDO v0.17.0 기준으로 작성되었다.

KUDO에 관련된 정보는 이전 글들 참고

환경 설정

  • 파일 시스템 레이아웃 구성

    우선 작업할 내용은 개발 및 테스트 환경을 구성하는 것이다. 이전 글들에서 언급했던 것과 같이 아래와 같은 구성이 필요하다. (KUDO-CLI 명령을 통해서 구조 및 기본 파일들을 생성할 수 있다.)

    작업할 대상은 ~/kudo_sample/galera-operator 폴더를 기준으로 한다.

    .
    └── operator
        ├── operator.yaml
        ├── params.yaml
        └── templates
    

    2 directories, 2 files

    생성된 operator.yaml 파일은 아래와 같이 구성한다.

    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: {}
    tasks: []

    생성된 params.yaml 파일은 아래와 같이 구성한다.

    apiVersion: kudo.dev/v1beta1
    parameters: []

    그리고 자동으로 생성되지 않는 templates 디렉터리도 생성해 놓는다.

  • 배포 계획 생성

    가장 먼저 작업할 내용은 모든 Operator가 반드시 가지고 있어야 할 배포 계획을 구성하는 것이다. (operator.yaml)

    ...
    plans:
      deploy:
        strategy: serial
        phases:
          - name: deploy
            strategy: serial
            steps:
    ...

    위와 같이 기본 배포 계획 구성을 추가한다.

Bootstrap Config 설정

Galera 클러스터를 배포할 때 Bootstrap을 위해 수행할 단계가 존재하기 때문에 부트스트랩 노드를 구성해야 한다. 이 부트스트랩 노드는 클러스터의 다른 노드와 구성이 다르므로 이를 배포하기 위해서 구성해야 한다.

ConfigMap 리소스를 이용해서 부트스트랩 컨테이너에 전달해야 한다. 따라서 배포 계획에 Phases와 Steps를 추가해서 이를 처리하기 위한 구성을 아래와 같이 처리한다. (operator.yaml)

...
plans:
  deploy:
    strategy: serial
    phases:
      - name: deploy
        strategy: serial
        steps:
          - name: bootstrap_config
            tasks:
              - bootstrap_config
tasks:
  - name: bootstrap_config
    kind: Apply
    spec:
      resources:
        - bootstrap_config.yaml
...

지금까지의 작업으로 완성한 ~/kudo_sample/galera-operator/operator/operator.yaml 파일의 내용은 다음과 같다.

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
tasks:
  - name: bootstrap_config
    kind: Apply
    spec:
      resources:
        - bootstrap_config.yaml

위에서 추가한 Step/Task 의 내용은 부트스트랩 노드를 위한 ConfigMap 리소스를 사용하겠다는 의미로 templates/bootstrap_config.yaml 파일을 생성하고 아래와 같이 구성한다. (bootstrap_config.yaml)

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Name }}-bootstrap
  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://
    wsrep_sst_auth = "{{ .Params.SST_USER }}:{{ .Params.SST_PASSWORD }}"
    binlog_format = ROW

위의 설정 내용은 ConfigMap 리소스로 단일 데이터로 galera.cnf 파일의 내용으로 Galera 설정 내용이다.

  • wsrep_cluster_address = gcomm://: 이 설정을 통해서 이 노드가 부트스트랩 노드가 될 것을 지정한 것이다.
  • name: {{ .Name }}-bootstrap: 각 KUDO Instance에 유일한 값을 지정하는 것으로 ConfigMap도 유일한 이름으로 지정하기 위한 것이다.
  • namespace: {{ .Namespace }}: 네임스페이스에 속한 리소스로 한정되도록 하는 것이다.
  • wsrep_sst_auth = "{{ .Params.SST_USER }}:{{ .Params.SST_PASSWORD }}": 노드 간의 동기화를 위해 Galera 클러스터 내부적으로 사용할 자격 증명을 지정한 것이다.

이제 ConfigMap에서 사용하도록 지정한 파라미터들 (.Params로 시작하는)을 정의하기 위해 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"

위의 내용은 SST_USER, SST_PASSWORD 파라미터를 정의하고 기본 값을 설정한 것이다.

주의

일반적으로 Secret 리소스에 민감한 정보를 구성하는 것을 권장한다. 위와 같이 파라미터로 설정하는 방식은 암호화되지 않고 클러스터에 저장되기 때문에 쉽게 노출될 수 있다.

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

  • KUDO 설치 (using init)

    가장 먼저 작업할 내용은 KUDO Operator 설치로 아래와 같이 수행한다.

    $ kubectl kudo init --unsafe-self-signed-webhook-ca --wait  # Webhook TLS를 자체 서명한 버전으로 처리
    

    $KUDO_HOME has been configured at /home/centos/.kudo Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition ✅ installed crds ✅ installed namespace ✅ installed service account Warning: admissionregistration.k8s.io/v1beta1 MutatingWebhookConfiguration is deprecated in v1.16+, unavailable in v1.22+; use admissionregistration.k8s.io/v1 MutatingWebhookConfiguration ✅ installed webhook ✅ installed kudo controller ⌛Waiting for KUDO controller to be ready in your cluster… ✅ KUDO is ready!

  • Galera Operator 설치 (using install)

    설치된 KUDO Operator에 작성한 Galera Operator를 설치한다. (KUDO는 Respository를 지원하지만 이번에는 로컬 디렉터리 (~/kudo_sample/galera-operator/operator)를 기준으로 설치한다.)

    $ kubectl kudo install ./
    

    Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition operator default/galera-operator created operatorversion default/galera-operator-0.1.0-0.1.0 created instance default/galera-operator-instance created

    설치할 때 Instance 이름을 별도로 지정하지 않았기 때문에 패키지 이름을 그대로 사용한다. (galera-operator => galera-operator-instance가 된다)

  • 설치된 Operator Instance 확인

    설치된 Instance 정보는 아래와 같이 확인할 수 있다.

    $ kubectl kudo plan status --instance=galera-operator-instance
    

    Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition Plan(s) for “galera-operator-instance” in namespace “default”: . └── galera-operator-instance (Operator-Version: “galera-operator-0.1.0-0.1.0” Active-Plan: “deploy”) └── Plan deploy (serial strategy) [COMPLETE], last updated 2020-12-23 06:17:06 └── Phase deploy (serial strategy) [COMPLETE] └── Step bootstrap_config [COMPLETE]

  • 설치된 ConfigMap 확인

    deploy plan의 bootstrap_config step으로 생성된 ConfigMap은 아래와 같이 확인할 수 있다.

    $ kubectl get configmaps
    

    NAME DATA AGE galera-operator-instance-bootstrap 1 21m

    생성된 ConfigMap의 내용은 아래와 같이 확인할 수 있다.

    $ kubectl describe configmap galera-operator-instance-bootstrap
    
    Name:         galera-operator-instance-bootstrap
    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-bootstrap","namespace":"default","creationTimestamp":nu...
                  kudo.dev/last-plan-execution-uid: 3bb3d148-b420-47d5-83d9-baef16c4095c
                  kudo.dev/phase: deploy
                  kudo.dev/plan: deploy
                  kudo.dev/step: bootstrap_config
    
    Data
    ====
    galera.cnf:
    ----
    [galera]
    wsrep_on = ON
    wsrep_provider = /usr/lib/galera/libgalera_smm.so
    wsrep_sst_method = mariabackup
    wsrep_cluster_address = gcomm://
    wsrep_sst_auth = "root:admin"
    binlog_format = ROW
    
    Events:  
  • KUDO 및 Operator 삭제

    지금까지 작업한 내용이 적용된 것을 확인했으므로 다음 작업을 위해서 KUDO Operator를 포함한 설치된 모든 리소스들을 삭제하도록 한다.

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

    Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition customresourcedefinition.apiextensions.k8s.io “operators.kudo.dev” deleted customresourcedefinition.apiextensions.k8s.io “operatorversions.kudo.dev” deleted customresourcedefinition.apiextensions.k8s.io “instances.kudo.dev” deleted namespace “kudo-system” deleted serviceaccount “kudo-manager” deleted clusterrolebinding.rbac.authorization.k8s.io “kudo-manager-rolebinding” deleted Warning: admissionregistration.k8s.io/v1beta1 MutatingWebhookConfiguration is deprecated in v1.16+, unavailable in v1.22+; use admissionregistration.k8s.io/v1 MutatingWebhookConfiguration mutatingwebhookconfiguration.admissionregistration.k8s.io “kudo-manager-instance-admission-webhook-config” deleted secret “kudo-webhook-server-secret” deleted service “kudo-controller-manager-service” deleted statefulset.apps “kudo-controller-manager” deleted

Bootstrap 서비스 구성

다음 작업은 부트스트랩 서비스를 정의하는 것으로, 클러스터 노드가 배포되면 부트스트랩 노드에 연결하기 때문에 이를 위한 서비스를 정의하는 과정이다.

  • operator.yaml 파일에 bootstrap_service step 추가
  • operator.yaml 파일에 bootstrap_service task 추가
  • task에서 사용할 bootstrap_service.yaml 설정

위의 같은 작업을 처리한 operator.yaml은 다음과 같다.

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
tasks:
  - name: bootstrap_config
    kind: Apply
    spec:
      resources:
        - bootstrap_config.yaml
  - name: bootstrap_service
    kind: Apply
    spec:
      resources:
        - bootstrap_service.yaml

이제 Task에 리소스로 정의한 부트스트랩 서비스 리소스 파일을 templates/bootstrap_service.yaml 파일에 아래와 같이 구성한다.

apiVersion: v1
kind: Service
metadata:
  name: {{ .Name }}-bootstrap-svc
  namespace: {{ .Namespace }}
  labels:
    app: galera-bootstrap
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 
  selector:
    app: galera-bootstrap
    instance: {{ .Name }}
  clusterIP: None
  • name: {{ .Name }}-bootstrap-svc: 서비스의 이름도 고유한 값으로 설정
  • app: galera-bootstrap: 이 서비스를 사용하는 모든 인스턴스들을 관리하는데 사용할 레이블 설정
  • port: {{ .Params.MYSQL_PORT }}: mySQL 사용 포트를 파라미터와 연동하도록 설정
  • port: {{ .Params.SST_PORT }}: SST 연계용 포트를 파라미터와 연동하도록 설정
  • port: {{ .Params.REPLICATION_PORT }}: Replication용 포트를 파라미터와 연동하도록 설정
  • port: {{ .Params.IST_PORT }}: IST용 포트를 파라미터와 연동하도록 설정
  • instance: {{ .Name }}: 부트스트랩 인스턴스 Selector 설정

이 특별한 서비스는 하나의 인스턴스만 사용하기 때문에 클러스터 IP는 필요하지 않고, 서비스는 Headless일 수 있으며 Kubernetes는 관련된 DNS Endpoint를 생성하게 된다.

서비스를 정의하면서 추가로 사용한 파라미터들을 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"

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

  • 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
    

    Plan(s) for “galera-operator-instance” in namespace “default”: . └── galera-operator-instance (Operator-Version: “galera-operator-0.1.0-0.1.0” Active-Plan: “deploy”) └── Plan deploy (serial strategy) [COMPLETE], last updated 2020-12-23 07:48:27 └── Phase deploy (serial strategy) [COMPLETE] ├── Step bootstrap_config [COMPLETE] └── Step bootstrap_service [COMPLETE]

  • 설치된 Service 확인

    deploy plan의 bootstrap_service step으로 생성된 service는 아래와 같이 확인할 수 있다.

    $ kubectl get services
    

    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE galera-operator-instance-bootstrap-svc ClusterIP None 3306/TCP,4444/TCP,4567/TCP,4568/TCP 80s kubernetes ClusterIP 10.96.0.1 443/TCP 21d

    생성된 서비스의 상세 정보는 아래와 같이 확인할 수 있다.

    $ kubectl describe service galera-operator-instance-bootstrap-svc
    
    Name:              galera-operator-instance-bootstrap-svc
    Namespace:         default
    Labels:            app=galera-bootstrap
                      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-bootstrap-svc","namespace":"default","creationTimestamp":...
                      kudo.dev/last-plan-execution-uid: 7fdc50f2-86b3-4a5f-adb1-eb6c57a90c81
                      kudo.dev/phase: deploy
                      kudo.dev/plan: deploy
                      kudo.dev/step: bootstrap_service
    Selector:          app=galera-bootstrap,instance=galera-operator-instance
    Type:              ClusterIP
    IP:                None
    Port:              mysql  3306/TCP
    TargetPort:        3306/TCP
    Endpoints:         
    Port:              sst  4444/TCP
    TargetPort:        4444/TCP
    Endpoints:         
    Port:              replication  4567/TCP
    TargetPort:        4567/TCP
    Endpoints:         
    Port:              ist  4568/TCP
    TargetPort:        4568/TCP
    Endpoints:         
    Session Affinity:  None
    Events:            

    위의 결과와 같이 레이블과 포트 및 정의된 정보들이 제대로 설정된 것을 확인할 수 있다. 지금 시점에는 서비스를 사용할 부트스트랩 노드의 실제 인스턴스가 없기 때문에 Endpoint 정보가 없다.

  • KUDO 및 Operator 삭제

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

Bootstrap Node 배포

마지막 작업으로 위에서 설정한 Config, Service를 사용할 부트스트랩 노드의 실제 인스턴스를 배포하는 것이다.

  • operator.yaml 파일에 bootstrap_deploy step 추가
  • operator.yaml 파일에 bootstrap_deploy task 추가
  • task에서 사용할 templates/bootstrap_deploy.yaml 파일 추가

위의 같은 작업을 처리한 operator.yaml은 다음과 같다.

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
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

이제 Task에 리소스로 정의한 부트스트랩 배포 리소스 파일을 templates/bootstrap_deploy.yaml 파일에 아래와 같이 구성한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Name }}-bootstrap
  namespace: {{ .Namespace }}
  labels:
    app: galera-bootstrap
    instance: {{ .Name }}
spec:
  selector:
    matchLabels:
      app: galera-bootstrap
      instance: {{ .Name }}
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: galera-bootstrap
        instance: {{ .Name }}
    spec:
      containers:
      - image: mariadb:latest
        name: mariadb
        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 }}-bootstrap
          mountPath: /etc/mysql/conf.d
      volumes:
        - name: {{ .Name }}-bootstrap
          configMap:
            name: {{ .Name }}-bootstrap
            items:
            - key: galera.cnf
              path: galera.cnf

이전에 정의한 리소스들에 비해서는 복잡해 보이지만 몇 가지만 추가된 것이다. 주요한 몇 가지는 아래와 같다.

selector:
  matchLabels:
    app: galera-bootstrap
    instance: {{ .Name }}

리소스를 연결하는데 사용할 레이블과 인스턴스를 지정한 것이다.

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

컨테이너에서 사용할 포트들을 파라미터와 연계해서 지정한 것이다.

env:
  # Use secret in real usage
- name: MYSQL_ROOT_PASSWORD
  value: {{ .Params.MYSQL_ROOT_PASSWORD }}

env 섹션을 통해서 파라미터와 연계된 mySQL root 사용자 비밀번호를 저정한 것이다.

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

livenessProbe와 readinessProbe를 통해서 접근이 가능한지와 사용할 수 있는지에 대한 검증 명령을 지정한 것이다.

  volumeMounts:
  - name: {{ .Name }}-bootstrap
    mountPath: /etc/mysql/conf.d
volumes:
  - name: {{ .Name }}-bootstrap
    configMap:
      name: {{ .Name }}-bootstrap
      items:
      - key: galera.cnf
        path: galera.cnf

ConfigMap이 정의된 Volume을 설정하고 컨테이너에서 사용할 수 있도록 마운트하는 것을 지정한 것이다. Volume도 유일한 이름으로 지정되어야 하고, ConfigMap에서 찾아야할 부분을 Key/Path로 지정해서 마운트될 때 /etc/mysql/conf.d 라는 이름의 파일로 처리될 수 있도록 지정한 것이다.

배포를 정의하면서 추가로 사용한 파라미터들을 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"

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

  • 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
    

    Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition Plan(s) for “galera-operator-instance” in namespace “default”: . └── galera-operator-instance (Operator-Version: “galera-operator-0.1.0-0.1.0” Active-Plan: “deploy”) └── Plan deploy (serial strategy) [IN_PROGRESS], last updated 2020-12-23 09:23:50 └── Phase deploy (serial strategy) [IN_PROGRESS] ├── Step bootstrap_config [COMPLETE] ├── Step bootstrap_service [COMPLETE] └── Step bootstrap_deploy [IN_PROGRESS]

    위의 Plan 정보 중에 Phase, Step 이 IN_PROGRESS로 나타나는 것은 실제 컨테이너가 구동되는 시간이 (이미지를 다운로드하고 구성하는 등의 시간) 필요하기 때문에 나타나는 것으로 시간이 지나면 정상적으로 표시된다. 만일 실패가 되면 원인을 찾아서 다시 처리해야 한다.

    참고

  • Docker의 상용화 정책으로 인해서 Docker Repository에서 Image를 다운로드하는 부분에 Rate Limit가 설정되어 있기 때문에 오류가 발생할 수도 있다.

  • 설치된 Bootstrap Node 확인

    부트스트랩 노드 인스턴스를 배포한 것이기 때문에 Pod가 생성되어 동작하는지를 아래와 같이 확인할 수 있다.

    $ kubectl get pods
    NAME                                                  READY   STATUS    RESTARTS   AGE
    galera-operator-instance-bootstrap-59855f6884-gz4rr   1/1     Running   0          5m7s

    정상적으로 생성되어 동작하는 로그 정보는 아래와 같이 확인할 수 있다.

    $ kubectl logs galera-operator-instance-bootstrap-59855f6884-gz4rr
    

    … 2020-12-23 9:24:04 0 [Note] WSREP: Server initialized 2020-12-23 9:24:04 0 [Note] WSREP: Server status change initializing -> initialized 2020-12-23 9:24:04 0 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification. 2020-12-23 9:24:04 2 [Note] WSREP: Bootstrapping a new cluster, setting initial position to 00000000-0000-0000-0000-000000000000:-1 2020-12-23 9:24:04 4 [Note] WSREP: Cluster table is empty, not recovering transactions 2020-12-23 9:24:04 2 [Note] WSREP: Server status change initialized -> joined 2020-12-23 9:24:04 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification. 2020-12-23 9:24:04 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification. 2020-12-23 9:24:04 0 [Note] Reading of all Master_info entries succeeded 2020-12-23 9:24:04 0 [Note] Added new Master_info ‘’ to hash table 2020-12-23 9:24:04 0 [Note] mysqld: ready for connections. …

    위의 로그 결과와 같이 Galera 가 구성되었고 가입이 가능하도록 준비된 새 클러스터를 생성한 것을 확인할 수 있다.

    그리고 ConfigMap이 제대로 마운트되어 실행되어 있는지는 아래와 같이 동작하는 컨테이너에 연결해서 확인할 수 있다.

    $ kubectl exec -it galera-operator-instance-bootstrap-59855f6884-gz4rr /bin/bash
    

    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] – [COMMAND] instead.

    root@galera-operator-instance-bootstrap-59855f6884-gz4rr:/# ls /etc/mysql/conf.d/ galera.cnf

    root@galera-operator-instance-bootstrap-59855f6884-gz4rr:/# cat /etc/mysql/conf.d/galera.cnf

    [galera] wsrep_on = ON wsrep_provider = /usr/lib/galera/libgalera_smm.so wsrep_sst_method = mariabackup wsrep_cluster_address = gcomm:// wsrep_sst_auth = “root:admin” binlog_format = ROW

    그리고 bootstrap_service를 구성했을 때 지정되지 않았던 endpoint가 제대로 설정되었는지는 아래와 같이 확인할 수 있다.

    $ kubectl describe service galera-operator-instance-bootstrap-svc
    
    Name:              galera-operator-instance-bootstrap-svc
    Namespace:         default
    Labels:            app=galera-bootstrap
                      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-bootstrap-svc","namespace":"default","creationTimestamp":...
                      kudo.dev/last-plan-execution-uid: 11aebdd4-ff44-4f5c-a166-1bd56a9213ff
                      kudo.dev/phase: deploy
                      kudo.dev/plan: deploy
                      kudo.dev/step: bootstrap_service
    Selector:          app=galera-bootstrap,instance=galera-operator-instance
    Type:              ClusterIP
    IP:                None
    Port:              mysql  3306/TCP
    TargetPort:        3306/TCP
    Endpoints:         10.244.84.141:3306
    Port:              sst  4444/TCP
    TargetPort:        4444/TCP
    Endpoints:         10.244.84.141:4444
    Port:              replication  4567/TCP
    TargetPort:        4567/TCP
    Endpoints:         10.244.84.141:4567
    Port:              ist  4568/TCP
    TargetPort:        4568/TCP
    Endpoints:         10.244.84.141:4568
    Session Affinity:  None
    Events:            
  • KUDO 및 Operator 삭제

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

Conclusion

지금까지의 작업으로 완전하게 동작하는 Galera Bootstrap Node가 구성되어 연결을 수신힐 준비가 되었다는 것을 확인해 보았다.

PART 2에서는 더 많은 Operator 기능을 구성해서 노드들을 추가하고 클러스터에 참여하도록 하는 방법을 검토해 본다.

참고 자료

댓글

이 블로그의 인기 게시물

OData 에 대해서 알아보자.

얼마 전에 어떤 회사에 인터뷰를 하러 간 적이 있었다. 당시 그 회사는 자체 솔루션을 개발할 기술인력을 찾고 있었고 내부적으로 OData를 사용한다고 했다. 좀 창피한 이야기일 수도 있지만 나름 기술적인 부분에서는 많은 정보를 가지고 있다고 했던 것이 무색하게 OData란 단어를 그 회사 사장님에게서 처음 들었다. 작고, 단순한 사이트들만을 계속해서 작업을 하다 보니 어느덧 큰 줄기들을 잃어버린 것을 느끼기 시작했다. 명색이 개발이 좋고, 기술적인 기반을 만들려고 하는 인간이 단어조차도 모른다는 것은 있을 수 없는 것이라서 다시 새로운 단어들과 개념들을 알아보는 시간을 가지려고 한다. OData (Open Data Protocol) 란? 간단히 정리하면 웹 상에서 손쉽게 데이터를 조회하거나 수정할 수 있도록 주고 받는 웹(프로토콜)을 말한다. 서비스 제공자 입장에서는 웹으로 데이터를 제공하는 방식으로 각 포탈 사이트들이 제공하는 OPEN API 포맷을 독자적인 형식이 아니라 오픈된 공통규약으로 제공 가능하며, 개발자는 이 정보를 다양한 언어의 클라이언트 라이브러리로 어플리케이션에서 소비할 수 있도록 사용하면 된다. 공식 사이트는 www.odata.org 이며 많은 언어들을 지원하고 있다. 좀더 상세하게 정의를 해 보면 OData는 Atom Publishing Protocol  (RFC4287) 의 확장 형식이고 REST (REpresentational State Transfer) Protocol 이다. 따라서 웹 브라우저에서 OData 서비스로 노출된 데이터를 볼 수 있다. 그리고 AtomPub 의 확장이라고 했듯이 데이터의 조회만으로 한정되는 것이 아니라 CRUD 작업이 모두 가능하다. Example 웹 브라우저에서 http://services.odata.org/website/odata.svc 를 열어 보도록 하자. This XML file does not appear to have any style in...

C# 에서 Timer 사용할 때 주의할 점.

예전에 알고 지내시던 분의 질문을 받았다. Windows Forms 개발을 하는데, 주기적 (대략 1분)으로 데이터 요청을 하는 프로그램을 작성하기 위해서 Timer 를 사용하는데, 어떤 기능을 처리해야 하기 때문에 Sleep 을 같이 사용했다고 한다. 여기서 발생하는 문제는 Sleep 5초를 주었더니, Timer 까지 5초 동안 멈춘다는 것이다. Timer 라는 것은 기본적으로 시간의 흐름을 측정하는 기능이기 때문에 Sleep 을 했다고 해서 Timer 가 멈추는 일은 생겨서는 안된다. 그러나 실제 샘플을 만들어 보면 ... Timer 가 Sleep 만큼 동작이 멈추는 것을 확인할 수 있다. Windows Forms 는 UI Thread 를 사용하는 것으로 최적화 되어 있으며 여기서 Timer 를 쓰면 UI Thread 에 최적화된 System.Windows.Forms.Timer 가 사용된다. 여기서 문제의 발생이 시작되는 것이다. Sleep 을 사용하게 되면 UI Thread 가 Sleep 이 걸리기 때문에 여기에 속한 Timer 까지도 멈추는 것이다. 이런 문제를 해결하기 위해서는 System.Threading.Timer 를 사용해야 한다. 이 Timer 는 별도의 Thread 에서 동작하기 때문에 Sleep 의 영향을 받지 않는다. 언뜻 보면 쉬운 해결 방법인 것 같지만 Thread 가 분리되었기 때문에 Timer 가 돌아가는 Thread 에서 UI Thread 의 메서드나 컨트롤에 접근하기 위해서는 별도의 명령을 사용해야 하는 문제가 존재한다. 자~ 그럼 여기서 Timer 에 대해서 다시 한번 정리해 보도록 하자. .NET 에서 제공하는 Timer 들 .NET 에서는 기본적으로 3가지 Timer를 제공하고 있다. (MSDN) System.Windows.Forms.Timer - 사용자가 지정한 간격마다 이벤트를 발생시키며 Windows Forms 응용 프로그램에서 사용할 수 있도록 최적화 되어 있다. System...

[Logging] NLog 사용법 정리...

SCSF 에는 기본적으로 Enterprise Library가 사용된다. 예전에도 그랬지만 기능은 훌륭하고 많은 부분에서 최적화(?)된 것일지도 모르지만, 역시나 사용하기에는 뭔가 모르게 무겁고, 사용하지 않는 기능이 더 많다라는 느낌을 지울수가 없다. 이번 프로젝트도 SCSF를 기반으로 하고 있지만, Enterprise Library를 걷어내고 각 부분에 전문화된 오픈 소스를 사용하기로 하였다. 예전에는 Log4Net을 사용했지만, 대량 사용자 환경에서는 메모리 누수와 기타 문제점이 존재한다는 MS 컨설턴트(?)의 전해진 말을 들은 후로는 사용하지 않는다. 대안으로 사용하는 것이 NLog 이다. 조금 후에는 3.0 버전도 나온다고 홈 페이지에 기재되어 있지만, 그 때가 되면 프로젝트는 끝나기 때문에 현재 2.1.0 버전을 사용하기로 했다. [원본 출처] http://cloverink.net/most-useful-nlog-configurations-closed/ 위의 참조 자료에는 다양한 정보들이 존재하므로 꼭 링크를 통해서 관련된 정보를 확인하고 이해하는 것이 좋을 듯 하다. 여기서는 당장 필요한 부분만을 정리하도록 한다. [ Logger 찾기 ] 기본적으로 Logger가 존재하는 클래스를 기반으로 Logger 정보를 구성한다. Logger logger = LogManager.GetCurrentClassLogger(); 주로 Namespace 기반으로 Logger를 설정하는 경우에 유연하게 사용할 수 있다. 또 다른 방법으로는 지정한 문자열로 특정 Logger를 직접 선택하는 방법도 제공된다. 이를 혼용해서 Namespace와 직접 지정 방식을 같이 사용할 수도 있다. 물론 Logger 환경 설정에서 Wildcard (*)를 지정할 수도 있다. Logger logger = LogManager.GetLogger("Database.Connect"); Logger logger = LogManager.Get...