有状态的节点控制器 -- StatefulSet 及其网络状态

2022-04-24 21:21:07   最后更新: 2022-04-24 21:21:07   访问数量:67




 

上一篇文章中,我们详细介绍了 Kubernetes 中的作业副本控制器 Deployment:

 

详解作业副本控制器 Deployment

 

对于 Deployment 来说,每一种 Pod 都是完全一样的,因此,Deployment 可以按照配置任意增删任何一个 Pod,但在我们的实际场景中,情况并非总是如此,多个实例之间往往会有着复杂的依赖关系,比如主从、主备关系等等。这些情况下,实例之间的地位是不对等的,这样的应用就被称为“有状态应用”。

 

容器的解决方案是针对无状态应用场景的最佳实践,但对于有状态应用来说,就并非如此了。Kubernetes 用 StatefulSet 解决了有状态应用编排的问题,本文我们就来初步认识一下 StatefulSet。

 

 

StatefulSet 将应用设计抽象为了两种状态:

 

2.1 拓扑状态

 

应用存在多个实例,但多个实例地位并不完全对等。

 

应用的多个实例必须按照某种顺序启动,并且必须成组存在,例如一个应用中必须存在一个 A Pod 和两个 B Pod,且 A Pod 必须先于 B Pod 启动的场景。

 

2.2 存储状态

 

应用存在多个实例,但每个实例绑定的存储数据不同,那么对于一个 Pod 来说,无论它是否被重新创建,它读到的数据状态应该是一致的。

 

 

一个最简单的场景,我们用一个 nginx Headless Service 反向代理 Kubernetes 中的两个 Pod,并且这两个 Pod 具有不完全对等的网络身份,这个情况下,就是典型的拓扑状态下的 StatefulSet 的使用场景。

 

3.1 初识 Kubernetes Service

 

1. 两种访问方式

 

Kubernetes 的 Service 就是对外提供的可访问服务,它有两种访问方式:

 

  1. VIP 方式:它是 Virtual IP 的缩写,通过将服务绑定到 Kubernetes 虚拟的 IP 地址,提供给外部调用,通过虚拟 IP 地址隐藏了服务的具体实现与地址。
  2. DNS 方式:与虚拟 IP 地址类似,外部通过访问 DNS 记录的方式实现对具体 Service 的转发。

 

2. DNS 的两种处理方式

 

  1. Normal Service:将 DNS 地址绑定到虚拟 IP 地址,从而复用虚拟 IP 地址的设计和逻辑;
  2. Headless Service:将 DNS 地址直接代理到 Pod。

 

3.2 配置一个 Headless nginx Service

 

下面的配置文件配置了一个 Headless 方式启动的 nginx Service:

 

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

 

 

这个配置中,clusterIP 设置为了 None,表示不为这个 Service 分配 VIP,而是通过 Headless DNS 的方式来处理该 Service 的调用。

 

具体的 DNS 地址是这样的:

 

<pod-name>.<svc-name>.<namespace>.svc.cluster.local

 

这个 DNS 就是 Kubernetes 为 Pod 分配的唯一可解析身份,这样一来,只要有了 Pod 的名字和 Service 的名字,我们就能唯一确定一个能够访问这个 Pod 的 DNS 地址了。

 

3.3 配置 StatefulSet

 

下面,我们就来配置一个使用上述 nginx Service 的 StatefulSet:

 

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

 

 

这个 yaml 与 Deployment 的配置的唯一区别就是多了一个 ServiceName=nginx 的配置,它意味着 StatefulSet 控制器必须在执行控制循环时使用 nginx 这个 Service 来保证每一个 Pod 可解析。

 

通过 kubectl get 命令就可以查看 pod 的启动:

 

$ kubectl get statefulset web

 

通过命令 kubectl get pods -w -l app=nginx 可以看到这些 pod 的启动顺序,每一个 pod 都被命名为了 web-<编号>,比如 web-0 与 web-1,他们是严格按照编号顺次启动的。

 

如果我们通过 kubectl delete pod -l app=nginx,再通过 kubectl get 观察,就可以看到两个 Pod 删除后,Kubernetes 会按照原先的编号和顺序再次启动一组新的 pod,并且他们各自的网络身份与原 Pod 是一一对应的。

 

 

 

 

通过上述实践,我们看到,只要我们使用 DNS 记录来访问 StatefulSet 控制器控制下的 Pod,即使 Pod 发生了宕机和重启,DNS 记录对应的 nginx 记录本身是不会发生变化的,同一个“名字-编号”组合的 Pod 在 StatefulSet 中总是稳定地对外提供服务的,进而实现了整个“网络状态”的稳定。

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 

linux 使用及配置相关






kubernetes      pod      容器化      云原生      statefulset      网络状态     


京ICP备2021035038号