深入理解 StatefulSet 之拓扑状态

文章目录

  • Deployment 的限制
  • StatefulSet
    • Headless Service

Deployment 的限制

Deploymen 在生产环境中并不足以覆盖所有的应用编排问题。造成这个问题的原因是 Deployment 对所有的 Pod 都做了一个假设,那就是一个应用的所有 Pod 完全是一样的;它们之间没有顺序,也无所谓运行在哪台宿主机上。
但是,在实际的场景中,应用之间往往有依赖关系,比如:主从关系、主备关系等。
这种应用之间的不对等或者依赖关系,就被称为“有状态”(Stateful)。

StatefulSet

Kubernetes 社区在 Deployment 的基础上,扩展出了 StatefulSet 来支持“有状态应用”。
StatefulSet 把真实世界里的应用状态,抽象为了两种情况:

  1. 拓扑状态。这种情况意味着,应用的多个实例之间不是完全对等的关系。这些应用实例,必须按照某些顺序启动。而对于重建的 Pod 不仅要按照它们之前的顺序,并且这些 Pod 还要和原来的 Pod 的网络标识一样。
  2. 存储状态。这种情况意味着,应用的多个实例分别绑定了不同的存储数据。比如,Pod A 第一次读取到的数据,和隔了十分钟之后再次读取到的数据,应该是同一份,哪怕在此期间 Pod A 被重新创建过。

所以,StatefulSet 的核心功能,就是通过某种方式记录这些状态,然后在 Pod 被重新创建时,能够为 Pod 恢复这些状态。
在讲述 StatefulSet 之前,有必要先学习 Kubernetes 中的 Headless Service

Headless Service

Service 是 Kubernetes 项目中用来将一组 Pod 暴露给外界访问的一种机制。比如,一个 Deployment 有 3 个 Pod,那么我就可以定义一个 Service。然后,用户只要能访问到这个 Service,它就能访问到具体的 Pod。
访问 Service 的两种方式:

  1. 以 Service 的 VIP (Virtual IP,即虚拟 IP)方式。最终将发送给 Service 的请求转发到该 Service 所管理的某一个 Pod 上。
  2. 以 Service 的 DNS 方式。在这种方式下,又分两种处理方法:
    (1) Normal Service。这种情况下,访问 DNS 解析到的就是 Service 的 VIP。
    (2) Headless Service。这种情况下,访问 DNS 解析到的就是 Service 所管理的某一个 Pod 的 IP 地址。此方法,不需要分配 VIP。

如下所示为一个标准的 Headless Service 对应的 yaml 文件:

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx 

可以看到,所谓的 Headless Service 任然是一个标准 Service 的 yaml 文件。但是,它的 clusterIP 字段的值是:None。而这个 Headless Service 所代理的 Pod 依然使用 Label Selector 机制筛选出来,即:所有携带了 app=nginx 标签的 Pod,都会被这个 Service 代理起来。
当按照上述方式创建一个 Headless Service 之后,它所代理的 Pod 的 IP 地址,都会被绑定一个如下所示的 DNS 记录:

...svc.cluster.local

而这个 DNS 记录,正是 Kubernetes 项目为 Pod 分配的唯一的“可解析身份”。
如下所示为 StatefulSet 的 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:1.9.1
        ports:
        - containerPort: 80
          name: web

你可能感兴趣的:(Kubernetes)