StatefulSet
1 ) 概述
- Stateful,也就是有状态应用,微服务无状态是一个理想的这么一个环境
- 有些应用是有状态的,比如这个web服务器,它只能运行在一台server上
- 因为它要访问一些持久化的存储
- 比如说 mysql 它就是一个典型的有状态的应用,不希望应用随时漂移到别的节点上,然后数据发生变化
- 为什么说它有状态?
- 就是因为它的数据是落在这个磁盘上的
- 虽然云原生应用里面,尽量的把一些服务都变成云原生的应用
- 在实际生活中,在实际企业开发中,很多应用它是有状态的
- 那什么是无状态的呢?
- 比如一个博客应用,它是无状态的,它不依赖于你底层的数据库服务地址
- 这个应用可以部署多个
- 在这个mysql服务器,它是有状态的应用,K8s为了应对,提出了 StatefulSets 的概念
- StatefulSets 它是用来管理Deployment和扩展一组Pod,并且为这个pod提供序号唯一性的保证
- 所以它和Deployment的不同是在于
- 它管理了一组相同容器定义的pod, 它为每个Pod维护了一个固定的ID
- 在Deployment,它的ID是一个Pod名称加后面随机字母的组合,它的名称是动态拼出来的
- 但是,StatefulSet的pod, 它的容器名称有一个永久不变的ID, 如果建3个,就会变成 -0, -1, -2 这样的不变ID
- StatefulSets 会定义你期望的一个状态,比如说你有3个副本,它会给你创建3个副本
- StatefulSets 的使用场景
- 有稳定唯一的网络标识符
- 有一个稳定的持久化的存储,可以有序的去缩放,有序的去更新扩容
- 有序的是指更新是从012345...按顺序更新,而不是随机的去更新
- 这样的应用更适合 StatefulSets 来管理,而不是Deployment
- StatefulSets 的限制
- 必须有这个挂载 PersistentVolume 挂载卷,可以是本地,也可以是对象存储
- 需要有一个外部的持久化化存储,基于 storage class来匹配,那么这里面有一点很重要
- 注意,如果说删掉 StatefulSets 中的pod并不会删除它的关联的存储
- 这样是保证数据的安全,而在Deployment里删除pod, 其创建的临时数据文件都会消失
- 对于 StatefulSets 它其实更着重的是这些数据
- 所以 K8s 它设计的时候,存储这个对象和 StatefulSets,是两个隔离的对象
- 另外,StatefulSets 需要用 headless 服务来创建pod标识
- headless叫无头服务
- 就是我的请求, 有时候不想走负载均衡,直接想通过IP链接到后端
- 这个时候在 K8s 中,它就提供这个headless这个服务
- 在HTTP发请求的时候发一个post请求之前,会发一个head请求,这个headless请求会做一些事情
- 比如说对方后端的这个IP地址是哪里?做一些 session 的认证
- headless请求, 就是直接能够不发这个head请求,直接和后端的服务进行一个交互,直接进行CRUD的操作
- 在这种情况下, 需要要把这个 clusterip 设成为 none
- 就是 StatefulSets 里面的 pod 在容器里面不用固定的IP
2 )应用
-
在这里面,我们会先创建一个Service,然后再创建这个StatefulSets
-
新建 sfs-demo1.yaml
yamlapiVersion: apps/v1 kind: StatefulSet metadata: name: mongodb spec: serviceName: mongodb #必须配置 和service名字统一起来 replicas: 2 selector: matchLabels: app: mongodb template: metadata: labels: app: mongodb spec: containers: - name: mongo image: mongo:4.4 --- apiVersion: v1 kind: Service metadata: name: mongodb spec: selector: app: mongodb type: ClusterIP # HeadLess clusterIP: None ports: - port: 27017 #本 Service 的端口 targetPort: 27017 #容器的端口
-
$
kubectl apply -f sfs-demo1.yaml
confstatefulset.apps/mongodb created service/mongodb created
-
$
kubectl get all
confNAME READY STATUS RESTARTS AGE pod/mongodb-0 1/1 Running 0 20s pod/mongodb-1 1/1 Running 0 19s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 6d2h service/mongodb ClusterIP None <none> 27017/TCP 20s NAME READY AGE statefulset.apps/mongodb 2/2 20s
-
$
kubectl rollout restart statefulset mongodb
重启 -
$
kubectl scale statefulset mongodb --replicas=5
扩容 -
$
kubectl get all
confNAME READY STATUS RESTARTS AGE pod/mongodb-0 1/1 Running 0 3m31s pod/mongodb-1 1/1 Running 0 3m33s pod/mongodb-2 1/1 Running 0 2m33s pod/mongodb-3 1/1 Running 0 21s pod/mongodb-4 1/1 Running 0 20s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 6d2h service/mongodb ClusterIP None <none> 27017/TCP 6m49s NAME READY AGE statefulset.apps/mongodb 5/5 6m49s
-
$
kubectl get svc
confNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 6d2h mongodb ClusterIP None <none> 27017/TCP 8m49s
-
$
kubectl get endpoints mongodb -o yaml
confapiVersion: v1 kind: Endpoints metadata: annotations: endpoints.kubernetes.io/last-change-trigger-time: "2024-04-23T06:21:28Z" creationTimestamp: "2024-04-23T06:14:58Z" labels: service.kubernetes.io/headless: "" name: mongodb namespace: default resourceVersion: "292772" uid: e600cd76-37e9-48c1-90f8-fae2b31bbbd4 subsets: - addresses: - hostname: mongodb-1 ip: 10.244.1.107 nodeName: node1.k8s targetRef: kind: Pod name: mongodb-1 namespace: default resourceVersion: "292407" uid: 654c1164-9a0d-46c0-8148-61f71a6e7224 - hostname: mongodb-0 ip: 10.244.1.108 nodeName: node1.k8s targetRef: kind: Pod name: mongodb-0 namespace: default resourceVersion: "292437" uid: cef974da-f02d-4d93-bb00-0c74d534c866 - hostname: mongodb-3 ip: 10.244.1.109 nodeName: node1.k8s targetRef: kind: Pod name: mongodb-3 namespace: default resourceVersion: "292757" uid: caf43581-9e7c-48db-a761-1cb74e0ea871 - hostname: mongodb-2 ip: 10.244.2.67 nodeName: node2.k8s targetRef: kind: Pod name: mongodb-2 namespace: default resourceVersion: "292743" uid: 1eeba1cb-0e50-45fa-81d2-f4022dbd8b63 - hostname: mongodb-4 ip: 10.244.2.68 nodeName: node2.k8s targetRef: kind: Pod name: mongodb-4 namespace: default resourceVersion: "292770" uid: 4e3dc9f3-4f28-4802-af9a-705c12404ae5 ports: - port: 27017 protocol: TCP
-
$
kubectl exec -ti mongodb-0 -- mongo
测试数据存储confMongoDB shell version v4.4.29 connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("74389cfe-1776-43ef-a37a-61cf5a7a9d82") } MongoDB server version: 4.4.29 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see https://docs.mongodb.com/ Questions? Try the MongoDB Developer Community Forums https://community.mongodb.com --- The server generated these startup warnings when booting: 2024-04-23T06:18:17.563+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted 2024-04-23T06:18:17.563+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' --- >
-
$
exit
退出confbye
-
$
run mongodb-client --rm --tty -i --restart='Never' --image mongo:4.4 --command -- bash
连接数据库测试confIf you don't see a command prompt, try pressing enter. root@mongodb-client:/#
-
$
mongo --host mongodb-0.mongodb
confMongoDB shell version v4.4.29 connecting to: mongodb://mongodb-0.mongodb:27017/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("83892098-096c-4521-acf4-54aa13312392") } MongoDB server version: 4.4.29 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see https://docs.mongodb.com/ Questions? Try the MongoDB Developer Community Forums https://community.mongodb.com --- The server generated these startup warnings when booting: 2024-04-23T06:18:17.563+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted 2024-04-23T06:18:17.563+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' --- >
关于run相关参数
- $
kubectl run nginx --image=nginx
- 启动一个 Nginx 实例
- $
kubectl run hazelcast --image=hazelcast --port=5701
- 启动一个 hazelcast 单个实例,并开放容器的5701端口
- $
kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
- 运行一个 hazelcast 单个实例,并设置容器的环境变量"DNS_DOMAIN=cluster" and "POD_NAMESPACE=default"
- $
kubectl run nginx --image=nginx --replicas=5
- 启动一个 replicated 实例去复制 nginx
- $
kubectl run nginx --image=nginx --dry-run
- 试运行,不创建他们的情况下,打印出所有相关的 API 对象
- $
kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
- 用可解析的 JSON 来覆盖加载
deployment
的spec
,来运行一个 nginx 单个实例 - 替换 ... 为具体key, value
- 用可解析的 JSON 来覆盖加载
- $
kubectl run -i --tty busybox --image=busybox --restart=Never
- 运行一个在前台运行的 busybox 单个实例,如果退出不会重启