카테고리 없음

mariadb + maxscale

자바바라 2024. 11. 6. 23:28

 

 

Kubernetes 환경에서 MariaDB Replication과 MaxScale을 설정하기 위해 필요한 단계와 리소스 정의를 설명하겠습니다. 이 예제는 `kind` 클러스터에서 진행됩니다.

### 1. Kind 클러스터 생성

먼저, Kind 클러스터를 생성한 후 클러스터에 접속합니다.


kind create cluster
kubectl cluster-info


### 2. MariaDB StatefulSets 생성

MariaDB의 복제를 위해 StatefulSet을 사용하여 마스터와 슬레이브를 생성합니다. 아래는 `mariadb-master`와 `mariadb-slave`라는 StatefulSet을 정의하는 YAML 파일입니다.

#### 2.1. MariaDB ConfigMap 및 Secrets 생성

MariaDB의 환경 변수를 관리할 ConfigMap과 Secrets를 생성합니다.

**mariadb-config.yaml**
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-config
data:
  my.cnf: |
    [mysqld]
    bind-address=0.0.0.0
    log_bin=mysql-bin
    binlog_do_db=mydb
```

**mariadb-secrets.yaml**
```yaml
apiVersion: v1
kind: Secret
metadata:
  name: mariadb-secret
type: Opaque
data:
  root-password: <BASE64_ENCODED_ROOT_PASSWORD>
  replication-password: <BASE64_ENCODED_REPLICATION_PASSWORD>
```

`<BASE64_ENCODED_ROOT_PASSWORD>` 및 `<BASE64_ENCODED_REPLICATION_PASSWORD>`는 각각의 비밀번호를 Base64로 인코딩하여 넣습니다. 예를 들어, `mypassword`의 경우:

echo -n "mypassword" | base64


#### 2.2. MariaDB Master StatefulSet 생성

**mariadb-master.yaml**
```yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb-master
spec:
  serviceName: "mariadb-master"
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
      role: master
  template:
    metadata:
      labels:
        app: mariadb
        role: master
    spec:
      containers:
      - name: mariadb
        image: mariadb:10.5
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: root-password
        - name: MYSQL_DATABASE
          value: mydb
        - name: MYSQL_USER
          value: user
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: replication-password
        - name: MYSQL_REPLICATION_USER
          value: repl
        - name: MYSQL_REPLICATION_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: replication-password
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mariadb-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mariadb-storage
        persistentVolumeClaim:
          claimName: mariadb-master-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mariadb-master-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```

#### 2.3. MariaDB Slave StatefulSet 생성

**mariadb-slave.yaml**
```yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb-slave
spec:
  serviceName: "mariadb-slave"
  replicas: 2
  selector:
    matchLabels:
      app: mariadb
      role: slave
  template:
    metadata:
      labels:
        app: mariadb
        role: slave
    spec:
      containers:
      - name: mariadb
        image: mariadb:10.5
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: root-password
        - name: MYSQL_REPLICATION_USER
          value: repl
        - name: MYSQL_REPLICATION_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: replication-password
        - name: MYSQL_MASTER_HOST
          value: mariadb-master
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mariadb-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mariadb-storage
        persistentVolumeClaim:
          claimName: mariadb-slave-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mariadb-slave-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```

### 3. MaxScale 설정

MaxScale은 MariaDB 클러스터 앞에 배치되어 로드 밸런싱 및 SQL 라우팅을 제공하는 프록시입니다.

**maxscale.yaml**
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: maxscale
spec:
  replicas: 1
  selector:
    matchLabels:
      app: maxscale
  template:
    metadata:
      labels:
        app: maxscale
    spec:
      containers:
      - name: maxscale
        image: mariadb/maxscale:2.5
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: maxscale-config
          mountPath: /etc/maxscale.cnf
          subPath: maxscale.cnf
      volumes:
      - name: maxscale-config
        configMap:
          name: maxscale-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: maxscale-config
data:
  maxscale.cnf: |
    [maxscale]
    threads=4

    [MariaDB Monitor]
    type=monitor
    module=mariadbmon
    servers=mariadb-master,mariadb-slave
    user=repl
    password=<REPLICATION_PASSWORD>
    monitor_interval=10000

    [Read-Write Service]
    type=service
    router=readwritesplit
    servers=mariadb-master,mariadb-slave
    user=user
    password=<MYSQL_PASSWORD>

    [Read-Only Service]
    type=service
    router=readconcurrency
    servers=mariadb-slave
    user=user
    password=<MYSQL_PASSWORD>
```

