Kubernetes Pod使用

Pod是Kubernetes中可以创建、调度和部署的最小,也是最简单的单元。Pod是基于Kubernetes部署和运维应用的基础。本文重点介绍下Pod各字段的含义及Pod的使用,关于Pod更多的知识细节可以参考Kubernetes Pod详解一文。
本文参考的主要内容来源于Kubernetes 1.29版本,在阅读时要稍微注意下,避免出现因版本不兼容导致的功能差异。

API对象公共属性配置

Pod作为API对象,具有API对象需要包含的一些公共属性。其中:apiVersions属性用来标识API对象对应资源的版本,这里是Pod的API版本;kind用来标识API对象的资源类型,这里是"Pod"类型;metadata用来记录API对象的元数据信息,如name(名称)、uid(唯一id)、namespace(命名空间)、labels(标签)、annotations(注释)、finalizers(终结器)、ownerReferences(属主引用)等,更多API对象metadata的介绍可以参考Kubernetes官网ObjectMeta一文;spec用来描述对象的期望状态以及关于对象的一些基本信息。对于Pod来说,spec声明了需要使用的容器信息和多个容器共享的信息(如重启策略、挂载在Pod的存储卷、安全上下文等),是学习和使用Pod的重点;status用来描述系统当前达到的状态,由Kubernetes自动更新。不同类型的对象可以有不同的status信息,这里是PodStatus。不推荐用户去修改该属性。可以通过该属性查看Pod最新状态,辅助定位问题。API对象公共属性配置在Pod的声明文件的内容如下:

apiVersion: v1                 # 对象基础属性,标识API对象对应资源的版本,这里是Pod版本
kind: Pod                      # 对象基础属性,标识API对象的资源类型,这里是Pod类型
metadata:                      # 对象基础属性,记录API对象的元数据信息name: string                     # 标识当前API对象在同类资源中的唯一性uid: string                      # 标识当前API对象在整个集群中的唯一性,由Kubernetes自动填充namespace: string                # 用于将同一集群的资源进行逻辑分组labels:                          # 给资源打标签,用于指定对用户有意义且相关的对象的标识属性name1: stringname2: stringannotations:                     # 用来记录一些注释信息name1: stringname2: stringfinalizers:                      # 用于告诉 Kubernetes等到特定的条件被满足后,再完全删除被标记为删除的资源- string- stringownerReferences:                 # 标记其属主信息- apiVersion: string                 # 属主版本kind: string                       # 属主资源类型blockOwnerDeletion: boolean        # 默认为 false,如果为 true,且属主具有 "foregroundDeletion“ 终结器,则在删除此引用之前,无法删除属主controller: boolean                # 如果为 true,则此引用指向管理的控制器name: string                       # 属主名称uid: string                        # 属主uid
spec:                          # 对象基础属性,描述该对象的期望状态,不同类型的API对象其spec的格式都是不同的,在使用时要根据API对象的类型具体分析. containers:                                        # Pod中声明的容器,容器相关的字段很多,后面再展开描述- name: stringimage: stringimagePullPolicy: [Always | Never | IfNotPresent]restartPolocy: [Always | Never | OnFailure ]volumes:                    # Pod专属属性,描述Pod上挂载的存储卷,可被Pod中的容器共享,支持挂载多种存储类型,如Secret、ConfigMap等- name: string                   # 定义创建volume的名称,容器中需要使用这个名字来引用存储卷
status:                        # 对象基本属性,描述系统当前达到的状态,由Kubernetes自动更新。不同类型的对象可以有不同的status信息。这里对应PodStatushostIP: string                   # Pod所在Node的IPphase: [Pending | Running | Succeeded | Failed] # Pod所处生命周期阶段qosClass: [BestEffort | Guaranteed | Burstable] # Pod的服务质量类(Quality of Service class,QoS class),在Node资源不足时使用QoS类来就驱逐Pod作出决定PodIP: string                    # Pod的IPreason: string                   # 如果运行失败,记录具体原因startTime: time                  # 记录状态的时间conditions:                      # Status的细分,描述造成当前Status的具体原因- lastProbeTime: timelastTransitionTime: timestatus: stringtype: stringreason: stringinitContainerStatuses:          # Pod中容器初始状态的记录- containerID: stringimge: stringimageID: stringname: stringlastState: [running | terminated | waiting]state: [running | terminated | waiting]containerStatuses:              # Pod中容器当前状态的记录- containerID: stringimge: stringimageID: stringname: stringlastState: [running | terminated | waiting]state: [running | terminated | waiting]

注意,上面只是列举了常用的属性,完整的属性信息可以参考官网PodSpec一文。更多API对象公共属性的知识细节可以参考Kubernetes API对象一文。接下来重点介绍Pod独有属性的使用。

在Pod中声明容器

