再谈有状态应用部署statefulset
1106字约4分钟
2024-09-29
无状态与有状态
Deployment控制器设计原则:管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node 运行,可随意扩容和缩容。这种应用称为“无状态”,例如Web服务
在实际的场景中,并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有 依赖关系,例如主从关系、主备关系,这种应用称为“有状态”,例如MySQL主从、Etcd集群
StatefulSet 控制器概述
StatefulSet控制器用于部署有状态应用,满足一些有状态应 用的需求:
- Pod有序的部署、扩容、删除和停止 
- Pod分配一个稳定的且唯一的网络标识 
- Pod分配一个独享的存储 
StatefulSet 控制器:网络标识
稳定的网络标识:使用Headless Service(相比普通Service只是将spec.clusterIP定义为None)来维 护Pod网络身份,会为每个Pod分配一个数字编号并且按照编号顺序部署。还需要在StatefulSet添加 serviceName: “nginx”字段指定StatefulSet控制器要使用这个Headless Service。
稳定主要体现在主机名和Pod A记录:
主机名:<statefulset名称>-<编号>
Pod DNS A记录:<statefulset名称-编号>.<service-name>.<namespace>.svc.cluster.local部署statefulset控制器
vim statefulset-web.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-web
spec:
  serviceName: "handless-service"
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web部署handless-service
vim handless-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: handless-service
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376验证查看
kubectl apply -f statefulset-web.yaml
kubectl apply -f handless-service.yaml 
kubectl get pod,svc
kubectl get statefulsets.apps查看Pod创建顺序:

查看主机名:
kubectl exec statefulset-web-0 -- hostname
kubectl exec statefulset-web-1 -- hostname
kubectl exec statefulset-web-2 -- hostname
测试A记录解析:
kubectl run -it dns-test --rm --image=busybox:1.28.4 -- sh
nslookup handless-service解析出对应的三个Pod IP记录,其他Pod可使用这个名称访问:

StatefulSet 控制器:独享存储
独享存储:StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用 VolumeClaimTemplate创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC, 每个PVC绑定对应的PV,从而保证每个Pod都拥有独立的存储。
部署nfs
#安装nfs安装包(每个k8s节点都要安装)
yum install nfs-utils
#创建nfs共享目录
mkdir -p /nfs/kubernetes
#修改nfs配置文件
vim /etc/exports
/nfs/kubernetes *(rw,no_root_squash)
#启动nfs并加入开机自启
systemctl start nfs
systemctl enable nfs
#尝试在别的K8s节点挂载nfs共享目录
mount -t nfs 192.168.0.13:/nfs/kubernetes /mnt/部署nfs-storage
git clone https://github.com/kubernetes-incubator/external-storage 
cd nfs-client/deploy 
kubectl apply -f rbac.yaml # 授权访问apiserver 
kubectl apply -f deployment.yaml # 部署插件,需修改里面NFS服务器地址与共享目录 
kubectl apply -f class.yaml # 创建存储类
kubectl get sc  # 查看存储类部署statefulset控制器
vim statefulset-web.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-web
spec:
  serviceName: "handless-service"
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      storageClassName: "managed-nfs-storage"
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gkubectl delete -f statefulset-web.yaml 
kubectl apply -f statefulset-web.yaml
nfs服务器共享目录

测试在这三个pv目录下创建三个不同内容的index.html页面,然后访问对应不同的Pod的IP

验证访问

从上面图中,我们可以看到每个pod的数据都是独立存储的。
测试删除statefulset控制器

从上图可以看出,当我们删除pod的时候,并没有删除对应pvc和pv,而是做了数据的持久化。
再次重建测试能否访问之前的数据


从上图可以看出,重建之后,数据还是之前的数据,每个pvc对应绑定每个pv,pod的IP发生了变化。
kubernetes根据pod的编号找同样编号的pvc去挂载,从而实现了数据持久化。
通过编号保证每个pod的启动顺序
通过编号为每个pod创建不同的主机名以及dns A记录
通过编号为每个pod创建独立的pvc
StatefulSet 控制器:小结
StatefulSet与Deployment区别:有身份的!
身份三要素:
- 域名 
- 主机名 
- 存储(PVC) 
