k8s series 8: StatefulSet部署数据库

1,948 阅读4分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

像关系型数据库mysql,非关系型数据库mongodb,消息队列kafka,分布式协调工具zookeeper等都属于有状态服务,这类有状态有存储的pod在k8s中有专门的控制器来管理部署和扩缩,那就是statefulset。

StatefulSet 介绍

 StatefulSet是k8s中专门来用 管理有状态Pod的控制器,有哪些功能了

特点

  • 稳定的唯一网络标识符(为每一个pod提供一个永不变的唯一ID)
  • 稳定的持久存储(借助pv,pvc功能提供,pod重启或销毁 数据依旧存在)
  • 有序的,优雅的部署和扩缩(按照id顺序部署和 扩缩容)
  • 有序的,自动的滚动更新(按照id顺序滚动启动和停止,期间不影响服务使用)
  • 客户端可以通过服务的域名连接到任意Pod

稳定  意味着 Pod 调度或重调度的整个过程是有持久性的。 如果应用不需要任何稳定的标识符或有序的部署、删除或伸缩,那么使用 由一组无状态的副本控制器提供的pod来部署应用,比如 Deployment 或者 ReplicaSet 来部署无状态应用

使用的时候有哪些注意事项了

限制

  • pod的存储必须预先提供(pv,pvc),或使用storage class定义
  • 删除或扩缩容不会删除相关的pvc或sc
  • 集群式有状态服务,需要提前定义网络标示,并且不可重复
  • 优雅缩停止StatefulSet 控制器,最好的方式将缩放降低为0

生产使用注意事项

因为kubernetes核心是为无状态应用部署设计的,对于有状态应用需要运维多出时间来维护

  • 数据库应用有可能程度重启和故障转移,这是因为pod暂时的,出现问题会停止和重新启
  • 升级kubernetes时,需要额外的备份持久卷,并且需要隔段时间做恢复演练,这是因为和无状态不同,你不能仅仅启动一个干净的pod就能升级完成

StatefulSet架构图

StatefulSet 部署Mysql

yaml文件来源:  github.com/Yolean/kube…

切换到statefulset 分支,使用具有故障转移功能的配置

创建namespace

apiVersion: v1
kind: Namespace
metadata:
  name: mysql

创建pv

pv这边简单搭建个nfs网络文件共享服务器,方便使用pvc

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
  labels:
    app: mariadb
    podindex: "0"
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /data/nfs/pv1
    server: ip
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv2
  labels:
    app: mariadb
    podindex: "1"
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /data/nfs/pv2
    server: ip
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv3
  labels:
    app: mariadb
    podindex: "2"
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /data/nfs/pv3
    server: ip

创建pvc

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-mariadb-0
  namespace: mysql
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  selector:
    matchLabels:
      app: mariadb
      podindex: "0"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-mariadb-1
  namespace: mysql
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  selector:
    matchLabels:
      app: mariadb
      podindex: "1"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-mariadb-2
  namespace: mysql
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  selector:
    matchLabels:
      app: mariadb
      podindex: "2"

创建Service

  Headless Service 给StatefulSet 控制器每个pod创建了DNS记录条目,service metadate name 名称为mariadb,在同集群同namespace中可以使用pod-name.mariadb来访问该pod

mariadb service yaml

# the "Headless Service, used to control the network domain"
---
apiVersion: v1
kind: Service
metadata:
  name: mariadb
  namespace: mysql
spec:
  clusterIP: None
  selector:
    app: mariadb
  ports:
    - port: 3306
      name: mysql
    - port: 4444
      name: sst
    - port: 4567
      name: replication
    - protocol: UDP
      port: 4567
      name: replicationudp
    - port: 4568
      name: ist

mysql service yaml

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

创建ConfigMap

#!/bin/bash
DIR=`dirname "$BASH_SOURCE"`

kubectl create configmap "conf-d" --from-file="$DIR/conf-d/" --namespace=mysql

创建Secret

#!/bin/bash
echo -n Please enter mysql root password for upload to k8s secret:
read -s rootpw
echo
kubectl create secret generic mysql-secret --namespace=mysql --from-literal=rootpw=$rootpw

部署StatefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mariadb
  namespace: mysql
  labels:
    app: mariadb
spec:
  serviceName: "mariadb"
  selector:
    matchLabels:
      app: mariadb
  replicas: 1
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: mariadb
          image: mariadb:10.1.20@sha256:0ce9f13b5c5d235397252570acd0286a0a03472a22b7f0384fce09e65c680d13
          ports:
            - containerPort: 3306
              name: mysql
            - containerPort: 4444
              name: sst
            - containerPort: 4567
              name: replication
            - containerPort: 4567
              protocol: UDP
              name: replicationudp
            - containerPort: 4568
              name: ist
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: rootpw
            - name: MYSQL_INITDB_SKIP_TZINFO
              value: "yes"
          args:
            - --character-set-server=utf8mb4
            - --collation-server=utf8mb4_unicode_ci
            # Remove after first replicas=1 create
            - --wsrep-new-cluster
          volumeMounts:
            - name: mysql
              mountPath: /var/lib/mysql
            - name: conf
              mountPath: /etc/mysql/conf.d
            - name: initdb
              mountPath: /docker-entrypoint-initdb.d
      volumes:
        - name: conf
          configMap:
            name: conf-d
        - name: initdb
          emptyDir: {}
  volumeClaimTemplates:
  - metadata:
      name: mysql
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

部署完上述配置后,执行命令查看相应状态

状态检查

查看pv,pvc,service,statefulset,pod状态,为了方便,这里用对象的 缩写

kubectl get pv,pvc,sts,svc,pods -n mysql -o wide

此时看到只有一个mariadb启动,查看一下启动日志

kubectl logs -f mariadb-0 -n mysql

再加2个节点,组成3个节点的集群

bash -x 70unbootstrap.sh

#!/bin/bash
DIR=`dirname "$BASH_SOURCE"`
set -e
set -x

cp "$DIR/50mariadb.yml" "$DIR/50mariadb.yml.unbootstrap.yml"

sed -i '' 's/replicas: 1/replicas: 3/' "$DIR/50mariadb.yml.unbootstrap.yml"
sed -i '' 's/- --wsrep-new-cluster/#- --wsrep-new-cluster/' "$DIR/50mariadb.yml.unbootstrap.yml"

kubectl apply -f "$DIR/50mariadb.yml.unbootstrap.yml"
rm "$DIR/50mariadb.yml.unbootstrap.yml"

查看资源状态

kubectl get pv,pvc,sts,svc,pods -n mysql -o wide

集群特性说明

本例用的是3个节点,实现以下特性:

  • 1个甚至2个节点消失,读取一致
  • 2个节点消失,阻止写入
  • 1个节点消失,接受写入

查看数据

kubectl exec -it pod/mariadb-0 /bin/bash -n mysql
#查看user表
mysql
select * from mysql.user;
#更新密码
mysql --password=$MYSQL_ROOT_PASSWORD -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION;"

其他功能

像扩缩容,更新回滚,删除pod自动恢复等和deployment控制器是一样的,这里就不演示了

Rancher

集群管理依然使用rancher操作,界面友好,简单方便

参考

github.com/Yolean/kube…