### 4. 리소스 적용

위에서 작성한 YAML 파일들을 Kubernetes 클러스터에 적용합니다.

kubectl apply -f mariadb-config.yaml
kubectl apply -f mariadb-secrets.yaml
kubectl apply -f mariadb-master.yaml
kubectl apply -f mariadb-slave.yaml
kubectl apply -f maxscale.yaml


### 5. 서비스 생성

MariaDB와 MaxScale의 접근을 위해 서비스 리소스를 생성합니다.

**services.yaml**
```yaml
apiVersion: v1
kind: Service
metadata:
  name: mariadb-master
spec:
  ports:
  - port: 3306
  selector:
    app: mariadb
    role: master
---
apiVersion: v1
kind: Service
metadata:
  name: mariadb-slave
spec:
  ports:
  - port: 3306
  selector:
    app: mariadb
    role: slave
---
apiVersion: v1
kind: Service
metadata:
  name: maxscale
spec:
  ports:
  - port: 3306
  selector:
    app: maxscale
```

이 파일도 클러스터에 적용합니다.


kubectl apply -f services.yaml


### 6. 확인

모든 리소스가 올바르게 생성되었는지 확인합니다.

kubectl get pods
kubectl get services


이제 MaxScale을 통해 MariaDB에 접근할 수 있으며, 읽기 및 쓰기 요청을 분산할 수 있습니다. MaxScale의 IP 주소로 연결하여 MariaDB 클러스터에 접근할 수 있습니다.

### 7. MariaDB 연결 예시

MaxScale에 연결하려면, MaxScale 서비스의 IP 주소 또는 DNS를 사용합니다.


mysql -h <maxscale_service_ip> -u user -p


이렇게 하면 MariaDB Replication과 MaxScale이 설정된 Kubernetes 클러스터가 준비됩니다.
cat <<EOT> kind-metallb.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
networking:
  podSubnet: "172.16.0.0/16"
  serviceSubnet: "10.200.0.0/24"
  kubeProxyMode: "ipvs"
EOT



vi mariadb-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-configmap
  namespace: mariadb
data:
  primary.cnf: |
    [mariadb]
    log-bin
    binlog-format=ROW
    log_slave_updates=ON
    
  replica.cnf: |
    [mariadb]
    log-bin
    read_only=1
    log_slave_updates=ON
    
  primary.sql: |
    CREATE USER 'repluser'@'%' IDENTIFIED BY 'replsecret';
    GRANT REPLICATION REPLICA ON *.* TO 'repluser'@'%';  
    
    CREATE USER 'maxscale'@'%' IDENTIFIED BY 'maxscale_pw';
    GRANT SELECT ON mysql.user TO 'maxscale'@'%';
    GRANT SELECT ON mysql.db TO 'maxscale'@'%';
    GRANT SELECT ON mysql.tables_priv TO 'maxscale'@'%';
    GRANT SELECT ON mysql.columns_priv TO 'maxscale'@'%';
    GRANT SELECT ON mysql.procs_priv TO 'maxscale'@'%';
    GRANT SELECT ON mysql.proxies_priv TO 'maxscale'@'%';
    GRANT SELECT ON mysql.roles_mapping TO 'maxscale'@'%';
    GRANT SHOW DATABASES ON *.* TO 'maxscale'@'%';
    GRANT REPLICATION CLIENT ON *.* TO 'maxscale'@'%';
    GRANT SELECT ON mysql.* TO 'maxscale'@'%';
    GRANT ALL PRIVILEGES ON *.* TO 'maxscale'@'%' WITH GRANT OPTION;
    FLUSH PRIVILEGES;
    
  secondary.sql: |
    CHANGE MASTER TO
    MASTER_HOST='mariadb-0.mariadb-service.mariadb.svc.cluster.local',
    MASTER_USER='repluser',
    MASTER_PASSWORD='replsecret',
    MASTER_CONNECT_RETRY=10;
    
    

kubectl apply -f mariadb-configmap.yaml



vi mariadb-statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb
  namespace: mariadb
