目录

一、pod概述:

1、pod概念

2、pod的分类:

二、 pause容器

1、pause容器概念:

2、创建pod的流程:

3、pause容器的作用:

4、pause总结:

三、pod的生命周期:

1、pod的状态:

2、pod的生命周期过程:

3、创建一个pod容器过程:

4、init容器的作用:

5、pod的重启策略

6、总结:


一、pod概述:

1、pod概念

pod是K8S中最小的资源管理组件

pod也是最小化运行容器化的应用的资源管理对象

pod是一个抽象的概念,可以理解为一个或者多个容器化应用的集合

在一个pod中运行一个容器是最常用的方式

在一个pod当中同时运行多个容器,一个pod中可以同时封装几个需要耦合的互相协作的容器

这些多个容器时共享资源,也可以互相协作,组成一个service单位。

不论是运行一个还是多个容器,K8S管理的都是pod而不是容器

一个pod内的容器,必须都运行在同一节点。

基于现代容器技术的要求,就是一个pod运行一个容器,一个容器运行一个进程

这样做的目的:

  1. 横向扩展,方便扩缩容
  2. 解耦,一个pod内运行多个容器,耦合度太高,一旦一个进程失败,整个pod将全部失败。一个pod运行一个容器,可以实现解耦,可以创建多个副本,实现高可用和负载均衡
  3. 管理方面,简单直观

2、pod的分类:

  1. 自主式pod:pod不会自我修复,如果pod内容器的进程终止,或者被delete删除、缺少资源被驱逐,这个pod没有办法自愈(只要不是基于控制器创建的都是自主式pod)
  2. 控制器管理pod:可以滚动升级,可以自愈(自动重启),可以管理pod的数量,以及扩缩容

二、 pause容器

1、pause容器概念:

pod内的容器共享资源。

共享机制:pause底层基础容器来提供共享资源的机制

pause容器时基础容器,也可以称为父容器。作用就是管理pod内容器的共享操作

pause还可以管理容器的生命周期

K8S提供了pause容器作用:

  1. 为pod内的所有容器提供一个命名空间
  2. 启动容器的PID命名空间,每个pod中都作为PID为1的进程(init进程),回收僵尸进程
  3. 创建pod时,先创建pause容器,然后拉取镜像,生成容器,形成pod(容器不是由pod管理,而是由pause管理容器的进程)

pause相当于pod的基础容器,先有pause再有pod

kubelet 是负责管理整个 Pod 中所有容器的组件,包括pause容器。pause容器在这里充当一个辅助角色,为其他容器提供共享的运行环境。

创建一个nginx pod的过程:先拉取pause容器,在拉取nginx镜像,容器跑起来,pause管理

销毁pod:先销毁nginx,pause回收容器资源,kubelet销毁pause

pause是pod的基础,由pause管理pod内部的容器

总的来说kubelet管理节点上的pod,pause管理pod内的容器

2、创建pod的流程:

第一步:master节点发出指令,pod使用的镜像nginx,pod的副本数

第二步:scheduler来分配执行的node节点

第三步:node节点的kubelet收到master的指令,先拉pause,再拉nginx:1.22,指定副本数

第四步:pause容器先启动,提供命名空间,进程管理pid=1,来为pod内的容器提供共享服务以及容器的进程管理

3、pause容器的作用:

共享网络命名空间: 所有容器都共享同一个网络命名空间,它们可以通过 localhost 相互通信,而无需通过网络进行通信。

共享存储卷: 所有容器可以访问相同的存储卷,这使得它们之间可以共享数据。

维护 Pod 的生命周期: "pause" 容器的存在确保了 Pod 的运行。当 Pod 中的其他容器终止时,"pause" 容器依然存在,从而保持整个 Pod 的存在,直到所有容器都终止。

总体而言,pause容器在 Kubernetes 的 Pod 中扮演了一个关键的角色,为其他容器提供了网络和存储的共享环境,同时通过维护其自身的存在来维护整个 Pod 的生命周期。

pause作用:

  1. 网络命名空间共享
  2. 只要创建pod就会创建pause,维护pod内部容器的生命周期
  3. pod可以指定多个共享的VOLUME,pod内的容器共享这些VOLUME卷,可以实现数据的持久化,防止pod重新构建之后文件丢失

