k8s (十四) --- Kubernetes 存储 之 StatefulSet 控制器

这篇博客主要探讨StatefulSet如何通过Headless Service维持Pod的拓扑状态

一、StatefulSets

StatefulSet 是用来管理有状态应用的工作负载 API 对象。
StatefulSet 用来管理 Deployment 和扩展一组 Pod,并且能为这些 Pod 提供序号和唯一性保证

和 Deployment 相同的是,StatefulSet 管理了基于相同容器定义的一组 Pod。但和 Deployment 不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的 ID。这些 Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

StatefulSet 和其他控制器使用相同的工作模式。你在 StatefulSet 对象 中定义你期望的状态,然后 StatefulSet 的 控制器 就会通过各种更新来达到那种你想要的状态。

StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值:

  • 稳定的、唯一的网络标识符。
  • 稳定的、持久的存储。
  • 有序的、优雅的部署和缩放。
  • 有序的、自动的滚动更新。

在上面,稳定意味着 Pod 调度或重调度的整个过程是有持久性的。如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment 或者 ReplicaSet 可能更适用于您的无状态应用部署需要。

给定 Pod 的存储必须由 PersistentVolume 驱动 基于所请求的 storage class 来提供,或者由管理员预先提供。

删除或者收缩 StatefulSet 并不会删除它关联的存储卷。这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。

StatefulSet 当前需要 headless 服务 来负责 Pod 的网络标识。您需要负责创建此服务。

当删除 StatefulSets 时,StatefulSet 不提供任何终止 Pod 的保证。为了实现 StatefulSet 中的 Pod 可以有序和优雅的终止,可以在删除之前将 StatefulSet 缩放为 0。
在默认 Pod 管理策略(OrderedReady) 时使用 滚动更新,可能进入需要 人工干预 才能修复的损坏状态。

StatefulSet将应用状态抽象成了两种情况:

  • 拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样
  • 存储状态:应用的多个实例分别绑定了不同存储数据。

StatefulSet给所有的Pod进行了编号,编号规则是:$(statefulset名称)-$(序号),从0开始。

Pod被删除后重建,重建Pod的网络标识也不会改变,Pod的拓扑状态按照Pod的“名字+编号”的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,即Pod对应的DNS记录,同时重建时保证每个pod挂载到原来的卷上。

二、StatefulSet通过Headless Service维持Pod的拓扑状态

首先创建Headless service:

[root@server1 pv]# mkdir statefulset
[root@server1 pv]# cd statefulset/
[root@server1 statefulset]# vim service.yaml
[root@server1 statefulset]# cat service.yaml 
apiVersion: v1
kind: Service
metadata:
 name: nginx
 labels:
  app: nginx
spec:
 ports:
 - port: 80
   name: web
 clusterIP: None
 selector:
  app: nginx

创建服务:

[root@server1 statefulset]# kubectl apply -f service.yaml 
service/nginx created
[root@server1 statefulset]# kubectl get service
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   19d
myservice    ClusterIP   10.101.31.155   <none>        80/TCP    14d
nginx        ClusterIP   None            <none>        80/TCP    13s

可以看出创建了一个名为nginx的无头服务(Headless service)。

创建使用StatefulSet控制器的pod:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: web
spec:
 serviceName: "nginx"
 replicas: 2
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: nginx
     ports:
     - containerPort: 80
       name: web