一个Pod里可以封装一个容器或多个容器,可将Pod看成是对容器的编排。接下来介绍如何在Pod中声明容器。在Pod的声明文件的spec.containers属性声明容器,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:                                         # Pod中声明容器- name: string                                          # 容器名称image: string                                         # 镜像名称imagePullPolicy: [Always | Never | IfNotPresent]      # 镜像拉取策略command: [string]                                     # 容器启动时执行的命令,一般其启动容器镜像里的应用args: string                                          # 命令参数workingDir: string                                    # 容器的工作目录。如果未指定,将使用容器运行时的默认值,该默认值可能在容器镜像中配置stdin: boolean                                        # 是否使用stdin作为容器的标准输出,默认是falsestdinOnce: boolean                                    # 在第一个客户端附加到stdin时打开并接受数据,直到客户端断开连接,并关闭 stdintty: boolean                                          # 当使用stdin作为标准输出时,使用tty接收用户的标准输输入,返回操作系统的标准输出terminationMessagePath: string                        # 指定容器中文件路径用于写入容器的终止消息terminationMessagePolicy: [File | FallbackToLogsOnError]  # 指定写入策略,File类型指无论容器是否成功终止,都写入,FallbackToLogsOnError指在容器错误终止时,写入ports:                                                # 指定容器公开的端口列表- name: string                                           # 端口名称,Service会使用端口名来引用端口containerPort: string                                  # 容器的公开端口protocol: string                                       # 端口协议。必须是UDP、TCP 或 SCTP的一种。默认为TCPhostIP: string                                         # Node的IPhostPort: string                                       # Node的端口

上面仅介绍spec.containers的部分属性,更多属性的介绍可以参考Kubernetes官网Container v1 core一文。

资源申请及限制–CPU和内存的申请及限制

容器可以正常启动后,接下来要考虑的一个问题就是容器CPU和内存等资源的分配及限制。这里重点介绍下CPU和内存资源,其他资源的申请和限制有相似之处。可以在Pod声明文件的spec.containers.resources属性中指定需要申请的资源及对其使用的上限,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:                                         # Pod中声明容器- name: string                                          # 容器名称image: string                                         # 镜像名称command: [string]                                     # 容器启动时执行的命令,一般其启动容器镜像里的应用args: string                                          # 命令参数resources:                                            # 容器使用资源requests:                                              # 需要申请的资源memory: string                                          # 指定内存资源大小cpu: string                                             # 指定CPU资源大小limits:                                                # 需要限制的资源memory: string                                          # 指定内存资源大小cpu: string                                             # 指定CPU资源大小

需要注意的是,不同资源使用的单位不同,如内存资源的基本单位是字节(byte),其他还有:E、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Ki等;而CPU资源以CPU单位度量。Kubernetes中的一个 CPU 等同于:1个AWS vCPU或1个GCP核心或1个Azure vCore或裸机上具有超线程能力的英特尔处理器上的1个超线程。在CPU资源中,小数值是可以使用的。一个请求 0.5 CPU 的容器保证会获得请求 1 个 CPU 的容器的 CPU 的一半。 同时也可以使用后缀m表示毫。如 100m CPU、100 milliCPU 和 0.1 CPU 都是相同的。CPU资源的精度不能超过1m。需要注意的是,CPU资源只能使用绝对数量,而不是相对数量。0.1在单核、双核或48核上的CPU数量值是一样的。使用示例如下:

...
spec:containers:- name: demo-appimage: demo-image...resources:                       # 容器资源requests:                         # 当前容器申请的资源cpu: 1500m                         # 申请CPU资源1500m,也即1.5个CPUmemory: 1.5Gi                      # 申请内存资源1.5Gilimits:                           # 当前容器可使用资源上限cpu: 2                             # CPU资源上限2000m,也即2个CPUmemory: 2Gi                        # 内存资源上限2Gi

上述示例表明名为"demo-app"的容器的内存请求为1.5GiB,内存限制为2GiB,CPU请求为1500milliCPU,CPU限制为2个CPU。
在分配资源时,可能存在以下情况:
(1) 容器申请的资源超过了Node能力。如果没有Node可以满足新创建Pod里容器请求的资源,那么这个Pod将无法正常运行,会一直处于Pending状态。可以通过kubectl describe pod查看详细信息。
(2) 指定了需要申请的资源,但未指定资源的限制。如果没有为容器指定资源限制,则会发生以下情况之一:容器在可以使用的资源上没有上限。因而可以使用所在节点上所有的可用资源;容器在具有默认CPU限制的名字空间中运行,系统会自动为容器设置默认限制。集群管理员可以使用LimitRange指定CPU限制的默认值。
(3) 指定了资源的限制,但未指定需要申请的资源。这时,Kubernetes会自动为其设置与资源的限制相同的资源请求值。
(4) 未指定需要申请的资源,也未指定资源的限制。这种情况统一归类为"未指定资源的限制"进行处理。
常用的资源主要指CPU和内存,其他还包括分页大小等,同时Kubernetes也支持对一些扩展资源进行申请和限制。更多资源申请及限制相关的属性介绍可以参考Kubernetes官网ResourceRequirements v1 core一文。

配置探针