4、pause总结:

pause容器共享两种资源:网络和存储资源

网络:每个pod都是被分配一个集群内部唯一的IP地址,pod内的容器共享网络,pod在集群内部的IP地址和端口

pod内部的容器可以使用localhost互相通信。pod中的容器与外部通信时,从共享的资源当中进行分配

每个pod都有一个基础容器,pause容器。

pause容器对应的镜像是属于K8S集群的一部分,创建集群的时候就会有pause这个基础镜像

pod里面包含了一个或者多个相关的容器(应用),提供服务的是容器,不是pod

endpoints给pod分配IP地址,网络插件分配网络服务

pod外面再设置一个初始镜像:

  1. pod内部有一组容器,挂了一个,就算整个pod失效了么? 引入pause机制,可以代表整个容器组的状态。可以解决对pod内部整体状态的判断
  2. pod内的容器和pod共享ip,共享VOLUME,解决了容器内网络通信的问题,解决了容器内部文件共享的问题

三、pod的生命周期:

1、pod的状态:

1、pending挂起状态:

pod已被创建,但是尚未分配到运行他的node节点

出现原因:

节点上资源不够

需要等待其他pod资源的调度完成

2、Running运行中:

pod已经被分配到了node节点,pod内部的所用容器都已经启动,运行状态正常

3、competed/successded:容器内部的进程运行完毕正常退出,没有发生错误

4、failed:pod中的容器非正常退出。发生了错误,需要通过查看详情或者日志定位问题

5、UNkown:由于某些原因,K8S集群无法获取pod的状态。apiserver出了问题

6、terminating:终止中,pod正在被删除,里面的容器正在终止。终止过程中,涉及资源回收、垃圾清理、终止过程中需要执行的命令

2、pod的生命周期过程:

1、 先有pause基础容器才会创建初始化init容器

2、 初始化容器运行完毕而且是成功运行完毕后才会创建pod的主业务容器

在容器的生命周期中还伴随着2个容器钩子:

3、 容器钩子:

poststart:表示容器运行时执行的第一个命令

prestop:容器结束时执行的最后一个命令

容器生命周期中还有2个探针:

探针:用于检测容器状态是否正常。

livenessProbe:存活探针

readinessProbe:流量探针

启动探针

存活探针和流量探针会伴随整个pod的生命周期

会不停的检测内部主业务容器的情况。只要主业务容器出现问题,整个pod将不再式ready状态。

但是启动探针除外

3、创建一个pod容器过程:

1、 基础容器:pause

2、 init容器(初始化容器):init c

3、 业务容器:主服务容器

先启动pause基础容器 > init初始化容器 > pod业务主容器

在pause基础容器和init初始化容器的过程中。pod状态:init 1/3---2/3---3/3

当所有init初始化都启动完毕才会创建业务容器

实验验证:

vim init.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-init
spec:
  containers:
  - name: nginx1
    image: nginx:1.22
#定义的业务容器
  initContainers:
  - name: init-centos1
    image: centos:7
    command: ["echo", "hello,world"]
  - name: init-contos2
    image: centos:7
    command: ["echo", "I am ready"]
#这里定义业务容器和两个init初始化容器
#会先创建完pause初始化容器后
#才会先执行init-centos1输出hello,world。
#再执行init-centos2输出I am ready
#最后才会拉起nginx容器

4、init容器的作用:

环境变量,可以在创建的过程中为业务容器定制好相关的代码和工具。

init容器独立于业务容器,他是单独构建的一个镜像,对业务容器不产生任何安全影响

init容器能以不同于pod内应用容器的文件系统视图运行。secrets的权限。应用容器无法访问secrets的权限

总结:

init容器提供了应用容器运行之前的先决条件,提供了一种阻塞或者延迟机制来控制应用容器的启动。只有前置条件满足,才会创建pod内的应用容器

1、在pod的启动过程中,容器是按照初始化容器先启动,每个容器都必须下一个容器启动之前,要成功退出

2、如果有运行失败,会按照容器的重启策略进行指定动作,restartPolicy:Alawys Never Onfailure(非正常退出才会重启)

3、所有的init容器没有成功之前,pod是不会进入ready状态的

