K8S工作负载(2)
ReplicaSet
上一章我们讲到,一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力,那么这个 Replicaset 又是什么呢。
K8S 官方针对 ReplicaSet 的解释是ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性
这句话的意思就是replicaset 是用来维护指定数量的 Pod并保障指定数量 Pod 的可用性的。
上述说了 Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。也因此,官方建议使用 Deployment 而不是直接使用 ReplicaSet, 除非你需要自定义更新业务流程或根本不需要更新。
kubectl get rs -n xxxx # 查看执行 namespace 下的副本集合
StatefulSet
在实际场景中,多个实例之间,往往有依赖关系,比如:主从关系,主备关系;还有就是数据存储类应用,它的多个实例,往往都会在本地磁盘上保存一份数据。而这些实例一旦被杀掉,即便重建出来,实例与数据之间的对应关系也已经丢失,从而导致应用失败。所以,这种实例之间有不对等关系,以及实例对外部数据有依赖关系的应用,就被称为“有状态应用”
Kubernetes 中的 StatefulSet就是用来管理有状态应用的工作负载API 对象。
- StatefulSet给每个Pod提供固定名称,Pod名称增加从0-N的固定后缀,Pod重新调度后Pod名称和HostName不变。
- StatefulSet通过Headless Service给每个Pod提供固定的访问域名,Service的概念会在后面章节中详细介绍。
- StatefulSet通过创建固定标识的PVC保证Pod重新调度后还是能访问到相同的持久化数据。
Headless Service
如前所述,创建Statefulset需要一个Headless Service用于Pod访问,Service的概念会在后续章节中详细介绍,这里先介绍Headless Service的创建方法。
spec.clusterIP:#必须设置为None,表示Headless Service。
spec.ports.port:#Pod间通信端口号。
spec.ports.name:#Pod间通信端口名称。
这里我们创建一个 mysql 的 headless service
apiVersion: v1
kind: Service # 对象类型为Service
metadata:
name: mysql-default
namespace: dsc
spec:
clusterIP: None # 必须设置为None,表示Headless Service
ports:
- name: server # Pod间通信的端口名称
port: 3306 # Pod间通信的端口号
- name: metrics
port: 9104
selector:
app.kubernetes.io/component: mysql-default # 选择标签为对应的 pod
$ kubectl get svc -owide -n dsc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
mysql-default ClusterIP None <none> 3306/TCP,9104/TCP 5m app.kubernetes.io/component=mysql-default
Create StatefulSet
Statefulset的YAML定义与其他对象基本相同,主要有两个差异点:
- serviceName指定了Statefulset使用哪个Headless Service,需要填写Headless Service的名称。
- volumeClaimTemplates是用来申请持久化声明PVC ,storageClassName指定了持久化存储的类型;volumeMounts是为Pod挂载存储。当然如果不需要存储的话可以删除volumeClaimTemplates和volumeMounts字段。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-default
spec:
replicas: 3
serviceName: mysql-default # headless service的名称
selector:
matchLabels:
app.kubernetes.io/component: mysql-default
template:
metadata:
labels:
app.kubernetes.io/component: mysql-default
spec:
imagePullSecrets:
- name: inner
containers:
- name: mysql-exporter
image: "mysqld-exporter:0.10.0-amd64"
imagePullPolicy: IfNotPresent
ports:
- name: http-metrics
containerPort: 9104
env:
- name: DATA_SOURCE_NAME
value: "exporter:exporter@(localhost:3306)/"
- name: mysql
image: "mariadb:10.3.28-4c6641b-amd64"
imagePullPolicy: IfNotPresent
ports:
- name: mysql
containerPort: 3306
resources:
limits:
cpu: "2"
memory: 8Gi
requests:
cpu: "1"
memory: 4Gi
volumeMounts: # Pod挂载的存储
- name: volume0
mountPath: /var/lib/mysql # 存储挂载到/var/lib/mysql
volumeClaimTemplates:
- metadata:
name: volume0
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: storageclass-local-mysql
resources:
requests:
storage: 9.5G # 持久化存储的类型
命令执行后,查询一下StatefulSet和Pod,Pod的名称后缀从0开始到2,逐个递增。
$ kubectl get sts
NAME READY AGE
mysql-default 3/3 5m
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-default-0 2/2 Running 0 5m
mysql-default-1 2/2 Running 0 4m
mysql-default-2 2/2 Running 0 3m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
volume0-mysql-dsc-0 Bound local-pv-519f8522 186Gi RWO storageclass-local-mysql 5m
volume0-mysql-dsc-1 Bound local-pv-8fee3347 186Gi RWO storageclass-local-mysql 5m
volume0-mysql-dsc-2 Bound local-pv-f89adf61 186Gi RWO storageclass-local-mysql 5m
网络标识
StatefulSet创建后,Pod是有固定名称的,Headless Service是使用DNS,为Pod提供固定的域名,这样Pod间就可以使用域名访问,即便Pod被重新创建而导致Pod的IP地址发生变化,这个域名也不会发生变化。
Headless Service创建后,每个Pod的IP都会有下面格式的域名。
...svc.cluster.local
我们通过在集群内的一个工具的 pod,使用nslookup查看pod 的对应域名:
$ kubectl exec -it toolbox-xxx bash
//
nslookup mysql-default-0.mysql-default.default
Server: 169.254.25.10
Address: 169.254.25.10#53
Name: mysql-default-0.mysql-default.default.svc.cluster.local
Address: 10.225.94.8 #对应的 mysql-default-0 的 pod 的 podIP
//
nslookup mysql-default-1.mysql-default.default
Server: 169.254.25.10
Address: 169.254.25.10#53
Name: mysql-default-1.mysql-default.default.svc.cluster.local
Address: 10.231.90.191 #对应的 mysql-default-1 的 pod 的 podIP
//
nslookup mysql-default-2.mysql-default.default
Server: 169.254.25.10
Address: 169.254.25.10#53
Name: mysql-default-2.mysql-default.default.svc.cluster.local
Address: 110.228.119.81 #对应的 mysql-default-2 的 pod 的 podIP
若通过手动删除1和2的 pod, pod 被重新拉起的后,通过nslookup 会发现,对应的域名仍然会被解析到对应的 pod 上。
存储状态
通过PVC做持久化存储,保证Pod重新调度后还是能访问到相同的持久化数据,在删除Pod时,PVC不会被删除。下图就是sts 的 pod 的重建过程