Kubernetes对Pod的健康状态可以通过三类探针来检查:LivenessProbe(存活探针)、ReadinessProbe(就绪探针)及StartupProbe(启动探针)。其中,LivenessProbe指示容器是否正在运行。如果存活态探测失败,则kubelet会杀死容器,并且容器将根据其重启策略来进一步处理。ReadinessProbe指示容器是否准备好为请求提供服务(准备接收流量)。如果就绪态探测失败,Endpoint Controller将从与Pod匹配的所有服务的Endpoint列表中删除该Pod的IP地址,这样流量就不会到达该Pod。StartupProbe指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet将杀死容器,而容器依其重启策略来进一步处理。在Pod声明文件定义探针的内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:                                         # Pod中声明容器- name: stringimage: stringargs: stringlivenessProbe:                                      # 配置容器的liveness探针exec:                                               # 通过在容器中执行命令来完成探测,注意需要执行shell命令,还需显式调用shellcommand: [string]                                   # 需要执行的命令列表initialDelaySeconds: int                            # 表示在容器启动后,延时多少秒才开始探测,避免因容器启动但内部服务还未启动就启动探测并失败的情况periodSeconds: int                                  # 探测的频率,默认10s,最小值是1timeoutSeconds: int                                 # 探测超时限制,到了超时时间,如果探测还没返回结果,则说明此处探测失败。默认值是1,最小值是1failureThreshold: int                               # 最小连续失败次数,如果达到,则表示容器未就绪。默认值是3,最小值是1successThreshold: int                               # 最小连续成功次数,如果达到,则表示容器启动成功。默认值是1,最小值是1readinessProbe:                                     # 配置容器的readiness探针httpGet:                                            # 通过HTTP GET请求来完成探测host: string                                        # 待访问的主机名称,默认是Pod IPpath: string                                        # HTTP GET请求访问的资源路径port: int                                           # 待访问的端口scheme: string                                      # 连接host使用的协议,默认是HTTPhttpHeaders:                                        # HTTP GET请求中需要填充的HEADER- name: stringvalue: stringinitialDelaySeconds: intperiodSeconds: inttimeoutSeconds: intfailureThreshold: intsuccessThreshold: intstartupProbe:                                       # 配置容器的startup探针tcpSocket:                                          # 通过tcp套接字请求来完成探测host: string                                        # 待访问的主机名称,默认是Pod IPport: int                                           # 待访问的端口initialDelaySeconds: intperiodSeconds: inttimeoutSeconds: intfailureThreshold: intsuccessThreshold: int

LivenessProbe、ReadinessProbe、StartupProbe均使用相同的数据结构Probe描述探针。更多探针属性介绍可以参考Kubernetes官网Probe v1 core一文。
在使用探针时,需要选择探测方式。目前,Kubernetes支持四种不同的探测方式:exec方式用来在容器内执行指定命令、httpGet方式用来对容器的IP地址上指定端口和路径执行HTTP GET请求、tcpSocket方式用来对容器的IP地址上的指定端口执行TCP请求、grpc方式(v1.27稳定支持)使用gRPC执行一个远程过程调用。
由于LivenessProbe、ReadinessProbe、StartupProbe三种探针使用相同的数据结构,所以仅以其中一种探针作为事例,这里选择LivenessProbe。示例代码如下:

apiVersion: v1
kind: Pod
metadata:name: probe-demo-http
spec:containers:- name: liveness-demoimage: registry.k8s.io/liveness-demolivenessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 30  # 延迟探测时间periodSeconds: 3         # 重试时间间隔timeoutSeconds: 10       # 探测超时限制,到了超时时间,如果探测还没返回结果说明探测失败failureThreshold: 3      # 检测失败3次,就表示未就绪successThreshold: 2      # 检查成功2次,就表示就绪

在上述配置中,periodSeconds字段指定了kubelet每隔3秒执行一次存活探测。initialDelaySeconds字段告诉kubelet在执行第一次探测前应该等待30秒。kubelet会向容器内运行的服务(服务在监听8080端口)发送一个HTTP GET请求来执行探测。如果服务器上/healthz路径下的处理程序返回成功代码,则kubelet认为容器是健康存活的。如果处理程序返回失败代码,则kubelet会杀死这个容器并将其重启。对于HttpGet请求来说,返回大于或等于200并且小于400的任何代码都表示成功,其它返回代码都表示失败。

使用Hook

在容器的生命周期中,Kubernetes为其定义了postStartpreStop两个Hook,用来执行用户的一些扩展操作。
当一个容器启动后,Kubernetes将立即发送postStart事件;在容器被终结之前,Kubernetes将发送一个preStop事件。容器可以为每个事件指定一个处理程序。可以在Pod声明文件的spec.containers.lifecycle属性中对postStart事件或preStop事件指定的处理程序,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:- name: stringimage: stringargs: stringlifecycle:                                    # 在容器的生命周期配置HookpostStart:                                    # 创建容器后立即调用postStartexec:                                         # 在容器中执行命令command: [string]                             # 需要执行的命令列表preStop:                                      # 容器终止前调用preStop,如果容器崩溃或退出,则不会调用该处理程序。sleep:                                        # 配置休眠信息seconds: int                                  # 休眠时间,单位是秒

postStart和preStop更多属性的介绍可以参考Kubernetes官网Lifecycle v1 core一文。
在Hook上指定操作时,Kubernetes支持三种四种的探测方式:exec方式用来在容器内执行指定命令、httpGet方式用来对容器的IP地址上指定端口和路径执行HTTP GET请求、tcpSocket方式用来对容器的IP地址上的指定端口执行TCP请求、sleep方式设置休眠时间。示例代码如下:

...
spec:containers:- name: demo-appimage: demo-image...lifecycle:postStart:                                    # 创建容器后立即调用postStartexec:                                         # 在容器中执行命令,这里是打印指定字符串command: ["/bin/sh", "-c", "echo Hello World > /usr/share/message"]preStop:                                      # 容器终止前调用preStop,如果容器崩溃或退出,则不会调用该处理程序。sleep:                                        # 配置休眠信息seconds: 10                                 # 休眠10秒

在上述示例中,postStart事件在容器的/usr/share目录下写入文件message。preStop事件则让容器休眠了10秒。

在Pod中配置Init Container

Kubernetes引入Init Container(初始化容器)执行应用容器(app Contianer)启动之前的一些初始化操作。Init Container与应用容器在本质上是一样的,只是它们仅运行一次就结束,并且必须在成功运行完成后,系统才能继续执行下一个容器。Init Container中定义的容器,都会比spec.containers定义的应用容器先启动。如果为一个Pod指定了多个 Init Container,那些这个容器会按顺序逐一启动,直至都启动并退出,应用容器才会启动。
如果Pod的Init Container失败,则认为该Pod失败,Kubernetes会不断地重启该Pod,直到Init Container成功为止。然而,如果Pod对应的restartPolicy为Never,它就不会重新启动。
可以在Pod的声明文件的spec.initContainers属性配置Init Container,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:initContainers:                                         # Pod中声明Init Container- name: string                                          # 容器名称image: string                                         # 镜像名称command: [string]                                     # 容器启动时执行的命令,一般其启动容器镜像里的应用args: string                                          # 命令参数ports:                                                # 指定容器公开的端口列表- name: string                                           # 端口名称,Service会使用端口名来引用端口containerPort: string                                  # 容器的公开端口protocol: string                                       # 端口协议。必须是UDP、TCP 或 SCTP的一种。默认为TCPhostIP: string                                         # Node的IPhostPort: string                                       # Node的端口

Init Container配置可用属性与spec.containers一致,更多属性的介绍可以参考Kubernetes官网Container v1 core一文。
只是考虑到Init Container的使用场景,一般无需给Init Container配置生命周期操作(如postStart、preStop等)、探针(如Liveness、Readiness、Startup)等属性。
具体使用示例可以参考Kubernetes官网Init Containers一文。

在Pod中挂载存储卷

容器内部存储的生命周期是短暂的,会随着容器环境的销毁而销毁,具有不稳定性。如果多个容器希望共享同一份存储,则仅仅依赖容器是很难实现的。所以在Kubernetes中,把所有的存储资源抽象成存储卷(Volume)并将其设计在Pod层级来解决这个问题。存储卷是与Pod绑定的,且与Pod具有相同生命周期的资源对象。Pod的存储卷是被定义在Pod上,然后被各个容器挂载到自己的文件系统中的。同一个Pod中的多个容器能够共享Pod级别的存储卷。
可以在Pod的声明文件的spec.volumes属性,在Pod中挂载存储卷,然后在spec.containers.volumeMounts配置Init Container,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:- name: stringimage: stringcommand: [string]args: stringvolumeMounts:                   # 在容器中挂载存储卷- name: string                     # 存储卷的名称,对应Pod中的存储卷mountPath: string                # 存储卷的挂载路径,这里指容器中的路径volumes:                     # Pod专属属性,描述Pod上挂载的存储卷,可被Pod中的容器共享,支持挂载多种存储类型,如Secret、ConfigMap等- name: string                    # 定义创建volume的名称,容器中需要使用这个名字来引用存储卷emptyDir: object                # 存储卷的类型,这里是emptyDir,表示临时目录- name: stringconfigMap: object               # 存储卷的类型,这里是configMap,存储键值对等配置信息- name: stringpersistentVolumeClaim: object   # 存储卷的类型,这里是persistentVolumeClaim,用来声明持久化存储- name: stringsecret: object                  # 存储卷的类型,这里是secret,存储敏感键值对等信息

Kubernetes支持多种不同类型的存储卷的挂载,如azureDisk、cephfs、configMap、emptyDir、persistentVolumeClaim、secret等,更多存储卷类型以及spec.volumes属性可以参考Kubernetes官网Volume v1 core一文。在Pod上定义存储卷后,就可以在各个容器中将其挂载到文件系统中。更多容器中挂载卷的属性参考Kubernetes官网VolumeMount v1 core一文。使用示例如下:

...
spec:containers:- name: demo-appimage: demo-image...volumeMounts:                         # 容器中使用存储卷- name: demo-volume-1                     # 指定需要使用的存储卷,该存储卷已在sepc.volumes中声明mountPath: /data/app                   # 存储卷在容器中的挂载路径volumes:- name: demo-volume-1                    # 定义创建volume的名称emptyDir: {}                           # 存储卷的类型,这里是emptyDir,表示临时目录

上述示例中将类型为emptyDir的存储卷demo-volume-1挂载在Pod上,并将其应用到"demo-app"容器中,并对应到容器的"/data/app"路径。可以使用emptyDir存储容器日志等易失性数据。