spec:
  serviceName: "mariadb-service"
  replicas: 3
  selector:
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      initContainers:
      - name: init-mariadb
        image: mariadb:10.10.3
        command:
        - bash
        - "-c"
        - |
          set -ex
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          server_id=$((100 + ordinal))
          if [[ $ordinal -eq 0 ]]; then
            cp /mnt/config-map/primary.cnf /etc/mysql/conf.d/server-id.cnf
            cp /mnt/config-map/primary.sql /docker-entrypoint-initdb.d/
          else
            cp /mnt/config-map/replica.cnf /etc/mysql/conf.d/server-id.cnf
            cp /mnt/config-map/secondary.sql /docker-entrypoint-initdb.d/
          fi
        volumeMounts:
        - name: conf
          mountPath: /etc/mysql/conf.d
        - name: config-map
          mountPath: /mnt/config-map
        - name: initdb
          mountPath: /docker-entrypoint-initdb.d
      containers:
      - name: mariadb
        image: mariadb:10.10.3
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpassword"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: datadir
          mountPath: /var/lib/mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        - name: initdb
          mountPath: /docker-entrypoint-initdb.d
      volumes:
      - name: conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: mariadb-configmap
      - name: initdb
        emptyDir: {}
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

kubectl apply -f mariadb-statefulset.yaml


# kubectl scale statefulset mariadb-statefulset --replicas=3


vi mariadb-service.yaml


apiVersion: v1
kind: Service
metadata:
  name: mariadb-service
  namespace: mariadb
spec:
  selector:
    app: mariadb
  ports:
  - port: 3306
  clusterIP: None


kubectl apply -f mariadb-service.yaml



vi maxscale-configmap.yaml

kind: ConfigMap
metadata:
  name: maxscale-config
  namespace: mariadb
data:
  maxscale.cnf: |
    [maxscale]
    threads=auto
    admin_host=0.0.0.0
    admin_port=8989
    admin_secure_gui=false
    config_sync_cluster=MariaDB-Monitor
    config_sync_user=maxscale
    config_sync_password=maxscale_pw

    [server1]
    type=server
    address=mariadb-0.mariadb-service.mariadb.svc.cluster.local
    port=3306
    protocol=MariaDBBackend

    [server2]
    type=server
    address=mariadb-1.mariadb-service.mariadb.svc.cluster.local
    port=3306
    protocol=MariaDBBackend

    [server3]
    type=server
    address=mariadb-2.mariadb-service.mariadb.svc.cluster.local
    port=3306
    protocol=MariaDBBackend

    [MariaDB-Monitor]
    type=monitor
    module=mariadbmon
    servers=server1,server2,server3
    user=maxscale
    password=maxscale_pw
    monitor_interval=2000ms
    auto_failover=true
    auto_rejoin=true

    [Read-Write-Service]
    type=service
    router=readwritesplit
    servers=server1,server2,server3
    user=maxscale
    password=maxscale_pw
    causal_reads=true
    causal_reads_timeout=10s

causal_reads=fast: 가장 빠른 방법이지만, 슬레이브가 항상 지연되는 경우 마스터에 모든 읽기가 집중될 수 있습니다.
causal_reads=local: 현재 연결에서 데이터 변경이 있을 경우, MaxScale은 슬레이브가 해당 데이터를 복제할 때까지 최대 causal_reads_timeout 시간(기본값 10초) 동안 기다립니다.
causal_reads=global: local과 유사하지만, 모든 사용자의 데이터 변경을 고려합니다.

    [Read-Write-Listener]
    type=listener
    service=Read-Write-Service
    protocol=MariaDBClient
    port=3306



kubectl apply -f maxscale-configmap.yaml



vi maxscale-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: maxscale
  namespace: mariadb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: maxscale
  template:
    metadata:
      labels:
        app: maxscale
    spec:
      containers:
      - name: maxscale
        image: mariadb/maxscale:latest
        ports:
        - containerPort: 3306
        - containerPort: 8989
        volumeMounts:
        - name: config
          mountPath: /etc/maxscale.cnf
          subPath: maxscale.cnf
      volumes:
      - name: config
        configMap:
          name: maxscale-config


kubectl apply -f maxscale-deployment.yaml



vi maxscale-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: maxscale
  namespace: mariadb
spec:
  selector:
    app: maxscale
  ports:
  - port: 3306
    targetPort: 3306
    name: db
  - port: 8989
    targetPort: 8989
    name: admin
  type: NodePort


kubectl apply -f maxscale-service.yaml