init容器与service无关。不能对外提供访问

  1. 如果重启pod,所有的init容器一定会重新执行
  2. 如果修改init容器的spec(参数),只限制于image,修其他修改字段都不生效(基于deployment创建的pod)
  3. 每个容器的名称都要唯一,不能重复

5、pod的重启策略

实验举例:

apiVersion: v1
kind: Pod
metadata:
  name: centos
spec:
  restartPolicy: OnFailure
#k8s中pod的重启策略,基于容器的状态进行pod的重启
#Always:总是重启。只要容器退出,无论容器的状态码是正常还是不正常。默认策略可以不加
#Never:永不重启。只要容器退出,无论容器是否正常都不重启
#OnFailure:只有容器的状态码非0时候才会重启。正常退出不会重启。
#一般情况下都使用默认Always,只有特殊情况下会使用Never
#在deployment的yaml文件当中,重启的策略只能是Always也是默认策略。所以可以不加。
  containers:
  - name: centos
    image: centos:7
    command: ["echo", "I am ready"]

在deployment的yaml文件当中,重启的策略只能是Always也是默认策略。所以可以不加

实验举例:

apiVersion: v1
kind: Pod
metadata:
  name: centos
spec:
  restartPolicy: OnFailure
#k8s中pod的重启策略,基于容器的状态进行pod的重启
#Always:总是重启。只要容器退出,无论容器的状态码是正常还是不正常。默认策略可以不加
#Never:永不重启。只要容器退出,无论容器是否正常都不重启
#OnFailure:只有容器的状态码非0时候才会重启。正常退出不会重启。
#一般情况下都使用默认Always,只有特殊情况下会使用Never
#在deployment的yaml文件当中,重启的策略只能是Always也是默认策略。所以可以不加。
  containers:
  - name: centos
    image: centos:7
    command: ["echo", "I am ready"]

6、总结:

pause容器:底层容器/基础容器

提供pod内容器的网络和共享存储,以及pod内容器退出之后资源回收

init容器:人为设定的,业务容器启动之间的必要条件

pod的生命周期:

  1. pause基础容器
  2. init容器——全部成功退出——业务容器
  3. poststart prestop 容器的钩子

启动时命令和退出时的命令

  1. 探针:探测容器的健康状态。伴随pod的整个生命周期(除了容器探针)

总结一句话:

pod就是用来封装管理容器的,业务是容器。服务也是容器。端口也是容器

四、Pod控制器

1、概述

1.1、Pod的控制器是什么?

pod控制器:工作负载均衡。workload。用于管理pod的中间层。确保pod资源符合预期的状态。

预期状态:

1. 副本数
2. 容器的重启策略
3. 镜像拉取策略

pod出现故障时的重启等等

2、Pod控制器的类型

2.1、 replicaSet:指定副本的数量

三个组件:

1. Pod的副本数
2. 标签选择器:判断哪个pod归自己管理
3. 扩缩容

2.2、 Deployment控制器

他是工作在replicaSet之上。管理无状态应用。目前是最好的控制器。支持滚动跟新和回滚。提供声明式配置。

3、 statefulSet:也是控制器的一种,管理有状态的应用。也可也设置副本数,可以扩缩容。 Pod的序号是固定的。重启之后,Pod的名称也不会发生变化。表示有状态的pod

4、 DaemonSet:可以在所有节点部署一个pod。它没有副本数。可以限制部署的节点。也是无状态应用。服务必须是守护进程。例如: ingress、logstash、flannel

5、 job:工作pod控制器。执行完成即可退出。不需要重启,不需要重建。

6、 cronjob:周期性的定时任务控制器。不需要再后台持续运行。

Pod与控制器之间的关系

### 1、 controllers

1、 controllers:管理控制器

pod通过label---selector进行关联。

通过标签和选择标签和控制器关联

strategy字段:

web应用不需要加strategy字段会导致服务中断。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx1
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx1
  strategy:
      type: Recreate
#每次有更新,都会把旧的pod全部停止,然后再启动新的实例。服务可能会短暂的终端。无特殊需要可不加
  template:
    metadata:
      labels:
        app: nginx1
    spec:
      containers:
      - image: nginx:1.22
        name: nginx

  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%

这是deployment的默认更新策略