在Pod中使用亲和性和反亲和性

在生产环境中,出于健壮性、性能等方面的考虑,需要将Pod部署到特定的Node或者将存在某些相互依赖、频繁调用的Pod部署在同一个Node,亦或让某些Pod尽可能地远离某些特定的Pod等调度需求。如两个应用频繁交互,就有必要利用亲和性让两个应用尽可能靠近,这样可以减少因网络通信而带来的性能损耗;如某个应用采用多副本部署时,就有必要采用反亲和性让各个应用实例分布在各个Node节点上,这样可以提高服务的高可用性。以上诉求可以通过亲和性和反亲和性这一概念来实现。亲和性和反亲和性主要分为三类:
节点亲和性(Node Affinity):以Node为目标,解决Pod可以调度到哪些Node的问题
Pod亲和性(Pod Affinity):以Pod为目标,解决Pod可以和哪些已存在pod部署到同一个拓扑域中的问题
Pod反亲和性(Pod AntiAffinity):以Pod为目标,解决Pod不能和哪些已存在的pod部署在同一个拓扑域中的问题
这里的拓扑域由一些Node节点组成,这些Node节点通常有相同的地理空间坐标,如在同一个机架、机房或地区,一般用region表示机架、机房等拓扑域,用Zone表示地区跨度更大的拓扑域。在极端情况下,也可以认为一个Node就是一个拓扑域。
可以在Pod的声明文件的spec.affinity属性配置亲和性和反亲和性,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:- name: stringimage: stringaffinity:                                          # Pod的亲和性配置,支持三种配置:nodeAffinity、podAffinity、podAntiAffinitynodeAffinity:                                      # Pod亲和Node配置preferredDuringSchedulingIgnoredDuringExecution:   # 调度期间尽量满足- weight: int                                        #筛选条件的权重,优先选择权重总和最大的Nodepreference:                                        # 多个筛选条件,所有的条件都要满足,AND关系matchExpressions:                                  # 基于Node的标签(label)匹配的规则- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchFields:                                       # 基于Node的字段(field)匹配的规则- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]requiredDuringSchedulingIgnoredDuringExecution:    # 调度期间必须满足nodeSelectorTerms:                                 # 多个筛选条件,满足一个就行,OR关系- matchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchFields:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]podAffinity:                                      # Pod间亲和配置preferredDuringSchedulingIgnoredDuringExecution:- weight: intpodAffinityTerm:                                 # Pod亲和筛选项topologyKey: string                              # 指定拓扑域,Pod在亲和筛选时,仅能匹配拓扑域相同的NodenamespaceSelector:                               # 基于命名空间的筛选器matchExpressions:                                # 匹配的表达式,所有的条件都要满足,AND关系- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabels: object                              # matchLabels 是 {key,value} 对的映射。matchLabels映射中的单个{key,value}相当于matchExpressions的一个元素,其key字段是“key”,运算符是“In”,values数组只包含“value”。这些要求是“AND”。namespaces: [string]                             # 指定命名空间列表,限制namespaceSelector作用的命名空间labelSelector:                                   # 基于标签的筛选器,匹配规则与基于命名空间的筛选器的匹配规则一致matchLabels: objectmatchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabelKeys: [string]mismatchLabelKeys: [string]requiredDuringSchedulingIgnoredDuringExecution:- topologyKey: stringnamespaceSelector:matchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabels: objectnamespaces: [string]labelSelector:matchLabels: objectmatchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabelKeys: [string]mismatchLabelKeys: [string]podAntiAffinity:                                     # Pod反亲和配置,其配置项与podAffinity一致,只是作用效果相反preferredDuringSchedulingIgnoredDuringExecution:- weight: intpodAffinityTerm:                                 # Pod亲和筛选项topologyKey: string                              # 指定拓扑域,Pod在亲和筛选时,仅能匹配拓扑域相同的NodenamespaceSelector:                               # 基于命名空间的筛选器matchExpressions:                                # 匹配的表达式,所有的条件都要满足,AND关系- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabels: object                              # matchLabels 是 {key,value} 对的映射。matchLabels映射中的单个{key,value}相当于matchExpressions的一个元素,其key字段是“key”,运算符是“In”,values数组只包含“value”。这些要求是“AND”。namespaces: [string]                             # 指定命名空间列表,限制namespaceSelector作用的命名空间labelSelector:                                   # 基于标签的筛选器,匹配规则与基于命名空间的筛选器的匹配规则一致matchLabels: objectmatchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabelKeys: [string]mismatchLabelKeys: [string]requiredDuringSchedulingIgnoredDuringExecution:- topologyKey: stringnamespaceSelector:matchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabels: objectnamespaces: [string]labelSelector:matchLabels: objectmatchExpressions:- key: stringoperator: [In | NotIn | Exists | DoesNotExist | Gt | Lt]values: [string]matchLabelKeys: [string]mismatchLabelKeys: [string]

