apiVersion:v1 kind:ConfigMap metadata: name:mysql labels: app:mysql app.kubernetes.io/name:mysql data: primary.cnf:| # Apply this config only on the primary. [mysqld] log-bin replica.cnf:| # Apply this config only on replicas. [mysqld] super-read-only
# Headless service for stable DNS entries of StatefulSet members. apiVersion:v1 kind:Service metadata: name:mysql labels: app:mysql app.kubernetes.io/name:mysql spec: ports: -name:mysql port:3306 clusterIP:None selector: app:mysql --- # Client service for connecting to any MySQL instance for reads. # For writes, you must instead connect to the primary: mysql-0.mysql. apiVersion:v1 kind:Service metadata: name:mysql-read labels: app:mysql app.kubernetes.io/name:mysql readonly:"true" spec: ports: -name:mysql port:3306 selector: app:mysql
由于第一个 Service 配置了 clusterIP: None,所以它是一个 Headless Service,也就是它会代理编号为 0 的节点,也就是主节点
而第二个 Service,由于在 selector 中指定了 app: mysql,所以它会代理所有具有这个 label 的节点,也就是集群中的所有节点。readonly: "true"标签标识从节点只读。请注意,只有读查询才能使用负载均衡的客户端 Service
在同一 Kubernetes 集群和命名空间中的任何其他 Pod 内解析 <Pod 名称>.mysql 来访问 Pod (等部署完我们再测试下)
apiVersion:apps/v1 kind:StatefulSet metadata: name:mysql spec: selector: matchLabels: app:mysql app.kubernetes.io/name:mysql serviceName:mysql replicas:3 template: metadata: labels: app:mysql app.kubernetes.io/name:mysql spec: initContainers: -name:init-mysql image:mysql:5.7 command: -bash -"-c" -| set -ex # Generate mysql server-id from pod ordinal index. [[ $HOSTNAME =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf # Add an offset to avoid reserved server-id=0 value. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # Copy appropriate conf.d files from config-map to emptyDir. if [[ $ordinal -eq 0 ]]; then cp /mnt/config-map/primary.cnf /mnt/conf.d/ else cp /mnt/config-map/replica.cnf /mnt/conf.d/ fi volumeMounts: -name:conf mountPath:/mnt/conf.d -name:config-map mountPath:/mnt/config-map -name:clone-mysql image:gcr.io/google-samples/xtrabackup:1.0 command: -bash -"-c" -| set -ex # Skip the clone if data already exists. [[ -d /var/lib/mysql/mysql ]] && exit 0 # Skip the clone on primary (ordinal index 0). [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal -eq 0 ]] && exit 0 # Clone data from previous peer. ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql # Prepare the backup. xtrabackup --prepare --target-dir=/var/lib/mysql volumeMounts: -name:data mountPath:/var/lib/mysql subPath:mysql -name:conf mountPath:/etc/mysql/conf.d containers: -name:mysql image:mysql:5.7 env: -name:MYSQL_ALLOW_EMPTY_PASSWORD value:"1" ports: -name:mysql containerPort:3306 volumeMounts: -name:data mountPath:/var/lib/mysql subPath:mysql -name:conf mountPath:/etc/mysql/conf.d resources: requests: cpu:500m memory:1Gi livenessProbe: exec: command: ["mysqladmin", "ping"] initialDelaySeconds:30 periodSeconds:10 timeoutSeconds:5 readinessProbe: exec: # Check we can execute queries over TCP (skip-networking is off). command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"] initialDelaySeconds:5 periodSeconds:2 timeoutSeconds:1 -name:xtrabackup image:gcr.io/google-samples/xtrabackup:1.0 ports: -name:xtrabackup containerPort:3307 command: -bash -"-c" -| set -ex cd /var/lib/mysql # Determine binlog position of cloned data, if any. if [[ -fxtrabackup_slave_info&&"x$(<xtrabackup_slave_info)"!="x" ]];then # XtraBackup already generated a partial "CHANGE MASTER TO" query # because we're cloning from an existing replica. (Need to remove the tailing semicolon!) catxtrabackup_slave_info|sed-E's/;$//g'>change_master_to.sql.in # Ignore xtrabackup_binlog_info in this case (it's useless). rm-fxtrabackup_slave_infoxtrabackup_binlog_info elif [[ -fxtrabackup_binlog_info ]];then # We're cloning directly from primary. Parse binlog position. [[ `catxtrabackup_binlog_info`=~^(.*?)[[:space:]]+(.*?)$ ]] ||exit1 rm-fxtrabackup_binlog_infoxtrabackup_slave_info echo"CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\ MASTER_LOG_POS=${BASH_REMATCH[2]}">change_master_to.sql.in fi
# Check if we need to complete a clone by starting replication. if [[ -fchange_master_to.sql.in ]];then echo"Waiting for mysqld to be ready (accepting connections)" untilmysql-h127.0.0.1-e"SELECT 1";dosleep1;done
echo"Initializing replication from clone position" mysql-h127.0.0.1\ -e"$(<change_master_to.sql.in), \ MASTER_HOST='mysql-0.mysql', \ MASTER_USER='root', \ MASTER_PASSWORD='', \ MASTER_CONNECT_RETRY=10; \ START SLAVE;"||exit1 # In case of container restart, attempt this at-most-once. mvchange_master_to.sql.inchange_master_to.sql.orig fi
# Start a server to send backups when requested by peers. execncat--listen--keep-open--send-only--max-conns=13307-c\ "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root" volumeMounts: -name:data mountPath:/var/lib/mysql subPath:mysql -name:conf mountPath:/etc/mysql/conf.d resources: requests: cpu:100m memory:100Mi volumes: -name:conf emptyDir: {} -name:config-map configMap: name:mysql volumeClaimTemplates: -metadata: name:data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage:10Gi
apiVersion:apps/v1 kind:StatefulSet metadata: name:mysql spec: selector: matchLabels: app:mysql app.kubernetes.io/name:mysql serviceName:mysql replicas:3 template: metadata: labels: app:mysql app.kubernetes.io/name:mysql spec: initContainers: -name:init-mysql image:mysql:5.7 command: -bash -"-c" -| set -ex # Generate mysql server-id from pod ordinal index. [[ $HOSTNAME =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf # Add an offset to avoid reserved server-id=0 value. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # Copy appropriate conf.d files from config-map to emptyDir. if [[ $ordinal -eq 0 ]]; then cp /mnt/config-map/primary.cnf /mnt/conf.d/ else cp /mnt/config-map/replica.cnf /mnt/conf.d/ fi volumeMounts: -name:conf mountPath:/mnt/conf.d -name:config-map mountPath:/mnt/config-map -name:clone-mysql image:registry.cn-hangzhou.aliyuncs.com/hxpdocker/xtrabackup:1.0 command: -bash -"-c" -| set -ex # Skip the clone if data already exists. [[ -d /var/lib/mysql/mysql ]] && exit 0 # Skip the clone on primary (ordinal index 0). [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal -eq 0 ]] && exit 0 # Clone data from previous peer. ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql # Prepare the backup. xtrabackup --prepare --target-dir=/var/lib/mysql volumeMounts: -name:data mountPath:/var/lib/mysql subPath:mysql -name:conf mountPath:/etc/mysql/conf.d containers: -name:mysql image:mysql:5.7 env: -name:MYSQL_ALLOW_EMPTY_PASSWORD value:"1" ports: -name:mysql containerPort:3306 volumeMounts: -name:data mountPath:/var/lib/mysql subPath:mysql -name:conf mountPath:/etc/mysql/conf.d resources: requests: cpu:500m memory:1Gi livenessProbe: exec: command: ["mysqladmin", "ping"] initialDelaySeconds:30 periodSeconds:10 timeoutSeconds:5 readinessProbe: exec: # Check we can execute queries over TCP (skip-networking is off). command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"] initialDelaySeconds:5 periodSeconds:2 timeoutSeconds:1 -name:xtrabackup image:registry.cn-hangzhou.aliyuncs.com/hxpdocker/xtrabackup:1.0 ports: -name:xtrabackup containerPort:3307 command: -bash -"-c" -| set -ex cd /var/lib/mysql # Determine binlog position of cloned data, if any. if [[ -fxtrabackup_slave_info&&"x$(<xtrabackup_slave_info)"!="x" ]];then # XtraBackup already generated a partial "CHANGE MASTER TO" query # because we're cloning from an existing replica. (Need to remove the tailing semicolon!) catxtrabackup_slave_info|sed-E's/;$//g'>change_master_to.sql.in # Ignore xtrabackup_binlog_info in this case (it's useless). rm-fxtrabackup_slave_infoxtrabackup_binlog_info elif [[ -fxtrabackup_binlog_info ]];then # We're cloning directly from primary. Parse binlog position. [[ `catxtrabackup_binlog_info`=~^(.*?)[[:space:]]+(.*?)$ ]] ||exit1 rm-fxtrabackup_binlog_infoxtrabackup_slave_info echo"CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\ MASTER_LOG_POS=${BASH_REMATCH[2]}">change_master_to.sql.in fi
# Check if we need to complete a clone by starting replication. if [[ -fchange_master_to.sql.in ]];then echo"Waiting for mysqld to be ready (accepting connections)" untilmysql-h127.0.0.1-e"SELECT 1";dosleep1;done
echo"Initializing replication from clone position" mysql-h127.0.0.1\ -e"$(<change_master_to.sql.in), \ MASTER_HOST='mysql-0.mysql', \ MASTER_USER='root', \ MASTER_PASSWORD='', \ MASTER_CONNECT_RETRY=10; \ START SLAVE;"||exit1 # In case of container restart, attempt this at-most-once. mvchange_master_to.sql.inchange_master_to.sql.orig fi
# Start a server to send backups when requested by peers. execncat--listen--keep-open--send-only--max-conns=13307-c\ "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root" volumeMounts: -name:data mountPath:/var/lib/mysql subPath:mysql -name:conf mountPath:/etc/mysql/conf.d resources: requests: cpu:100m memory:100Mi volumes: -name:conf emptyDir: {} -name:config-map configMap: name:mysql volumeClaimTemplates: -metadata: name:data annotations: volume.beta.kubernetes.io/storage-class:nfs-client spec: accessModes: ["ReadWriteOnce"] resources: requests: storage:5Gi