Kubernetes控制器
Deployment -- 两层控制器
通过ReplicaSet个数描述应用版本(滚动升级),再通过ReplicaSet属性控制Pod数量(水平扩展)
image- Deployment 的控制器,实际上控制的是 ReplicaSet 的数目,以及每个 ReplicaSet 的属性。
- 一个应用的版本,对应的是一个 ReplicaSet。这个版本应用的 Pod 数量,则由 ReplicaSet 通过它自己的控制器(ReplicaSet Controller)来保证。
- 通过这样的多个 ReplicaSet 对象,Kubernetes 项目就实现了对多个“应用版本”的描述。
有状态应用编排 -- Stateful
- 拓扑状态:应用多实例有多种关系。主从、主备顺序等。
- 存储状态:应用多实例分别绑定不同存储数据。比如容器当前读取到的数据和半小时后读取的数据是同一份数据。
- Stateful的实现方式就是记录下这些状态,然后当Pod被重建时,恢复这些状态。
Stateful 如何实现拓扑状态?
外界如何访问Pod -- Service
Service就是外界连接Pod的网络机制。比如一个Deployment控制了多个Pod,这是定义一个Service就能访问到这三个Pod。
那Service又是如何怎么被访问的呢
- 通过虚拟IP(virtual IP),当访问一个预先定义好的VIP时,K8s就会把这次的访问请求路由到Service上。
- 通过Service DNS,比如:
test-service.test-namespace.svc.cluster.test
。在DNS解析时有两种处理方式- 一种是通过
test-service.test-namespace.svc.cluster.test
解析到VIP从而找到Pod - 另一种是访问时,解析出来的就是直接暴露出来的Pod IP而不是VIP, 这种解析方式叫做
Headless Service
。(Headless Service
的定义其实就是将cluster IP字段置为None,从而让这个Service没有一个VIP 作为头信息,从而暴露出Pod IP)
- 一种是通过
Stateful如何保持Pod拓扑状态
- 当定义Stateful时指定serviceName,比如如下,让Stateful在控制循环的时候使用
test-sf
来保证Pod的可解析身份
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: test-sf
spec:
serviceName: "test"
replicas: 2
selector:
matchLabels:
app: test-pod
template:
metadata:
labels:
app: test-pod
spec:
containers:
- name: test-pod
image: xxx
ports:
- containerPort: 80
name: testPod
- 当启动
test
这个svc和stateful后,Stateful就会创建两个testPod,并为它们命名为 testPod-0 与 testPod-1 。然后Stateful
就会把两个Pod及其名称存储下来,以后不管是testPod-0或1被删除了,只要在Stateful
生命周期内,这些顺序关系就不会失效。
Stateful 如何实现存储状态?
Persistent Volume Claim
- 定义一个 PVC,声明想要的 Volume 的属性:在这个 PVC 对象里,不需要任何关于 Volume 细节的字段,只有描述性的属性和定义。比如,storage: 1Gi,表示我想要的 Volume 大小至少是 1 GiB;accessModes: ReadWriteOnce,表示这个 Volume 的挂载方式是可读写,并且只能被挂载在一个节点上而非被多个节点共享
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pv-claim-test
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
- 在应用的 Pod 中,声明使用这个 PVC,只要我们创建这个 PVC 对象,Kubernetes 就会自动为它绑定一个符合条件的 Volume 即 pv
apiVersion: v1
kind: Pod
metadata:
name: pv-pod
spec:
containers:
- name: pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: pv-storage
volumes:
- name: pv-storage
persistentVolumeClaim:
claimName: pv-claim-test
- Kubernetes 中 PVC 和 PV 的设计,实际上类似于
接口
和实现
。开发者只要知道并会使用接口
,即:PVC
;而运维人员则负责给接口
绑定具体的实现,即:PV
。这种解耦,就避免了因为向开发者暴露过多的存储系统细节而带来的隐患。此外,这种职责的分离,往往也意味着出现事故时可以更容易定位问题和明确责任
StatefulSet存储状态
- 回到StatefulSet对存储状态管理上来
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: test-sf
spec:
serviceName: "test"
replicas: 2
selector:
matchLabels:
app: test-pod
template:
metadata:
labels:
app: test-pod
spec:
containers:
- name: test-pod
image: xxx
ports:
- containerPort: 80
name: xxx
volumeMounts:
- name: testVM
mountPath: /usr/share/xxx
volumeClaimTemplates:
- metadata:
name: testVM
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
- 这个
StatefulSet
额外添加了一个volumeClaimTemplates
字段。它跟 Deployment 里 Pod 模板(PodTemplate)的作用类似 => 凡是被这个StatefulSet
管理的Pod
,都会声明一个对应的 PVC;而这个 PVC 的定义,就来自于volumeClaimTemplates
这个模板字段。更重要的是,这个 PVC 的名字,会被分配一个与这个 Pod 完全一致的编号。这个自动创建的 PVC,与 PV 绑定成功后,就会进入 Bound 状态,这就意味着这个 Pod 可以挂载并使用这个 PV 了。 - 通过
kubectl get pvc -l app=nginx
,可以看到,这些 PVC,都以<PVC 名字 >-<StatefulSet 名字 >-< 编号 >
的方式命名,并且处于 Bound 状态。 - 这个
StatefulSet
创建出来的所有 Pod,都会声明使用编号的 PVC。比如,在名叫test-pod-0
的 Pod 的 volumes 字段,它会声明使用名叫testVM
的 PVC,从而挂载到这个 PVC 所绑定的 PV。
守护进程 -- DaemonSet
- 举个例子: 我们很多组件,比如网络插件、存储插件、监控和日志组件都需要agent来帮助处理容器的网络,存储目录挂载、收集节点监控数据。而这个agent就是我们节点的守护进程。
- 在K8s中,它也是一种编排对象 -- DaemonSet,它比其他所有对象的启动时机都要早。
- DaemonSetController通过给node打
污点
的方式来保证 同样能容忍
这个污点
的Pod 也就是 DaemonSet 的Pod 是第一个关联到node上的。
网友评论