[root@server1 statefulset]# 
[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web created
[root@server1 statefulset]# 
[root@server1 statefulset]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          31m
web-0                                     1/1     Running   0          29s
web-1                                     1/1     Running   0          26s

可以看出创建了两个名为web-0web-1的pod,service也会由两个endpoint:
在这里插入图片描述
其中pod名称中的0和1是pod的唯一标识。

当我们将replicas改为1时,web-1将会被回收:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
更改:
 replicas: 1

[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web configured
[root@server1 statefulset]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          33m
web-0                                     1/1     Running   0          2m12s

而当我们将replicas改为0时,所有pod将会被回收:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
更改:
 replicas: 0
[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web configured
[root@server1 statefulset]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          34m

之后再次重建pod:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
更改:
 replicas: 2
[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web configured
[root@server1 statefulset]# kubectl get pod
NAME                                      READY   STATUS              RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running             0          35m
web-0                                     0/1     ContainerCreating   0          2s
[root@server1 statefulset]# kubectl get pod
^[[3~NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          35m
web-0                                     1/1     Running   0          9s
web-1                                     1/1     Running   0          7s
[root@server1 statefulset]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          35m   10.244.1.81   server2   <none>           <none>
web-0                                     1/1     Running   0          28s   10.244.2.72   server3   <none>           <none>
web-1                                     1/1     Running   0          26s   10.244.1.83   server2   <none>           <none>

可以看出重新创建时是先创建web-0再创建web-1,而删除的时候是先删除web-1,再删除web-0.

但是需要注意的是虽然名称标识没有变,但是pod的ip发生了变化。

现在可以直接访问服务:

在这里插入图片描述

也可以解析地址:
在这里插入图片描述也可以使用nslookup web-1.nginx的方式解析和访问到:

在这里插入图片描述
PV和PVC的设计,使得StatefulSet对存储状态的管理成为了可能,现在为以上这些pod添加存储:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: web
spec:
 serviceName: "nginx"
 replicas: 2
 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: 100Mi

[root@server1 statefulset]# 
[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web created
[root@server1 statefulset]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          85m   10.244.1.81   server2   <none>           <none>
test                                      1/1     Running   2          48m   10.244.2.73   server3   <none>           <none>
web-0                                     1/1     Running   0          25s   10.244.1.84   server2   <none>           <none>
web-1                                     1/1     Running   0          20s   10.244.2.74   server3   <none>           <none>

StatefulSet还会为每一个Pod分配并创建一个同样编号的PVC。这样,kubernetes就可以通过Persistent Volume机制为这个PVC绑定对应的PV,从而保证每一个Pod都拥有一个独立的Volume:

[root@server1 statefulset]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-web-0   Bound    pvc-41713073-508d-4dcf-897e-dd0575a0945a   100Mi      RWO            managed-nfs-storage   2m30s
www-web-1   Bound    pvc-36ac2b3c-2f82-452e-ad39-bab2a51e67c6   100Mi      RWO            managed-nfs-storage   2m25s
[root@server1 statefulset]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
pvc-36ac2b3c-2f82-452e-ad39-bab2a51e67c6   100Mi      RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            2m28s
pvc-41713073-508d-4dcf-897e-dd0575a0945a   100Mi      RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            2m33s

可以往这些存储里写入测试页面:

[root@server1 statefulset]# ls /nfs/
default-www-web-0-pvc-41713073-508d-4dcf-897e-dd0575a0945a
default-www-web-1-pvc-36ac2b3c-2f82-452e-ad39-bab2a51e67c6
[root@server1 statefulset]# 
[root@server1 statefulset]# echo web-0 > /nfs/default-www-web-0-pvc-41713073-508d-4dcf-897e-dd0575a0945a/index.html
[root@server1 statefulset]# echo web-1 > /nfs/default-www-web-1-pvc-36ac2b3c-2f82-452e-ad39-bab2a51e67c6/index.html

测试解析和访问:

[root@server1 statefulset]# kubectl attach test -it

/ # nslookup nginx
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx
Address 1: 10.244.1.84 web-0.nginx.default.svc.cluster.local
Address 2: 10.244.2.74 10-244-2-74.myservice.default.svc.cluster.local

可以看出解析成功。

/ # curl nginx
web-1
/ # curl nginx
web-1
/ # curl nginx
web-0
/ # curl nginx
web-0
/ # curl nginx
web-1
/ # curl nginx
web-0
/ # curl web-1.nginx			#访问特定pod
web-1
/ # curl web-0.nginx
web-0

访问可以成功负载。

接下来我们将replicas设置为3,再次进行测试:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
修改:
 replicas: 3

[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web configured
[root@server1 statefulset]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          90m
test                                      1/1     Running   4          53m
web-0                                     1/1     Running   0          5m14s
web-1                                     1/1     Running   0          5m9s
web-2                                     1/1     Running   0          9s

service由三个endpoint:
在这里插入图片描述对应的pv当然也会创建:

[root@server1 statefulset]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
pvc-36ac2b3c-2f82-452e-ad39-bab2a51e67c6   100Mi      RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            5m35s
pvc-41713073-508d-4dcf-897e-dd0575a0945a   100Mi      RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            5m40s
pvc-c6e2ee56-02d8-4540-9dc7-b91926d34274   100Mi      RWO            Delete           Bound    default/www-web-2   managed-nfs-storage            35s

写入测试页面并访问:

[root@server1 statefulset]# ls /nfs/
default-www-web-0-pvc-41713073-508d-4dcf-897e-dd0575a0945a
default-www-web-1-pvc-36ac2b3c-2f82-452e-ad39-bab2a51e67c6
default-www-web-2-pvc-c6e2ee56-02d8-4540-9dc7-b91926d34274
[root@server1 statefulset]# echo web-2 > /nfs/default-www-web-2-pvc-c6e2ee56-02d8-4540-9dc7-b91926d34274/index.html
[root@server1 statefulset]# 
[root@server1 statefulset]# kubectl attach test -it
Defaulting container name to test.
Use 'kubectl describe pod/test -n default' to see all of the containers in this pod.
If you don't see a command prompt, try pressing enter.
/ # nslookup web-2.nginx
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-2.nginx
Address 1: 10.244.1.85 web-2.nginx.default.svc.cluster.local
/ # curl web-2.nginx
web-2
/ # curl web-1.nginx
web-1
/ # curl web-0.nginx
web-0

可以看出成功解析且访问。

而当我们将replicas改为0后,StatefulSet会将pod从2 ,1,0有序删除。

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
更改:
 replicas: 0
 
[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web configured
[root@server1 statefulset]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-6b66ddf664-zjvtv   1/1     Running   0          94m
test                                      1/1     Running   5          57m

删除后进行pod的重建:

[root@server1 statefulset]# vim deployment.yaml 
[root@server1 statefulset]# cat deployment.yaml 
更改:
 replicas: 3
 
[root@server1 statefulset]# kubectl apply -f deployment.yaml 
statefulset.apps/web configured

重键后测试访问:

[root@server1 statefulset]# kubectl attach test -it

/ # curl web-0.nginx
web-0
/ # curl web-1.nginx
web-1
/ # curl web-2.nginx
web-2

依然可以成功访问,这就验证了StatefulSet 控制器的特性。

最后将replicas改为0删除所有pod。

以上的一系列操作都是通过更改部署文件实现的,当然也可以使用命令的方式:

  • kubectl 弹缩

首先,想要弹缩的StatefulSet. 需先清楚是否能弹缩该应用.

$ kubectl get statefulsets <stateful-set-name>
  • 改变StatefulSet副本数量:
$ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
  • 如果StatefulSet开始由 kubectl apply 或 kubectl create --save-config
    创建,更新StatefulSet manifests中的 .spec.replicas, 然后执行命令 kubectl apply:
$ kubectl apply -f <stateful-set-file-updated>
  • 也可以通过命令 kubectl edit 编辑该字段:
$ kubectl edit statefulsets <stateful-set-name>
  • 使用 kubectl patch:
$ kubectl patch statefulsets <stateful-set-name> -p '{"spec":{"replicas":<new-replicas>}}'
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: k8sKubernetes)是一个开源的容器编排平台,用于自动化容器部署、扩展和管理。下面是一些与k8s相关的重要知识点运维笔记。 1. 容器化技术:k8s基于容器化技术,可以将应用程序及其依赖项封装到容器中,实现隔离和轻量级部署。熟悉Docker等容器化工具是使用k8s的先决条件。 2. 集群架构:k8s由Master和Worker节点组成,Master节点负责管理和控制集群,而Worker节点负责承载应用程序容器。了解集群架构和组件的功能是进行k8s运维的重要基础。 3. 资源管理:k8s通过Pod、Deployment、ReplicaSet等资源对象实现应用程序的管理。Pod是最小的可部署单元,可以包含一个或多个容器。Deployment用于定义和控制Pod的副本数和版本更新等。 4. 服务发现和负载均衡:k8s提供了Service对象用于服务发现和负载均衡。Service定义了一组Pod的访问入口,并通过ClusterIP、NodePort或LoadBalancer等方式实现内部和外部的访问。 5. 存储管理:k8s支持各种存储卷插件,包括本地存储、NFS、AWS EBS等。使用存储卷可以将应用程序中的数据持久化,并实现数据的共享和迁移。 6. 配置管理:k8s提供了ConfigMap和Secret等对象用于管理应用程序的配置和敏感信息。ConfigMap用于存储配置数据,而Secret用于存储敏感信息如密码和API密钥。 7. 监控和日志:k8s集成了多种监控和日志工具,如Prometheus、Grafana和EFK(Elasticsearch、Fluentd、Kibana)等。通过这些工具可以实时监控和分析应用程序的性能和日志信息。 8. 自动扩展:k8s可以根据应用程序的负载情况自动进行扩展。通过Horizontal Pod Autoscaler(HPA)等机制,可以根据CPU利用率或其他指标自动调整Pod的副本数。 9. 更新和回滚:k8s支持应用程序的版本更新和回滚。通过Deployment的滚动升级策略,可以实现应用程序的无缝更新,并在出现问题时快速回滚到之前的版本。 10. 故障排除和调试:k8s提供了一些工具和命令行工具,如kubectl、kubectl logs等,用于进行故障排查和调试。掌握这些工具的使用方法对于运维k8s集群是必要的。 以上是一些与k8s相关的重要知识点和运维笔记,对于熟练掌握k8s运维人员来说,这些知识点是必备的。当然,k8s是一个非常广泛且庞大的平台,还有很多其他方面的知识和技能需要进一步学习和掌握。 ### 回答2: Kubernetes(简称K8s)是一种用于自动化容器化应用程序部署、扩展和管理的开源容器编排工具。以下是关于Kubernetes相关重要知识点的运维笔记: 1. 集群架构:Kubernetes由Master和Node组成。Master负责集群管理,包括调度、监控、管理配置等,而Node是运行容器的主机。 2. Pod:Pod是Kubernetes最小的可调度和管理的单元,它可以包含一个或多个容器。Pod共享网络和存储资源,可以通过共享文件和通信进行协作。 3. 命名空间(Namespace):命名空间用于将集群内的资源进行隔离,可以避免不同应用程序之间的冲突。 4. 控制器(Controller):控制器用于实现自动化操作和管理,如应用部署、副本数监控、故障恢复等。常见的控制器包括ReplicaSet、Deployment、StatefulSet等。 5. 服务(Service):Service是一种抽象,用于定义一组Pod的访问方式。它为一组Pod分配固定的虚拟IP,并提供负载均衡和服务发现功能。 6. 存储卷(Volume):存储卷用于持久化数据,确保数据在容器重启或迁移时不丢失。Kubernetes支持多种存储类型,如本地存储、网络存储、云存储等。 7. 扩展机制:Kubernetes提供了多种扩展机制,如水平Pod自动伸缩(HPA)、自定义资源定义(CRD)、自定义控制器等,可以根据需求灵活扩展和定制。 8. 监控和日志:Kubernetes提供了丰富的监控和日志功能,可以通过Prometheus、Elasticsearch等工具对集群中的资源和应用进行监视和记录。 9. 网络和服务发现:Kubernetes为容器提供了多种网络模型,并集成了服务发现机制。可以通过Ingress、LoadBalancer等方式将容器暴露到集群外部。 10. 安全和认证授权:Kubernetes提供了多种安全机制,如RBAC、TLS等,用于认证和授权用户的访问权限,确保集群的安全性。 这些是Kubernetes运维中的重要知识点,掌握了这些知识对于有效管理和运维Kubernetes集群至关重要。 ### 回答3: 1. k8s是一种开源的容器编排和管理平台,用于自动化应用程序的部署、扩展和管理。 2. k8s中的基本组件包括Master节点和Worker节点。Master节点负责管理整个集群的状态和配置信息,Worker节点负责运行容器。 3. k8s中的最小调度单位为Pod,一个Pod是一个或多个相关容器的组合,它们共享存储、网络和名称空间。 4. Replication Controller是k8s中用于复制和扩展Pod的机制,它可以确保指定数量的Pod在任何时间都运行在集群中。 5. Service是k8s中用于将Pod组织成服务的机制,提供一个稳定的IP地址和DNS名称,使得其他Pod或外部用户可以访问服务。 6. Volume是k8s中用于持久化数据的机制,允许容器访问与它们的生命周期无关的存储。 7. k8s支持多种网络插件,如Flannel、Calico和Weave等,用于在集群中实现容器之间的网络通信。 8. k8s可以通过Horizontal Pod Autoscaler实现根据负载自动进行Pod的扩缩容。它根据定义的指标监控集群的负载,并在负载过高或过低时自动调整Pod数量。 9. k8s支持滚动更新,可以在不中断服务的情况下逐步更新应用程序的版本。 10. k8s提供了丰富的监控和日志收集机制,如Heapster和ELK Stack等,帮助用户监控和分析集群的状态和性能。 11. k8s还支持命名空间的概念,可以将集群划分为多个逻辑上独立的区域,以实现更好的资源隔离和管理。 12. k8s支持灵活的部署方式,可以在公有云、私有云或裸机上部署,同时支持自建集群和托管集群。 13. k8s有丰富的命令行工具和API,方便用户进行集群的管理和操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值