这是我参与更文挑战的第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操作,界面友好,简单方便