Kubernetes:控制器

Kubernetes控制器

Deployment -- 两层控制器

通过ReplicaSet个数描述应用版本(滚动升级),再通过ReplicaSet属性控制Pod数量(水平扩展)

image
  1. Deployment 的控制器,实际上控制的是 ReplicaSet 的数目,以及每个 ReplicaSet 的属性。
  2. 一个应用的版本,对应的是一个 ReplicaSet。这个版本应用的 Pod 数量,则由 ReplicaSet 通过它自己的控制器(ReplicaSet Controller)来保证。
  3. 通过这样的多个 ReplicaSet 对象,Kubernetes 项目就实现了对多个“应用版本”的描述。

有状态应用编排 -- Stateful

  1. 拓扑状态:应用多实例有多种关系。主从、主备顺序等。
  2. 存储状态:应用多实例分别绑定不同存储数据。比如容器当前读取到的数据和半小时后读取的数据是同一份数据。
  3. Stateful的实现方式就是记录下这些状态,然后当Pod被重建时,恢复这些状态。

Stateful 如何实现拓扑状态?

外界如何访问Pod -- Service

Service就是外界连接Pod的网络机制。比如一个Deployment控制了多个Pod,这是定义一个Service就能访问到这三个Pod。

那Service又是如何怎么被访问的呢

  1. 通过虚拟IP(virtual IP),当访问一个预先定义好的VIP时,K8s就会把这次的访问请求路由到Service上。
  2. 通过Service DNS,比如:test-service.test-namespace.svc.cluster.test。在DNS解析时有两种处理方式
    1. 一种是通过test-service.test-namespace.svc.cluster.test解析到VIP从而找到Pod
    2. 另一种是访问时,解析出来的就是直接暴露出来的Pod IP而不是VIP, 这种解析方式叫做Headless Service。(Headless Service的定义其实就是将cluster IP字段置为None,从而让这个Service没有一个VIP 作为头信息,从而暴露出Pod IP)

Stateful如何保持Pod拓扑状态

  1. 当定义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
  1. 当启动test这个svc和stateful后,Stateful就会创建两个testPod,并为它们命名为 testPod-0 与 testPod-1 。然后Stateful就会把两个Pod及其名称存储下来,以后不管是testPod-0或1被删除了,只要在Stateful生命周期内,这些顺序关系就不会失效。

Stateful 如何实现存储状态?

Persistent Volume Claim
  1. 定义一个 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
  1. 在应用的 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
  1. Kubernetes 中 PVC 和 PV 的设计,实际上类似于接口实现。开发者只要知道并会使用接口,即:PVC;而运维人员则负责给接口绑定具体的实现,即:PV。这种解耦,就避免了因为向开发者暴露过多的存储系统细节而带来的隐患。此外,这种职责的分离,往往也意味着出现事故时可以更容易定位问题和明确责任

StatefulSet存储状态

  1. 回到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
  1. 这个 StatefulSet 额外添加了一个 volumeClaimTemplates 字段。它跟 Deployment 里 Pod 模板(PodTemplate)的作用类似 => 凡是被这个 StatefulSet 管理的 Pod,都会声明一个对应的 PVC;而这个 PVC 的定义,就来自于 volumeClaimTemplates 这个模板字段。更重要的是,这个 PVC 的名字,会被分配一个与这个 Pod 完全一致的编号。这个自动创建的 PVC,与 PV 绑定成功后,就会进入 Bound 状态,这就意味着这个 Pod 可以挂载并使用这个 PV 了。
  2. 通过kubectl get pvc -l app=nginx,可以看到,这些 PVC,都以--< 编号 >的方式命名,并且处于 Bound 状态。
  3. 这个 StatefulSet 创建出来的所有 Pod,都会声明使用编号的 PVC。比如,在名叫 test-pod-0 的 Pod 的 volumes 字段,它会声明使用名叫 testVM 的 PVC,从而挂载到这个 PVC 所绑定的 PV。

守护进程 -- DaemonSet

  1. 举个例子: 我们很多组件,比如网络插件、存储插件、监控和日志组件都需要agent来帮助处理容器的网络,存储目录挂载、收集节点监控数据。而这个agent就是我们节点的守护进程。
  2. 在K8s中,它也是一种编排对象 -- DaemonSet,它比其他所有对象的启动时机都要早。
  3. DaemonSetController通过给node打污点的方式来保证 同样能容忍这个污点的Pod 也就是 DaemonSet 的Pod 是第一个关联到node上的。
参考:

《深入剖析Kubernetes》 - 张磊

你可能感兴趣的:(Kubernetes:控制器)