对亲和性来说,提供了两种亲和等级:软亲和(preferredDuringSchedulingIgnoredDuringExecution,也称软需求、软限制)和硬亲和(requiredDuringSchedulingIgnoredDuringExecution,也称硬需求、硬限制)。对硬亲和来说,必须满足指定的规则,如果不存在这样的Node,则无法调度Pod,Pod会一致处于pending状态。对软亲和来说,强调优先满足指定规则,如果不存在这样的Node,也不强求,仍能调度到无法满足条件的Node上。对于多个规则的场景,可以通过设置权重(weight)值,来定义执行的先后顺序。权重值越高,越先匹配。
更多Affinity属性的介绍可以参考Kubernetes官网Affinity v1 core一文。

NodeAffinity

NodeAffinity(节点亲和性)关注Pod与Node之间的亲和性关系。通过NodeAffinity,可以要求或禁止将某个Pod调度到具有特定亲和性关系的Node上,以满足应用程序的性能和资源需求。使用示例如下:

spec:...affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: topology.kubernetes.io/zoneoperator: Invalues:- antarctica-east1- antarctica-west1- matchFields:- key: topology.kubernetes.io/zoneoperator: Invalues: ["antarctica-south1","antarctica-north1"]preferredDuringSchedulingIgnoredDuringExecution:- weight: 1preference:matchExpressions:- key: another-node-label-keyoperator: Invalues:- another-node-label-value- weight: 2preference:matchFields:- key: another-node-field-keyoperator: Invalues:- another-node-field-value

在这一示例中,所应用的规则如下:
(1) Node必须包含一个键名为topology.kubernetes.io/zone的标签,并且该标签的取值必须为 antarctica-east1 或 antarctica-west1,并且必须保证字段的取值为antarctica-south1或antarctica-north1。
(2) Node最好具有一个键名为another-node-label-key 且取值为 another-node-label-value 的标签,
或具有一个键名为another-node-field-key且取值为another-node-field-value的字段,且优先匹配后面的规则。

PodAffinity和PodAntiAffinity

PodAffinity(Pod亲和性)关注Pod间的亲和性关系,而PodAntiAffinity关注Pod间的反亲和性关系。通过PodAffinity和PodAntiAffinity可以将不同的Pod调度到同一个拓扑域或者调度到不同的拓扑域,以满足应用程序的性能和资源需求。尽管PodAffinity和PodAntiAffinity使用不同的对象描述,但是从结构上来说,目前两者结构相同,具体可以参考Kubernetes官网PodAffinity v1 core和PodAntiAffinity v1 core。使用示例如下:

...
spec:...affinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: securityoperator: Invalues:- S1topologyKey: topology.kubernetes.io/zone- namespaceSelector:matchExpressions:- key: namespacke-keyoperator: Invalues:- namespacke-valuetopologyKey: topology.kubernetes.io/zonepodAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: securityoperator: Invalues:- S2topologyKey: topology.kubernetes.io/zone- weight: 10podAffinityTerm:namespaces:- namespace-1- namespace-2namespaceSelector:matchExpressions:- key: namespacke-keyoperator: Invalues:- namespace-valuetopologyKey: topology.kubernetes.io/zone

上述示例中,定义了一条Pod亲和性规则和一条Pod反亲和性规则。其中:
亲和性规则规定,只有Node属于特定的拓扑域(这里是topology.kubernetes.io/zone)且该区域中的其他Pod已打上security=S1标签且该区域中的其他Pod命名空间namespacke-key的键包含namespacke-value的值时,调度器才可以将示例Pod调度到此节点上。
反亲和性规则规定,如果Node属于特定的拓扑域(这里是topology.kubernetes.io/zone)且该区域中的其他Pod已打上security=S2标签或该区域中的其他Pod命名空间namespacke-key的键包含namespacke-value的值,则调度器应尝试避免将示例Pod调度到此节点上。但是对于这条规则来说,因为是软需求,所以如果没有符合条件的Node,仍有可能调度到这类Node。
需要注意的是,Pod间亲和性和反亲和性都需要不小的计算量,因此会在大规模集群中显著降低调度速度。不建议在包含数百个节点的集群中使用这类设置。

Taints(污点)和Tolerations(容忍度)

如果说亲和性使Pod被吸引到一类特定的节点,那么Taint(污点)则相反,它的作用是使节点能够排斥一类特定的Pod。Toleration(容忍度)则允许调度器调度带有对应Taint的Pod。注意,Toleration允许调度但并不保证调度:作为其功能的一部分,调度器也会评估其他参数。Taint和Toleration相互配合,可以用来避免Pod被分配到不合适的Node上。每个节点上都可以应用一个或多个Taint,这表示对于那些不能容忍Taint的Pod,是不会被该Node接受的。
可以使用命令kubectl taint给Node增加一个Taint,示例如下:

$kubectl taint nodes node1 key1=value1:NoSchedule

这样就给名为node1的Node增加了一个Taint,它的键名是key1,键值是value1,效果是NoSchedule。
而Pod为了能够将其部署到拥有Taint的Node上,需要在其声明文件中声明spec.Tolerations,内容如下:

