什么是StatefulSet
RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。
StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:
$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
例如访问mysql集群Master库:jdbc:mysql://mysql-0.mysql.mysql.svc.cluster.local:3306/test
创建 StatefulSet
K8s 1.23版本,创建 StatefulSet,以 mysql集群 为例,演示怎么通过外部端口访问k8s mysql集群内的数据库:
apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: mysql spec: replicas: 2 selector: matchLabels: app: mysql serviceName: mysql template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: 10.100.57.178:5000/mysql:8.0.19 imagePullPolicy: IfNotPresent command: - bash - "-c" - | set -ex [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 myindex=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf echo server-id=$((100 + ${myindex})) >> /mnt/conf.d/server-id.cnf if [[ ${myindex} -eq 0 ]]; then cp /mnt/config-map/master.cnf /mnt/conf.d/ else cp /mnt/config-map/slave.cnf /mnt/conf.d/ fi volumeMounts: - name: conf mountPath: /mnt/conf.d - name: config-map mountPath: /mnt/config-map - name: clone-mysql image: 10.100.57.178:5000/mzmuer/xtrabackup:1.0 imagePullPolicy: IfNotPresent command: - bash - "-c" - | set -ex [[ -d /var/lib/mysql/mysql ]] && exit 0 [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 myindex=${BASH_REMATCH[1]} [[ ${myindex} -eq 0 ]] && exit 0 ncat --recv-only mysql-$((${myindex}-1)).mysql 3307 | xbstream -x -C /var/lib/mysql xtrabackup --prepare --target-dir=/var/lib/mysql # --redo-only 加了会导致为提交的事务不回滚 volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d containers: - name: mysql image: 10.100.57.178:5000/mysql:8.0.19 imagePullPolicy: IfNotPresent args: ["--default-authentication-plugin=mysql_native_password"] 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: 250m memory: 256Mi limits: cpu: 500m memory: 512Mi livenessProbe: exec: command: ["mysqladmin", "ping"] initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 readinessProbe: exec: command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"] initialDelaySeconds: 5 periodSeconds: 2 timeoutSeconds: 1 - name: xtrabackup image: 10.100.57.178:5000/mzmuer/xtrabackup:1.0 imagePullPolicy: IfNotPresent ports: - name: xtrabackup containerPort: 3307 command: - bash - "-c" - | set -ex mkdir /test cd /var/lib/mysql if [[ -s xtrabackup_slave_info ]]; then mv xtrabackup_slave_info change_master_to.sql.in rm -f xtrabackup_binlog_info elif [[ -f xtrabackup_binlog_info ]]; then [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1 echo -e "CHANGE MASTER TO\nMASTER_LOG_FILE='${BASH_REMATCH[1]}',\nMASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in rm -f xtrabackup_binlog_info fi if [[ -f change_master_to.sql.in ]]; then echo "Waiting for mysqld to be ready (accepting connections)" until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done echo "Initializing replication from clone position" mv change_master_to.sql.in change_master_to.sql.orig mysql -h 127.0.0.1 <<EOF $(<change_master_to.sql.orig), MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='repl123.', MASTER_CONNECT_RETRY=10; START SLAVE; EOF echo "master slave config ok" fi [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 myindex=${BASH_REMATCH[1]} if [[ ${myindex} -eq 0 ]]; then mysql -h 127.0.0.1 <<EOF use mysql; delete from user where user='repl' and host='%';flush privileges; CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'repl123.'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';flush privileges; SELECT Host, User, plugin from mysql.user; EOF else Slave_healthy=`mysql -h 127.0.0.1 -e 'show slave status\G' 2> /dev/null |grep -E "Slave_IO_Running|Slave_SQL_Running"|awk '{print $2}'|grep -c Yes` if [[ ${Slave_healthy} -eq 2 ]]; then echo "master slave healthy ok" elif [[ ${Slave_healthy} -eq 1 ]]; then echo "master slave healthy no" mysql -h 127.0.0.1 <<EOF stop slave; reset slave; start slave; EOF echo "master slave healthy revert" elif [[ ${Slave_healthy} -eq 0 ]]; then echo "master slave healthy no" mysql -h 127.0.0.1 <<EOF reset slave; start slave; EOF echo "master slave healthy revert" fi fi exec ncat --listen --keep-open --send-only --max-conns=1 3307 -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 limits: cpu: 200m memory: 200Mi volumes: - name: conf emptyDir: {} - name: config-map configMap: name: mysql volumeClaimTemplates: - metadata: name: data spec: storageClassName: "managed-nfs-storage" accessModes: ["ReadWriteMany"] resources: requests: storage: 10Gi
|
创建第一个外部端口,以访问Master库
apiVersion: v1 kind: Service metadata: name: mysql-0-external namespace: mysql spec: type: NodePort ports: - port: 3306 protocol: TCP targetPort: 3306 nodePort: 31306 --- apiVersion: v1 kind: Endpoints metadata: name: mysql-0-external namespace: mysql subsets: - addresses: - ip: "10.244.2.239" # 根据 pod mysql-0 的 ip 填写 ports: - port: 3306
|
创建完成后,用户可以通过 jdbc:mysql://宿主机IP:31306
访问Master库
创建第2个外部端口,以访问Slave库
apiVersion: v1 kind: Service metadata: name: mysql-1-external namespace: mysql spec: type: NodePort ports: - port: 3306 protocol: TCP targetPort: 3306 nodePort: 31307 --- apiVersion: v1 kind: Endpoints metadata: name: mysql-1-external namespace: mysql subsets: - addresses: - ip: "10.244.2.240" # 根据 pod mysql-1 的 ip 填写 ports: - port: 3306
|
创建完成后,用户可以通过 jdbc:mysql://宿主机IP:31307
访问Slave库