目录

基于Kubernetes部署MySQL主从集群

基于Kubernetes部署MySQL主从集群

以下是一个基于Kubernetes部署MySQL主从集群的详细YAML示例,包含StatefulSet、Service、ConfigMap和Secret等关键配置。MySQL主从集群需要至少1个主节点和多个从节点,这里使用 StatefulSet + 初始化脚本 实现主从自动配置。


1. 创建 Namespace (可选)

apiVersion: v1
kind: Namespace
metadata:
  name: mysql-cluster

2. 创建 Secret (存储MySQL密码)

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secrets
  namespace: mysql-cluster
type: Opaque
data:
  root-password: eHg=  # echo -n "xx" | base64 (示例密码)
  replication-password: eHg=  # 主从同步专用密码

3. 创建 ConfigMap (主从配置文件)

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: mysql-cluster
data:
  master.cnf: |
    [mysqld]
    log-bin=mysql-bin
    server-id=1
  slave.cnf: |
    [mysqld]
    log-bin=mysql-bin
    server-id=2
  init.sql: |  # 初始化主从复制的SQL脚本
    CREATE USER 'repl'@'%' IDENTIFIED BY 'xx';  # 密码需与Secret中一致
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
    FLUSH PRIVILEGES;

4. 创建 Service (主从分离访问)

# 主节点服务
apiVersion: v1
kind: Service
metadata:
  name: mysql-master
  namespace: mysql-cluster
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql
    role: master
  clusterIP: None

# 从节点服务
apiVersion: v1
kind: Service
metadata:
  name: mysql-slave
  namespace: mysql-cluster
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql
    role: slave
  clusterIP: None

5. 创建 StatefulSet (1主2从)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: mysql-cluster
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
        role: slave  # 默认标记为slave,init容器中将修改第一个Pod为master
    spec:
      initContainers:
      - name: init-mysql
        image: mysql:8.0
        command:
        - bash
        - "-c"
        - |
          # 根据Pod序号分配server-id和角色
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          if [[ $ordinal -eq 0 ]]; then
            # 主节点配置
            cp /mnt/config/master.cnf /mnt/conf.d/
            echo "role=master" > /mnt/conf.d/role
          else
            # 从节点配置
            cp /mnt/config/slave.cnf /mnt/conf.d/
            echo "role=slave" > /mnt/conf.d/role
          fi
        volumeMounts:
        - name: conf
          mountPath: /mnt/conf.d
        - name: config-map
          mountPath: /mnt/config
      - name: clone-mysql
        image: alpine:3.18
        command:
        - bash
        - "-c"
        - |
          # 只有从节点需要等待主节点初始化完成
          if [ -f /mnt/conf.d/role ] && grep -q "slave" /mnt/conf.d/role; then
            until nslookup mysql-0.mysql; do
              sleep 2
            done
          fi
        volumeMounts:
        - name: conf
          mountPath: /mnt/conf.d
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: root-password
        - name: MYSQL_REPL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: replication-password
        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        - name: init-sql
          mountPath: /docker-entrypoint-initdb.d
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command: ["mysql", "-uroot", "-p${MYSQL_ROOT_PASSWORD}", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 5
      volumes:
      - name: conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: mysql-config
          items:
          - key: master.cnf
            path: master.cnf
          - key: slave.cnf
            path: slave.cnf
      - name: init-sql
        configMap:
          name: mysql-config
          items:
          - key: init.sql
            path: init.sql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "standard"  # 根据环境调整
      resources:
        requests:
          storage: 10Gi

6. 主从初始化自动化脚本 (StatefulSet启动后执行)

主节点启动后自动创建复制用户,从节点自动连接主节点:

# 在StatefulSet的Pod模板中添加以下生命周期钩子
lifecycle:
  postStart:
    exec:
      command:
      - "/bin/bash"
      - "-c"
      - |
        if [ -f /etc/mysql/conf.d/role ] && grep -q "master" /etc/mysql/conf.d/role; then
          # 主节点执行初始化SQL
          mysql -uroot -p${MYSQL_ROOT_PASSWORD} < /docker-entrypoint-initdb.d/init.sql
        else
          # 从节点配置主从复制
          until mysql -h mysql-0.mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "SELECT 1"; do
            sleep 1
          done
          mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "
            CHANGE MASTER TO
            MASTER_HOST='mysql-0.mysql',
            MASTER_USER='repl',
            MASTER_PASSWORD='${MYSQL_REPL_PASSWORD}',
            MASTER_AUTO_POSITION=1;
            START SLAVE;
          "
        fi

验证主从同步

# 检查主节点状态
kubectl exec -it mysql-0 -n mysql-cluster -- mysql -uroot -p -e "SHOW MASTER STATUS\G"

# 检查从节点同步状态
kubectl exec -it mysql-1 -n mysql-cluster -- mysql -uroot -p -e "SHOW SLAVE STATUS\G"

关键注意事项:

  1. 主节点高可用 :此方案主节点单点,若需高可用,需结合 OrchestratorProxySQL 实现故障转移。
  2. 数据持久化 :确保 storageClassName 与实际存储系统匹配(如 rook-cephfsnfs )。
  3. 密码安全 :通过Secret管理敏感信息,禁止明文存储。
  4. 网络通信 :确保StatefulSet的Pod之间可通过DNS名称互相访问(如 mysql-0.mysql.mysql-cluster.svc.cluster.local )。
  5. 扩展性 :通过增加 replicas 数量扩展从节点。

完整架构示意图:

Client -> Service(mysql-master) -> Pod(mysql-0) [Master]
Client -> Service(mysql-slave)  -> Pod(mysql-1, mysql-2) [Slave]

可根据需求调整副本数量或增加读写分离中间件(如ProxySQL)。