rollingUpdate:滚动跟新

maxSurge: 25% 升级过程中,新启动的pod数量不能超过期望pod数的25%

maxUnavailable: 25% 升级过程中,新的pod启动好后,销毁的旧pod数量不能超过期望pod的25%

升级和销毁都不能超过期望pod的25%这样不会导致业务中断

3、 无状态应用

2、 无状态应用:pod名称是无序的。认为所有pod都是一体的。共享NFS存储。

所有deployment下的pod共享一个存储。

statfulSet:有状态应用。pod的名称是有序的。所有pod都是独立的。存储卷也是独立的。顺序从0开始到n。

delete删除也不会改变pod的序号。扩缩容也是有序扩缩容。同样从0开始

headless service:无头服务,他没有clusterIP。必须要有动态的pvc

statfulSet有状态应用控制器实验举例:

apiVersion: v1
kind: Service
metadata:
  name: nginx-web
  labels:
    app: nginx2

spec:
  ports:
  - port: 80
    targetPort: 80
  clusterIP: ""
  selector:
    app: nginx2
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
  labels:
    app: nginx2

spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
  serviceName: "nginx-web"
  template:
    metadata:
      labels:
        app: nginx2
    spec:
    apiVersion: v1
kind: Service
metadata:
  name: nginx-web
  labels:
    app: nginx2

spec:
  ports:
  - port: 80
    targetPort: 80
  clusterIP: ""
#clusterIP必须为空
  selector:
    app: nginx2
---
apiVersion: apps/v1
#开始创建控制器
kind: StatefulSet
metadata:
  name: web
  labels:
    app: nginx2

spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx2
  serviceName: "nginx-web"
  #定义应用哪个service文件
  template:
    metadata:
      labels:
        app: nginx2
    spec:
      containers:
      - name: nginx
        image: nginx:1.22
        volumeMounts:
#定义挂载卷
        - name: html
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  #定义动态卷
  - metadata:
      name: html
    spec:
      accessModes: ["ReadWriteMany"]
#定义挂载卷权限
      storageClassName: "nfs-client-storageclass"
      resources:
        requests:
          storage: 2Gi

headless service无头服务:是k8s集群中一种特殊的服务类型。

1. 他不分配clusterIP给service。

2. 不会负载均衡到后端的pod。

3. 通过DNS来提供服务的发现和访问。

由于ClusterIP是空的。k8s集群会给每个headless service中的pod创建一个dns记录。

格式: pod-name.headless-service-name.namespace.svc.cluster.local.

通过dns直接解析访问pod的IP地址

#### 为什么要使用headless?

有序、独立个体

deployment的pod是没有名称的。随机字符串。无序的。他需要一个集中的clusterIP来集中统一为pod提供网络。

statefulset是有序的。pod名称是固定的。即便是重建之后pod的表示也不变。pod的名称是唯一的标识符。

系统直接通过pod名称解析IP地址。

只要pod名称不变通过pod名来映射IP地址即可

#### 为什么要使用动态PV?

只要是有状态的副本集群都会涉及到持久化存储。但是每个pod是独立个体。每个pod都有自己专用的存储点。

statefulSet再定义时就规定了每个pod不能使用同一个存储卷。所以才需要动态PV

定义好了每个pod都必须绑定一个存储卷所以使用动态pv

#### statefulset的使用场景

1. 用于不是固定节点的应用。不是固定IP的应用。
2.  更新发布比较频繁的场景
3.  支持自动伸缩。节点资源不够,可以自动扩容的场景。

删除statefulset

不需要clusterIP。没有clusterIP的就是无头服务headless

### 3、 demonSet

4、 demonSet:

确保每个节点上都运行一个pod副本。如果有node加入集群,也会为他薪资一个pod

实验举例:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-daemon
  labels:
    app: nginx1
#提高代码的可读性。方便别人读。不同业务可以通过namespace隔离。
#命名时根据业务进行专业命名
spec:
  selector:
    matchLabels:
      app: nginx1
  template:
    metadata:
      labels:
        app: nginx1
    spec:
      containers:
      - name: nginx
        image: nginx:1.22
#部署一个daemonset的控制器。
#daemonset不能指定副本数他会在每个节点上都创建一个pod

