第3章 深入掌握Pod
3.1 Pod定义详解
3.2 Pod的基本用法
在使用docker时,可以使用docker run命令创建并启动一个容器。而在k8s系统中对长时间运行容器的要求是:其主程序需要一直在前台执行。
如果我们创建docker镜像的启动命令是后台执行程序,例如Linux脚本:
nohup ./start.sh &
则在kubelet创建包含这个容器的Pod之后运行完该命令,即认为Pod执行结束,将立即销毁该pod。如果为该pod定义了ReplicationController,
则系统会监控到该pod已经终止,之后根据RC定义中Pod的replicas副本数量生成一个新的pod。一旦创建新的pod,又陷入循环中了。这就是k8s需要我们
自己创建的docker镜像并以一个前台作为启动命令的原因。
对于无法改造成前台执行的应用,可以用Supervisor辅助进行管理。
3.3 静态Pod
静态Pod是由kubelet进行管理的仅存在于Node上的Pod。它们不能通过API Server进行管理,无法与ReplicationController、
Deployment或者DaemonSet进行关联,并且kubelet无法对它们进行健康检查。静态Pod总是由kubelet创建的,并且总在kubelet所在的node
上运行。
创建静态pod有2种方式:配置文件方式和HTTP方式。
1.配置文件方式
设置kubelet的启动参数 "--pod-manifest-path"。或者在 kubelet 配置文件中设置 staticPodPath,推荐这个。
2.HTTP方式
通过设置 kubelet 的启动参数 "--manifest-url",kubelet将会定期从该url地址下载Pod的定义文件,并以.yaml或
.json文件的格式进行解析,然后创建Pod。其实现方式和配置文件方式是一致的。
3.4 Pod容器共享Volume
同一个pod的多个容器能够共享pod级别的存储卷Volume。
3.5 Pod的配置管理
3.5.1 ConfigMap概述
ConfigMap供容器使用的典型用法如下:
1.生成为容器内的环境变量
2.设置容器启动命令的启动参数(需要设置为环境变量)
3.以Volume的形式挂载为容器内部的文件或目录
可以通过yaml配置文件或者直接使用 kubectl create configmap 命令行的方式来创建ConfigMap。
3.5.2 创建ConfigMap资源对象
1.通过yaml配置文件方式创建
//创建ConfigMap
kubectl create -f cm-appvars.yaml
//查看创建好的ConfigMap
kubectl get configmap
2.通过 kubectl 命令行方式创建
可以使用 --from-file 或者 --from-literal 指定内容,并且可以在一行命令中指定多个参数。
a)通过 --from-file 参数从文件中进行创建,可以指定key的名称,也可以在一个命令行中创建包含多个key的ConfigMap
kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
kubectl create configmap cm-server.xml --from-file=server.xml
b)通过 --from-file 参数从目录中进行创建,该目录下的每个配置文件名都被设置为key,文件的内容被设置为value,语法为:
kubectl create configmap NAME --from-file=config-files-dir
kubectl create configmap cm-appconf --from-file=configfiles
c)使用 --from-literal 时会从文本中进行创建,直接将指定的 key#=value# 创建为ConfigMap 的内容,语法为:
kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2
kubectl create configmap NAME --from-literal=loglevel=info --from-literal=appdatadir=/var/data
容器应用对 ConfigMap 的使用有以下2种方式:
1.通过环境变量获取ConfigMap中的内容
2.通过Volume挂载的方式将ConfigMap中的内容挂载为容器内部的文件或目录
3.5.3 在Pod中使用ConfigMap
1.通过环境变量方式使用ConfigMap
2.通过 volumeMount 使用 ConfigMap
3.5.4 使用ConfigMap的限制条件
1.ConfigMap 必须在pod之前创建
2.ConfigMap 受 Namespace 限制,只有处于相同 namespace 中的pod菜可以引用它
3.ConfigMap中的配额管理还未能实现
4.kubelet只支持可以被 api server 管理的Pod使用ConfigMap。kubelet在Node上通过 --manifest-url 或者 --config自动
创建的静态pod将无法引用ConfigMap
5.在pod对ConfigMap进行挂载操作时,在容器内部只能挂载为目录,无法挂载为文件。在挂载到容器内部后,在目录下将包含ConfigMap
定义的每个item,如果在该目录下原来还有其他文件,则容器内的该目录将被挂载的ConfigMap覆盖。如果应用程序需要保留原来的其他文件,
则需要进行额外的处理。可以将ConfigMap挂载到容器内部的临时目录,再通过启动脚本将配置文件复制或者链接到(cp或者link)应用所用
的实际配置目录下
3.6 在容器内获取Pod信息(Downward API)
每个pod被创建出来之后,都会被系统分配唯一的名字、IP地址,并且处于某个namespace中,那么如何在pod的容器如何获取这些信息呢?
答案是Downward API。
Downward API 可以通过下面2种方式将pod的信息注入容器内部:
1.环境变量:用于单个变量,可以将pod信息和Container信息注入容器内部
2.Volume挂载:将数组类信息生成文件并挂载到容器内部
3.6.1 环境变量方式:将Pod信息注入为环境变量
3.6.2 环境变量方式:将容器资源信息注入为环境变量
3.6.3 Volume挂载方式
3.7 Pod生命周期和重启策略
Pod的状态:
1.Pending
API Server已经创建该pod,但在pod内还有一个或者多个容器的镜像没有创建,包括正在下载镜像的过程。
2.Running
pod内所有容器均创建,且至少有一个容器处于运行状态、正在启动或者重启状态。
3.Succeeded
pod内所有容器均成功执行后退出,且不会再重启。
4.Failed
pod内所有容器均已退出,但至少有一个容器退出为失败状态。
5.Unknown
由于某种原因无法获取该pod的状态,可能由于网络通信不畅导致的。
Pod的重启策略(RestartPolicy),pod的重启策略应用于pod内的所有容器,并且仅在pod所处的Node上由kubectl进行判断和重启操作。当某个
容器异常退出或者健康检查失败时,kubelet 将根据 RestartPolicy 的设置来进行相应的操作:
1.Always
当容器失败时,由kubelet自动重启该容器;
2.OnFailure
当容器终止运行时且退出码不为0时,由kubelet自动重启该容器;
3.Never
不论容器运行状态如何,kubelet都不会重启该容器。
3.8 Pod健康检查和服务可用性检查
k8s 对pod的健康状态可以通过两类探针来检查:LivenessProbe和ReadinessProbe,kubelet定期执行者两类探针来诊断容器的健康情况。
1.LivenessProbe探针
用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将杀掉该容器,并根据容器的重启策略做
相应的处理。如果一个容器不包含Linveness探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。
2.ReadinessProbe探针
用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod菜可以接收请求。对于被Service管理的pod,Service与Pod Endpoint
的关联关系也将基于pod是否Ready进行设置。如果在运行过程中Ready状态变成False,则系统自动将其从Service的后端Endpoint列表中
隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的pod实例
上。
LivenessProbe和ReadinessProbe均可配置以下三种实现方式:
1.ExecAction
在容器内部执行一个命令,如果该命令返回0,则表明容器是健康的。
2.TCPSocketAction
通过容器的ip地址和端口进行tcp检查,如果能够建立tcp连接,则表明容器健康。
3.HTTPGetAction
通过容器的ip地址、端口号以及路径调用HTTP Get方法,如果响应的状态码大于200且小于400,则认为容器是健康的。
3.9 玩转Pod调度
在k8s平台上,我们很少会直接创建一个pod,大多数情况下都是通过RC、Deployment、DaemonSet、Job等控制器完成对一组Pod副本的
创建、调度以及生命周期的自动控制任务。
我们不应该直接使用底层的ReplicaSet控制Pod副本,而应该使用管理ReplicaSet的Deployment对象来控制副本,官方建议。
3.9.1 Deployment或RC:全自动调度
Deployment或者RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。
3.9.2 NodeSelector:定向调度
有时候需要将一些pod调度到指定的一些Node上。
1.首选in通过 kubectl label 命令给目标 Node 上打一些标签
kubectl label nodes <node-name> <label-key>=<label-value>
//打上 zone=north 的标签,也可以通过修改资源定义文件的方式,并执行 kubectl replace -f xxx.yaml 的方式
kubectl label nodes node1 zone=north
2.然后,在pod的定义中加上 nodeSelector的设置
3.kubectl create -f xxx.yaml ,创建该pod
4.kubectl get pods -o wide,查看
如果我们指定了pod的 nodeSelector 条件,且在集群中不存在包含相应标签的node,则即时在集群中还有其他可供使用的node,这个
pod也无法被成功调度。
NodeSelector 通过标签的方式,简单的实现了限制pod所在节点的方法。亲和性调度机制则极大扩展了pod的调度能力,主要的增强功能
如下:
1.根据表达力
2.可以使用软限制、优先采用等限制方式,代替之前的硬限制,这样调度器在无法满足优先需求的情况下,会退而求其次,继续运行该pod
3.可以依据节点上正在运行的其他pod的标签来进行限制,而非节点本身的标签。这样就可以定义一种规则来描述pod之间的亲和或互斥关系
3.9.3 NodeAffinity:Node亲和性调度
目前有两种亲和性表达:
1.RequiredDuringSchedulingIgnoredDuringExecution
必须满足指定的规则才可以调度pod到node上,与 nodeSelector很像,但是使用不同的语法。相当于硬限制。
2.PreferredDuringSchedulingIgnoredDuringExecution
强调优先满足指定规则,调度器会尝试调度pod到node上,但不强求,相当于软限制。多个优先级规则还可以设置权重值,以定义
执行的先后顺序。
IgnoredDuringExecution的意思是:如果一个pod所在的节点在pod运行期间标签发生了变更,不再符合该pod节点亲和性需求,则系统
将忽略node上label的变化,该Pod能继续在该节点上运行。
3.9.4 PodAffinity:Pod亲和与互斥调度策略
这一功能让用户从另一个角度来限制pod所能运行的节点:根据节点上正在运行的pod标签而不是节点的标签进行判断和调度,要求对节点和pod
2个条件进行匹配。
3.9.5 Taints和Tolerations(污点和容忍)
前面介绍的NodeAffinity节点亲和性,是在pod上定义的一种属性,使得pod能够被调度到某些Node上运行(优先或者强制要求)。Taint则
正好相反,它让Node拒绝pod的运行。
Taint 需要和 Toleration 配合使用,让pod避开那些不合适的node。在node上设置一个或者多个 Taint之后,除非Pod明确声明能够
容忍这些污点,否则无法再这些node上运行。Toleration是pod的属性,让pod能够(注意只是能够,而非必须)运行在标注了Taint的node上。
1.可以用 kubectl taint 命令为 node 设置 Taint 信息
kubectl taint nodes node1 key=value:NoSchedule
这个设置为node1加上了一个Taint,该 Taint 的键为key,值为value,Taint的效果是 NoSchedule。这意味着除非pod明确声明可以
容忍这个Taint,否则就不会被调度到 node1上。
然后,需要在pod上声明 Toleration。下面的2个 Toleration 都被设置为可以容忍(Toleration)具有该Taint的node,使得pod
能够被调度到node1上。
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
--------
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
pod 的 Toleration 声明中的key和effect需要与Taint的设置保持一致,并且满足下面条件之一:
1.operator的值是 Exists(无需指定value)
2.operator的值是 Equal并且value相等
如果不指定 operator,则默认值为 Equal。
另外,还有如下两个特例:
1.空的key配合Exists操作符能够匹配所有的键和值
2.空的effect匹配所有的effect
系统允许在同一个node上设置多个 Taint,也可以在pod上设置多个Toleration。k8s调度器处理多个 Taint和Toleration的逻辑
顺序为:首先列出节点中所有的 Taint,然后忽略pod的 Toleration能够匹配的部分,剩下的没有忽略的Taint就是对pod的效果了。下面是
几种特殊情况:
1.如果在剩余的Taint中存在 effect=NoSchedule,则调度器不会把该pod调度到这一节点上;
2.如果在剩余的 Taint 中没有 NoSchedule 效果,但是有 PreferNoSchedule效果,则调度器会尝试不把这个pod指派给这个节点;
3.如果在剩余的Taint中有 NoExecute效果,并且这个pod已经在该节点上运行,则会被驱逐;如果没有在该节点上运行,则也不会在被调度
到该节点上。
常见应用:
1.独占节点
kubectl taint nodes nodename dedicated=groupName:NoSchedule
然后给这些应用的pod加入对应的Toleration,这样,带有合适 Toleration 的Pod就会被允许同使用其他节点一样使用有Taint的节点
2.具有特殊硬件设备的节点
kubectl taint nodes nodename special=true:NoSchedule
kubectl taint nodes nodename special=true:PreferNoSchedule
3.定义Pod的驱逐行为,以应对节点故障
前面提到的 NoExecute 这个 Taint 效果对节点上正在运行的Pod有以下影响:
1.没有设置 Toleration 的pod 会被立即驱逐
2.配置了对应的 Toleration的pod,如果没有为 tolerationSeconds 赋值,则会一直留在这一节点中
3.配置了对应的 Toleration的pod且指定了 tolerationSeconds 值,则会在指定时间后驱逐
4.k8s从1.6版本开始引入一个Alpha版本的功能,即把节点故障标记为 Taint
3.9.6 Pod Priority Preemption:Pod优先级调度
抢占式调度几个维度:
1.Priority,优先级
2.QoS,服务质量等级
3.系统定义的其他度量指标
优先级抢占调度策略的核心行为分别是 驱逐(Eviction)和抢占(Preemption),这2种行为的使用场景不同,效果相同。Eviction是
kubelet进程的行为,
3.Kubernetes权威指南 --- 深入掌握Pod
于 2022-11-20 22:07:01 首次发布
本文详细探讨了Kubernetes中Pod的概念,作为最基础的部署单元,Pod如何承载应用实例,其生命周期管理,以及Pod在集群中的网络通信机制。通过学习,读者将能够深入掌握Pod在容器化环境中的核心作用。
摘要由CSDN通过智能技术生成