apiVersion: v1
kind: Pod
metadata:name: stringnamespace: string
spec:containers:- name: stringimage: stringtolerations:                                           # 声明可容忍Taint的Node- key: string                                            # 待匹配的taint的keyoperator: [Exists | Equal]                             # 匹配操作类型:相等或模糊匹配effect: [NoSchedule | PreferNoSchedule | NoExecute]    # 容忍Taint的效果,如PreferNoSchedule将尝试避免将不能容忍污点的Pod调度到的节点上,但不能保证一定避免tolerationSeconds: int                                 # 容忍的时长,单位是秒,如一个Node之前没有Taint,再新添加Taint后,其上的Pod还可以继续执行tolerationSecondsvalue: string                                          # taint的键对应的值,不适用operator为Exists的场景

更多Toleration属性的介绍可以参考Kubernetes官网Toleration v1 core一文。使用示例如下:

...
spec:...tolerations:- key: "example-key"operator: "Exists"effect: "NoSchedule"tolerationSeconds: 3600  

在上述示例中,待创建的Pod可以被分配到taint的键中包含“example-key”的Node上或没有taint的Node上。如果该Pod运行在一个没有taint的Node上,如果手动给这个Node添加taint,那么这个Pod仍能运行3600秒。

在API对象中使用Pod

因为Pod生命周期是短暂的,一旦运行完成则立即回收,且涉及Pod的创建、自愈、删除等操作比较复杂,所以很少在Kubernetes中直接使用Pod。而是使用更高级的API对象来管理Pod。当前将应用的类型划分为以下几种:无状态应用(stateless application)、批处理型(batch)、节点后台支撑型(node-daemon)和有状态应用型(stateful application)。对应Kubernetes中API对象是Deployment、Job、DaemonSet和StatefulSet。
在Deployment、Job、DaemonSet和StatefulSet等资源对象中声明Pod的方式一致,都是在spec.template属性上声明PodTemplate,而PodTemplate遵循Pod的Schema规范。示例如下:

apiVersion: apps/v1
kind: Deployment
metadata:name: demo-deployment
spec:replicas: 3selector:matchLabels:app: demo-apptemplate:                      # template字段用来声明Pod,遵循Pod的Schema规范metadata:labels:app: demo-appspec:containers:- name: demo-appimage: demo-app-image

所以说,掌握了Pod的Schema后,就可轻松地在Deployment、Job、DaemonSet和StatefulSet等资源对象中声明Pod,然后将关注点转移到对各个应用类型资源对象的使用上。

Pod Cheat Sheet

Pod是学习和使用Kubernetes的基础,Pod中各个字段的含义及作用是掌握Pod的基础。针对Pod中的字段,可参考如下全景图:
请添加图片描述
需要说明的是,上述Pod字段全景图是基于Kubernetes 1.6版本,在使用的时候要稍微注意下。

参考

《Kubernetes权威指南 从Docker到Kubernetes实践全接触》 龚正 吴治辉 闫健勇 编著
《深入剖析Kubernetes》 张磊 著
https://lib.jimmysong.io/kubernetes-handbook/objects/Pod-overview Pod 概览
https://jimmysong.io/kubernetes-handbook/concepts/pod.html Pod 解析
https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/ Using Finalizers to Control Deletion
https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/common-definitions/object-meta/ 对象元数据
https://www.runoob.com/w3cnote/yaml-intro.html YAML 入门教程
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/ Pod
https://www.cnblogs.com/liugp/p/16366688.html Kubernetes(k8s)pod详解
https://kubernetes.io/zh/docs/tasks/configure-pod-container/quality-service-pod/ 配置 Pod 的服务质量
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/ 配置 Pods 和容器
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#podstatus-v1-core PodStatus v1 core
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ Pod Lifecycle
https://cloud.tencent.com/developer/article/1683483 理解 Kubernetes 的亲和性调度
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/ 为容器的生命周期事件设置处理函数
https://developer.aliyun.com/article/932905 Kubernetes–Pod亲和性调度
https://blog.csdn.net/qq_45631844/article/details/122080509 Kubernetes 亲和性与反亲和性
https://zhuanlan.zhihu.com/p/676245970 K8S学习指南(44)-k8s调度之NodeAffinity

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/665072.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式——2_1 命令(Command)

文章目录 定义图纸一个例子:空调和他的遥控器只有控制面板的空调遥控器可以撤销的操作 碎碎念命令和Runnable命令和事务 定义 把请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持…

Linux文件结构

所有Linux系统的文件结构都是一样的,区别于win系统的c盘,d盘,他只有一个根目录“/”,下面的文件夹结构基本是一样的,如下,文件夹有“箭头”代表的是软链接,即该文件夹的位置不在此,右…

小米平板6获取root权限教程