kubectl delete daemonsets.apps nginx-daemon
#删除daemonSet控制器

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-daemon
  labels:
    app: nginx1
#提高代码的可读性。方便别人读。不同业务可以通过namespace隔离。
#命名时根据业务进行专业命名
spec:
  selector:
    matchLabels:
      app: nginx1
  template:
    metadata:
      labels:
        app: nginx1
    spec:
      containers:
      - name: nginx
        image: nginx:1.22
      nodeSelector:
        ingress: "true"
#只在有ingress为true这个标签的节点上部署,没有这个标签的节点不会部署

kubectl delete daemonsets.apps nginx-daemon
#删除daemonSet控制器

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-daemon
  labels:
    app: nginx1
#提高代码的可读性。方便别人读。不同业务可以通过namespace隔离。
#命名时根据业务进行专业命名
spec:
  selector:
    matchLabels:
      app: nginx1
  template:
    metadata:
      labels:
        app: nginx1
    spec:
      containers:
      - name: nginx
        image: nginx:1.22
      nodeSelector:
        ingress: "true"
#只在有ingress为true这个标签的节点上部署,没有这个标签的节点不会部署

kubectl delete jobs.batch centos
#删除控制器

对于k8s系统来说,既然定义了是job。你只需要执行一次,或者指定册数即可。不能一直允许。

它拥有两个限制:

1. 必须要指定容器容器策略:OnFailure、Never
2. 执行失败的次数也是受限制的。默认是6次。字数可以通过添加 backoffLimit 来自定义失败次数
3. 跟新yaml文件要先删除任务。再更新。不能动态更新。

5、job

job分为两类:

job:普通任务

cronjob:定时任务

job的作用:执行只需要一次性的任务

适用于脚本需要执行、数据库迁移、视频解码等等业务

对K8S系统来说,既然定义了是job,你只需要执行一次,或者指定次数即可,不能一直允许

第一点:必须要指定容器的重启策略(只能是Onfailure、Never)

第二点:执行失败的次数也是受限的。默认是6次

第三点:更新yaml文件要先删除任务,再更新。他不能动态更新

apiVersion: batch/v1
kind: Job
metadata:
  name: centos

spec:
  template:
    spec:
      containers:
      - name: centos
        image: centos:7
        command: ["/bin/bash", "-c", "test -e /etc/passwd"]
      restartPolicy: Never
  backoffLimit: 4
#允许任务失败的次数是4次,4次到了之后,restartPolicy的策略,来进行容器的重启或者不重启

backoffLimit: 4

失败四次之后才会执行Never

6、 cronjob

cronjob:周期性执行任务,定时执行。和linux的crontab含义是一样的。语法一样都是 分 时 日 月 周

应用场景:定时备份、通知作用、定时检查(结合探针一起布置设定多长时间执行一次)

1. 必须要指定容器容器策略:OnFailure、Never
2. 执行失败的次数也是受限制的。默认是3次。
3. 跟新yaml文件要先删除任务。再更新。不能动态更新。

实验举例:

apiVersion: batch/v1
kind: Job
metadata:
  name: centos
spec:
  template:
    spec:
      containers:
      - name: centos
        image: centos:7
        command: ["/bin/bash", "-c", "test -e /etc/passwd"]
#定义一个任务
#Job类型的参数必须要设置重启策略。只支持“OnFailure、Never”两种策略
      restartPolicy: Never
#指定重启策略
  backoffLimit: 4
#定义重启次数。如果不加默认6次
#允许任务失败的次数是4次。
#当达到4次之后。根据容器的重启策略restartPolicy来进行容器的重启或者是不重启。

kubectl delete cronjobs.batch hello
#删除定时任务

7、总结

五个都是控制器创建的pod都是依赖于控制器。

deployment:无状态应用。最好用的。也是最多的

statefulSet:有状态应用。有序的。独立的pod

daemonSet:无状态应用。不能定义副本数。每个系欸但都运行一个pod。可以指定节点。

job:执行一次性的任务。必须要有重启策略。同时默认失败次数6次。只有失败次数达到,重启策略才会生效

cronjob:定时任务。通知。备份或者探测。执行定时任务。必须要有重启策略。默认失败3次。只有失败次数达到后重启策略才会生效

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