1. 绑定账号 1> 打开"设置-我的设备-全部参数-连续点击MIUI版本按钮",直到提示已打开开发者模式( p s : 这里需要重点关注红框平板型号和 M I U I 版本,例如我这里平板型号是 X i a o m i P a d 6 , M I U I 版本是 14.0.10 &am…

【开源】JAVA+Vue+SpringBoot实现就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

酷开系统 | 酷开科技智慧AI带你领略神奇的世界

在这个科技日新月异的时代,AI已成为我们生活中不可或缺的一部分。它不仅改变了我们的生活方式,更让我们对未来充满期待。说起酷开系统中智慧AI的强大,着实让人叹为观止。无论是语音识别、数据整理还是语言处理,智慧AI都在不断地突…

MySQL数据库①_MySQL入门(概念+使用)

目录 1. 数据库的概念 1.1 数据库的存储介质 1.2 主流数据库 2. MySQL的基本使用 2.1 链接数据库 2.2 服务器管理 2.3 数据库,服务器和表关系 2.4 简单MySQL语句 3. MySQL架构 4. SQL分类 5. 存储引擎 本篇完。 1. 数据库的概念 数据库是按照数据结构来…

测试大佬是怎么看待测试用例设计的

前言 最近干的最多的事情就是设计测试用例、评审测试用例了,于是我不禁又想到了一个经典的问题:如何设计出优秀的测试用例? 可能有些童鞋看到这个问题会有些不以为然,这有什么好想的?干个测试谁还不会设计测试用例&…

C++(10)——类与对象(最终篇)

目录 static成员 概念 特性 友元 友元函数 友元类 内部类 匿名对象 经过这么多天的分享,C的类与对象终于要结束了。结束也意味着C快要入门了。 static成员 概念 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之…

基于YOLOv8算法的照片角度分类项目实践

目录 一、任务概述二、YOLOv8算法简介2.1 算法改进2.2 算法特点2.3 网络结构2.4 性能比较 三、工程实践3.1 安装算法框架库ultralytics3.2 库存照片预处理3.2.1 提取所有图片3.2.2 去除冗余的相同照片3.2.3 去除无车辆照片3.2.4 随机提取指定数量的图片 3.3 照片朝向分类3.3.1 …

STM32--USART串口(2)串口外设

一、USART简介 可配置数据位:不需要校验就是8位,需要校验就选9位; 停止位:决定了帧的间隔; STM32F103C8T6USART:USART1挂载在APB2总线上,USART2和USART3挂载在APB1总线上; 二、USART框图 TXE…

excel给数据库初始化/旧数据处理(自动sql拼装)

思路: 首先导出数据到excel编写单条数据操作的sql利用excel CONCATENATE 函数自动生成,每一行数据的操作sql 小技巧:对于需要套娃的字段值,可以加一个临时列同样使用CONCATENATE函数进行sql拼装 案例: 1.临时列:CONCATENATE(C2, …

分库分表 21 条法则,hold 住!

大家好~今天给大家分享分库分表的 21 条法则 我们结合具体业务场景,以t_order表为例进行架构优化。由于数据量已经达到亿级别,查询性能严重下降,因此我们采用了分库分表技术来处理这个问题。具体而言,我们将原本的单库…

【Python小游戏】五子棋小游戏(完整代码)

文章目录 写在前面Tkinter简介五子棋小游戏游戏介绍程序设计运行结果注意事项写在后面写在前面 本期内容:基于tkinter开发一个五子棋小游戏 实验环境 python3.11及以上pycharmtkinterTkinter简介 Tkinter是Python中最常用的图形用户界面(GUI)库之一,用于创建窗口、对话框…

如何搭建私有云盘SeaFile并实现远程访问本地文件资料

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-hsDnDEybLME85dTx {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Web项目利用OSS进行图像存储服务

一、OSS介绍 在Web项目中,一些常见的功能,比如展示图片,修改头像等,都需要进行图片的上传操作,但是如果是存储在Web服务器中,在读取图片的时候会占用比较多的资源,影响服务器的性能。 常…

【数据结构】双向带头循环链表实现及总结

简单不先于复杂&#xff0c;而是在复杂之后。 文章目录 1. 双向带头循环链表的实现2. 顺序表和链表的区别 1. 双向带头循环链表的实现 List.h #pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h>typede…

fastDFS客户端实现文件上传

一、准备工作 请确保fastDFS的tracker服务和storage服务都是处于启动状态&#xff0c;防火墙是关闭的&#xff1b; 二、具体步骤 1、pom.xml 2、让当前的微服务成为fdfs的客户端 package com.qf.config;import com.github.tobato.fastdfs.FdfsClientConfig; import org.sprin…

JMeter HTTP请求的详细指南,还不知道的快来看

HTTP请求简介 在JMeter中&#xff0c;服务器名称和它的路径对于检查请求是否到达了正确的目的地非常重要。默认情况下&#xff0c;HTTP协议与请求一起被遵循&#xff0c;如果需要&#xff0c;可以转换为HTTPS。如果需要&#xff0c;用户参数可以包含在特定页面的请求中。如果&a…

MySQL查询缓存

MySQL查询缓存 MySQL在查询的时候首先会查询缓存&#xff0c;如果缓存命中的话就直接返回结果&#xff0c;不需要解析sql语句&#xff0c;也不会生成执行计划&#xff0c;更不会执行&#xff1b;如果没有命中缓存&#xff0c;则再进行SQL解析以及进行查询&#xff0c;并将结果返…

机器学习系列-2 线性回归训练损失

机器学习系列-2 线性回归&训练损失 学习内容来自&#xff1a;谷歌ai学习 https://developers.google.cn/machine-learning/crash-course/framing/check-your-understanding?hlzh-cn 本文作为学习记录1 线性回归&#xff1a; 举例&#xff1a;蝉&#xff08;昆虫物种&…