• k8s 集群调度,标签,亲和性和反亲和性,污点和容忍,pod启动状态 排错详解


    目录

    pod启动创建过程

    kubelet持续监听的原因

    调度概念

    调度约束

    调度过程

    优点

    原理

    优先级选项

    示例

    指定调度节点

    标签基本操作

    获取标签帮助

    添加标签(Add Labels):

    更新标签(Update Labels)

    删除标签(Remove Labels)

    查询标签(Query Labels)

    使用标签选择器(Label Selectors)

    标签匹配的运算符

    亲和性

    节点亲和性:

    Pod 亲和性:

    硬策略和软策略

    硬策略示例

    软策略示例

    软硬策略结合示例

    pod亲和和反亲和

    调度策略

    Pod 亲和性调度策略的详细说明

    示例

    创建一个标签为 app=myapp01 的 Pod

    使用 Pod 亲和性调度,创建多个 Pod 资源

    使用 Pod 反亲和性调度

    污点(Taint) 和 容忍(Tolerations)

    概念

    格式和支持的效果(选项)

    污点的基本操作

    添加污点:

    查看污点:

    删除污点:

    示例

    容忍

    举例说明

    值得注意的操作

    维护节点和应用程序操作

    pod启动阶段的状态解读与排错技巧

    Pod启动阶段(相位 phase)

    pod可能的状态

    故障排除步骤


     

    pod启动创建过程

    这里有三个 List-Watch,分别是 Controller Manager(运行在 Master),Scheduler(运行在 Master),kubelet(运行在 Node)。 他们在进程已启动就会监听(Watch)APIServer 发出来的事件。

    • 用户通过 kubectl 或其他 API 客户端提交创建 Pod 的请求给 APIServer

    • APIServer 将 Pod 对象的元数据尝试存入 etcd 中,待写入操作执行完成,APIServer返回确认信息给客户端。

    • etcd 接受创建 Pod 的信息后,在集群中保存该信息,并触发 Create 事件给APIserver。

    • Controller Manager 监听到 Create 事件后,调用 Replication Controller 来确保 Node 上的副本数量符合定义。一旦副本数量少于 RC 中定义的数量,RC 会自动创建副本。总之它是保证副本数量的 Controller(PS:扩容缩容的担当)。

    • Replication Controller 创建 Pod 的副本。

    • APIServer 更新 etcd 中的 Pod 信息,并向 Controller Manager 发送更新事件。

    • Scheduler 监听到更新事件后,根据调度算法将 Pod 绑定到合适的 Node 上。

    • Scheduler 更新 Pod 的信息,包括它所部署的 Node,然后将信息反馈给 APIServer。

    • APIServer 更新 etcd 中的 Pod 信息,并将更新成功的事件发送给 Scheduler。

    • kubelet 在 Node 上监听 APIServer 发送的 Pod 更新事件,根据更新信息调用 Docker 启动容器。

    • kubelet 将 Pod 的状态信息反馈给 APIServer,并更新至 etcd。

    • APIServer 将 Pod 的状态信息持久化存储在 etcd 中,APIServer将确认信息发送至相关的 kubelet,事件将通过它被接受,完成整个启动创建过程。

    kubelet持续监听的原因

    kubelet持续监听的原因在于保持对集群中 Pod 状态的实时感知和响应。即使创建过程完成,kubelet仍然需要:

    • 实时调整资源: 如果通过 kubectl 进行扩容或缩容操作,kubelet会感知这些变化,根据最新的 Pod 副本数量,调整 Node 上的资源。

    • 镜像更新: 如果 Pod 的镜像文件升级,kubelet会自动获取最新的镜像文件并加载,确保 Pod 使用的是最新的容器镜像。

    通过持续监听,kubelet能够及时响应各种变化,确保集群中的 Pod 始终处于最新、正确的状态。这种实时性是 Kubernetes 系统的关键特性之一。

    调度概念

    Kubernetes集群调度是指Kubernetes系统中的调度器(scheduler)负责将应用程序的工作负载(如Pod)分配到可用的集群节点上。调度器通过考虑诸如节点资源利用率、硬件约束、亲和性和反亲和性规则等因素,选择最佳的节点来放置Pod,以实现高效的资源利用和负载均衡。调度器的工作包括评估节点的可用资源、满足Pod的资源需求、遵循用户定义的调度策略等。

    • Kubernetes 是通过 List-Watch 机制进行每个组件的协作,保持数据同步的,每个组件之间的设计实现了解耦。

    • 用户是通过 kubectl 根据配置文件,向 APIServer 发送命令,在 Node 节点上面建立 Pod 和 Container。

    • APIServer 经过 API 调用,权限控制,调用资源和存储资源的过程,实际上还没有真正开始部署应用。这里 需要 Controller Manager、Scheduler 和 kubelet 的协助才能完成整个部署过程。

    • 在 Kubernetes 中,所有部署的信息都会写到 etcd 中保存。实际上 etcd 在存储部署信息的时候,会发送 Create 事件给 APIServer,而 APIServer 会通过监听(Watch)etcd 发过来的事件。其他组件也会监听(Watch)APIServer 发出来的事件。

    调度约束

    Kubernetes中的调度约束,这些约束是指在将Pod调度到节点上时需要考虑的各种条件和限制。这些约束包括但不限于:

    • 资源约束: 每个节点有一定的资源限制,如CPU和内存。调度器会考虑Pod的资源请求和节点的可用资源,确保Pod能够得到满足并不会超出节点的资源容量。

    • 亲和性和反亲和性: 可以指定Pod之间或Pod与节点之间的亲和性和反亲和性规则,以确保它们被调度到合适的节点上。例如,可以将Pod调度到与特定标签匹配的节点上,或者避免将它们调度到某些节点上。

    • 节点亲和性: 通过节点亲和性规则,可以指定Pod应该调度到与某些节点属性匹配的节点上。例如,将Pod调度到具有特定硬件特性或数据存储的节点上。

    • Pod 亲和性: 通过Pod亲和性规则,可以确保一组Pod被调度到同一节点上,或者避免它们被调度到同一节点上。

    • 污点和容忍: 污点用于标记节点上的不可接受条件,而容忍则允许一些Pod调度到带有污点的节点上。这有助于将特定类型的工作负载调度到适合的节点上。

    这些约束通过Kubernetes的调度器实现,调度器会根据这些约束选择最佳的节点来放置Pod,以满足用户需求并确保集群的高效利用。

    调度过程

    Kubernetes(k8s)调度涉及调度器、控制器管理器和kubelet。当使用kubectl创建作业时,kube-controller检测到它,创建一个Pod实例,并将其发送到API服务器。kube-scheduler在检测到未调度的Pod时,选择一个节点,将Pod绑定到它,并向API服务器发送绑定指令。相应节点上的kubelet在检测到绑定指令后,指示节点的容器API运行Pod。这个过程确保了Kubernetes集群中资源的有效分配和工作负载的分发。

    优点

    Scheduler是Kubernetes的调度器,其主要任务是将定义的Pod分配到集群的节点上。

    • 公平:确保每个节点都能获得公平的资源分配,避免资源不均衡。

    • 资源高效利用:最大化集群中所有资源的利用率,确保资源被充分利用而不浪费。

    • 效率:调度器需要具备良好的性能,能够快速而有效地对大批量的Pod完成调度工作,以满足用户的需求。

    • 灵活:允许用户根据自己的需求控制调度的逻辑,例如通过标签、调度策略等方式定制调度规则,以适应不同的应用场景和需求。

    原理

    调度器作为一个独立的程序运行,并监听 API Server,负责将未指定节点的 Pod 分配到合适的节点上。整个调度过程分为预算策略(predicate)和优选策略(priorities)两个阶段,分别用于先过滤不满足条件的节点和对通过的节点进行排序。最后,从中选择优先级最高的节点进行调度。如果在任何一个阶段出现错误,调度器会立即返回错误信息。

    如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。 经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:按照优先级大小对节点排序。

    优先级选项

    Kubernetes Pod 调度过程中使用的一系列优先级选项及其作用:

    • LeastRequestedPriority(最低资源请求优先级):根据节点的 CPU 和内存使用率来确定权重,使用率越低的节点权重越高。这意味着优先选择资源利用率较低的节点来部署 Pod。

    • BalancedResourceAllocation(平衡资源分配优先级):根据节点上 CPU 和内存使用率的平衡程度来确定权重。如果节点上的 CPU 和内存使用率越接近,权重越高。通常与最低资源请求优先级一起使用,以便在选择节点时考虑资源的平衡分配。

    • ImageLocalityPriority(镜像本地性优先级):倾向于选择已经存在所需镜像的节点部署 Pod。权重根据镜像的总大小来确定,镜像总大小越大,权重越高。

    示例

    举例来说,假设有三个 Kubernetes 节点:node01、node02 和 node03。现在有一个 Pod 需要调度到其中一个节点上。

    • LeastRequestedPriority(最低资源请求优先级):如果 node01 的 CPU 和内存使用率较低,node02 的使用率中等,而 node03 的使用率较高,那么优先选择调度到 node01,因为它的资源使用率最低。

    • BalancedResourceAllocation(平衡资源分配优先级):假设 node01 的 CPU 使用率为20%,内存使用率为60%,而 node02 的 CPU 和内存使用率均为50%,则根据平衡资源分配优先级,可能更倾向于选择 node02,因为它的资源使用情况更平衡。

    • ImageLocalityPriority(镜像本地性优先级):如果 node01 已经存在 Pod 所需的镜像,而 node02 和 node03 没有,那么优先选择调度到 node01,因为它具有镜像的本地性。

    指定调度节点

    pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配

    1. vim myapp.yaml
    2. apiVersion: apps/v1
    3. kind: Deployment
    4. metadata:
    5. name: myapp
    6. spec:
    7. replicas: 3
    8. selector:
    9. matchLabels:
    10. app: myapp
    11. template:
    12. metadata:
    13. labels:
    14. app: myapp
    15. spec:
    16. nodeName: node01
    17. containers:
    18. - name: myapp
    19. image: soscscs/myapp:v1
    20. ports:
    21. - containerPort: 80
    22. kubectl apply -f myapp.yaml
    23. kubectl get pods -o wide
    • apiVersion: apps/v1: 指定了使用的 Kubernetes API 版本。

    • kind: Deployment: 定义了这个配置文件描述的 Kubernetes 资源类型,即部署。

    • metadata: 包含有关资源的元数据,比如名称。

    • name: myapp: 指定部署的名称为 "myapp"。

    • spec: 定义了部署的规格,包括副本数量、选择器和模板。

    • replicas: 3: 指定了要创建的 Pod 的副本数量为 3。

    • selector: 定义了用于选择要管理的 Pod 的标签。

      • matchLabels: 指定了匹配标签的条件。

      • app: myapp: 指定了标签 app 的值为 myapp

    • template: 定义了要创建的 Pod 的模板。

      • metadata: 包含了 Pod 模板的元数据,包括标签。

      • labels: 指定了 Pod 模板的标签。

        • app: myapp: 指定了标签 app 的值为 myapp
      • spec: 指定了 Pod 的规格。

      • nodeName: node01: 使用 nodeName 字段将 Pod 直接调度到名为 node01 的节点上。

      • containers: 指定了要在 Pod 中运行的容器列表。

        • name: myapp: 定义了容器的名称为 myapp

        • image: soscscs/myapp:v1: 指定了要在容器中运行的镜像。

        • ports: 指定了容器要监听的端口。

        • containerPort: 80: 指定了容器监听的端口号为 80。

    通过应用此配置文件,成功地创建了一个名为 myapp 的 Deployment,其中包含了三个 Pod,每个 Pod 都直接调度到了名为 node01 的节点上,并且每个 Pod 内运行一个名为 myapp 的容器,该容器使用 soscscs/myapp:v1 镜像并监听端口 80。

    kubectl describe pod myapp-
    

    查看详细事件,发现未经过 scheduler 调度分配

    这些事件显示了 Pod 的创建过程,但没有显示与调度相关的事件,这是因为在 Pod 的配置中明确指定了 nodeName: node01,这意味着 Pod 将直接调度到名为 node01 的节点上,而不经过调度器的调度分配过程。

    因此,在描述中看不到与调度相关的事件,而只能看到与 Pod 创建、拉取镜像、容器创建和启动等过程相关的事件。

    pod.spec.nodeSelector:通过 kubernetes 的 label-selector 机制选择节点,由调度器调度策略匹配 label,然后调度 Pod 到目标节点,该匹配规则属于强制约束

    标签基本操作

    获取标签帮助

    kubectl label --help
    

    添加标签(Add Labels):

    添加标签是为资源附加额外的元数据,以便更容易地对其进行标识和分类。例如,为名为nginx的Pod添加标签app=web

    1. kubectl label <资源类型> <资源名称> <标签键>=<标签值>
    2. kubectl label pods nginx app=web
    • 这将给名为nginx的Pod添加了一个名为app,值为web的标签。

    • 添加标签是为资源附加额外的元数据,以便更容易地对其进行标识和分类。例如,为名为nginx的Pod添加标签app=web

    更新标签(Update Labels)

    更新标签是对已存在的标签进行更改。例如,将名为nginx的Pod的app标签的值从web更改为frontend

    1. kubectl label <资源类型> <资源名称> <标签键>=<新标签值> --overwrite
    2. kubectl label pods nginx app=frontend --overwrite
    • 使用--overwrite标志来确保标签的值被覆盖。

    删除标签(Remove Labels)

    删除标签是从资源中删除指定的标签。例如,从名为nginx的Pod中删除app标签:

    1. kubectl label <资源类型> <资源名称> <标签键>-
    2. kubectl label pods nginx app-
    • 删除一个 label,只需在命令行最后指定 label 的 key 名并与一个减号相连即可

    • 这将从Pod中删除名为app的标签。

    查询标签(Query Labels)

    查询标签是查找具有特定标签的资源。例如,查找具有app=web标签的所有Pod:

    1. kubectl get <资源类型> -l <标签选择器>
    2. kubectl get pods -l app=web

    这将返回所有具有app=web标签的Pod列表。

    使用标签选择器(Label Selectors)

    1. spec:
    2. selector:
    3. <标签键>: <标签值>

    在定义资源时使用标签选择器,以便在对资源进行操作时能够指定匹配的标签。例如,定义一个Service并选择具有特定标签的Pod:

    1. apiVersion: v1
    2. kind: Service
    3. metadata:
    4. name: nginx-service
    5. spec:
    6. selector:
    7. app: web
    8. ports:
    9. - protocol: TCP
    10. port: 80
    11. targetPort: 80

    在这个例子中,Service选择了具有app=web标签的Pod作为其后端。

    标签匹配的运算符

    • In:表示 label 的值必须在指定的列表中。

    • 例如:key: "app", operator: In, values: ["web", "db"] 表示 "app" 的值必须是 "web" 或 "db"。

    • NotIn:表示 label 的值不能在指定的列表中。

    • 例如:key: "env", operator: NotIn, values: ["dev", "test"] 表示 "env" 的值不能是 "dev" 或 "test"。

    • Gt:表示 label 的值必须大于指定的值。

    • 例如:key: "replica", operator: Gt, values: ["3"] 表示 "replica" 的值必须大于 3。

    • Lt:表示 label 的值必须小于指定的值。

    • 例如:key: "version", operator: Lt, values: ["2.0"] 表示 "version" 的值必须小于 2.0。

    • Exists:表示某个 label 必须存在。

    • 例如:key: "app", operator: Exists 表示 "app" 必须存在。

    • DoesNotExist:表示某个 label 不能存在。

    • 例如:key: "deprecated", operator: DoesNotExist 表示 "deprecated" 不能存在。

    • 这些运算关系在定义亲和性规则时用于匹配标签的条件

    亲和性

    官方:将 Pod 指派给节点 | Kubernetes

    在 Kubernetes 中,"亲和性"(Affinity)是一种机制,用于控制 Pod 如何被调度到节点上。亲和性规则允许你指定 Pod 与特定节点或其他 Pod 之间的偏好关系。通过使用亲和性,可以确保相关的 Pod 在同一节点上运行,或者避免将它们调度到同一节点上,以提高性能、可用性或安全性。

    亲和性在 Kubernetes 中有两种类型:节点亲和性和 Pod 亲和性。节点亲和性定义了 Pod 与节点之间的关系,而 Pod 亲和性定义了 Pod 与其他 Pod 之间的关系。

    节点亲和性

    • 通过 nodeAffinity 字段指定,可以使用 nodeSelector 或 nodeSelectorTerms 定义节点上的标签和条件,以确保 Pod 被调度到满足这些条件的节点上。

    • pod.spec.nodeAffinity 中的 preferredDuringSchedulingIgnoredDuringExecution 是软策略,表示首选但不是强制要求。系统会尽量遵循这些偏好,但在无法满足时也可以进行调度。

    • pod.spec.nodeAffinity 中的 requiredDuringSchedulingIgnoredDuringExecution 是硬策略,表示 Pod 必须满足这些条件才能被调度。如果无法满足条件,Pod 将不会被调度。

    Pod 亲和性

    • 通过 affinity 字段中的 podAffinity 和 podAntiAffinity 字段定义。podAffinity 用于描述 Pod 与其他 Pod 的关系,而 podAntiAffinity 用于定义 Pod 与其他 Pod 的排斥关系。可以使用 labelSelector 和 topologyKey 来定义匹配规则。

    • pod.spec.affinity.podAffinitypod.spec.affinity.podAntiAffinity 中的 preferredDuringSchedulingIgnoredDuringExecution 是软策略,表示首选但不是强制要求。系统会尽量遵循这些偏好,但在无法满足时也可以进行调度。

    • pod.spec.affinity.podAffinitypod.spec.affinity.podAntiAffinity 中的 requiredDuringSchedulingIgnoredDuringExecution 是硬策略,表示 Pod 必须满足这些条件才能被调度。如果无法满足条件,Pod 将不会被调度。

    硬策略和软策略

    在 Kubernetes 中,硬策略和软策略通常用于定义 Pod 的亲和性或节点的亲和性。这些策略决定了 Kubernetes 调度器在安排 Pod 时的行为。

    • 硬策略(requiredDuringSchedulingIgnoredDuringExecution)

    • 当使用硬策略时,调度器必须严格遵守亲和性规则。这意味着 Pod 必须满足定义的亲和性条件才能被调度到节点上。如果无法满足条件,Pod 将会一直处于 Pending 状态,直到满足条件为止。即使在运行时,如果条件不再满足,Pod 也不会被迁移到其他节点。

    • 软策略(preferredDuringSchedulingIgnoredDuringExecution)

    • 当使用软策略时,调度器会尽量遵守定义的亲和性规则,但不是必须的。如果有多个节点符合软策略的条件,调度器会倾向于选择满足条件的节点,但如果无法满足条件,调度器仍然可以将 Pod 调度到其他节点上。如果在运行时条件不再满足,Pod 也不会被迁移到其他节点。

    这两种策略提供了灵活性和可靠性之间的权衡。硬策略确保 Pod 被调度到满足条件的节点上,但可能会导致更多的 Pod 无法调度。软策略提供了更灵活的调度,但可能会导致一些 Pod 被调度到不太理想的节点上。在设计亲和性规则时,需要根据具体情况选择适当的策略来平衡资源利用率和可用性要求

    硬策略示例

    1. # 创建目录
    2. mkdir /opt/affinity
    3. # 切换目录
    4. cd /opt/affinity
    5. # 编辑 Pod 配置文件
    6. vim pod1.yaml
    7. apiVersion: v1
    8. kind: Pod
    9. metadata:
    10. name: affinity
    11. labels:
    12. app: node-affinity-pod
    13. spec:
    14. containers:
    15. - name: with-node-affinity
    16. image: soscscs/myapp:v1
    17. # 定义节点亲和性
    18. affinity:
    19. nodeAffinity:
    20. requiredDuringSchedulingIgnoredDuringExecution:
    21. nodeSelectorTerms:
    22. - matchExpressions:
    23. - key: kubernetes.io/hostname # 指定node的标签
    24. operator: NotIn # 设置Pod安装到kubernetes.io/hostname的标签值不在values列表中的node上
    25. values:
    26. - node02
    27. # 应用 Pod 配置
    28. kubectl apply -f pod1.yaml
    29. # 获取 Pod 列表
    30. kubectl get pods -o wide
    31. # 删除所有 Pod,重新应用配置,并查看 Pod 列表
    32. kubectl delete pod --all && kubectl apply -f pod1.yaml && kubectl get pods -o wide
    33. # 如果硬策略不满足条件,Pod 状态一直会处于 Pending 状态。

    这个示例中,创建了一个名为 affinity 的 Pod,并且定义了节点亲和性规则,使用了硬策略 requiredDuringSchedulingIgnoredDuringExecution。逐步解析这个示例:

    • metadata 部分指定了 Pod 的元数据,包括名称和标签。

    • spec 部分定义了 Pod 的规格,其中包含了容器的相关信息。

    • affinity 字段下,定义了节点亲和性规则。这里使用了 nodeAffinity,表示节点亲和性。

    • requiredDuringSchedulingIgnoredDuringExecution 中,指定了节点选择器条件。matchExpressions 用于指定匹配条件,key 指定了要匹配的标签键,这里是 kubernetes.io/hostname,即节点的主机名。operator 设置为 NotIn,表示标签值不在指定的列表中。而 values 则列出了不允许的节点主机名,这里只有一个节点 node02

    • 最后,应用了这个 Pod 的配置文件,并通过 kubectl get pods -o wide 命令来查看 Pod 的状态和所在的节点。由于节点亲和性规则指定了 Pod 不能运行在 node02 上,所以 Pod 被成功调度到了 node01 上,状态为 Running

    • 最后的删除并重新创建操作是为了再次验证规则,确保当条件不满足时,Pod 状态会一直保持在 Pending

    这个示例清晰地展示了硬策略的行为:当指定的条件无法满足时,Pod 将无法被调度,并且状态会一直保持在 Pending

    软策略示例

    1. # 编辑 Pod2 配置文件
    2. vim pod2.yaml
    3. apiVersion: v1
    4. kind: Pod
    5. metadata:
    6. name: affinity
    7. labels:
    8. app: node-affinity-pod
    9. spec:
    10. containers:
    11. - name: with-node-affinity
    12. image: soscscs/myapp:v1
    13. # 定义节点亲和性,优先使用软策略
    14. affinity:
    15. nodeAffinity:
    16. preferredDuringSchedulingIgnoredDuringExecution:
    17. - weight: 1 # 如果有多个软策略选项的话,权重越大,优先级越高
    18. preference:
    19. matchExpressions:
    20. - key: kubernetes.io/hostname
    21. operator: In
    22. values:
    23. - node03
    24. # 应用 Pod2 配置
    25. kubectl apply -f pod2.yaml
    26. # 获取 Pod 列表
    27. kubectl get pods -o wide

    这个YAML文件描述了一个Pod对象,其中包含一个名为affinity的Pod。

    • apiVersion: 指定了Kubernetes API的版本,这里使用的是v1版本。

    • kind: 定义了Kubernetes对象的类型,这里是一个Pod对象。

    • metadata: 包含了有关该Pod的元数据,包括名称(name)和标签(labels)。

    • name: 指定了Pod的名称为affinity

    • labels: 为Pod添加了一个标签,标签的键为app,值为node-affinity-pod

    • spec: 包含了Pod的规格,即容器和其他配置信息。

    • containers: 定义了Pod中的容器列表。

      • name: 指定了容器的名称为with-node-affinity

      • image: 指定了容器所使用的镜像为soscscs/myapp:v1

    • affinity: 定义了Pod的亲和性规则。

      • nodeAffinity: 定义了节点亲和性规则。

      • preferredDuringSchedulingIgnoredDuringExecution: 指定了软节点亲和性规则,即在调度时优先考虑,但在执行时忽略。

        • weight: 指定了该规则的权重为1,权重越大,优先级越高。

        • preference: 指定了偏好项,即优先调度到具有特定主机名的节点。

        • matchExpressions: 定义了匹配表达式。

          • key: 指定了匹配的键为kubernetes.io/hostname,即主机名。

          • operator: 指定了匹配操作符为In,表示匹配主机名列表中的任何一个值。

          • values: 指定了匹配的主机名列表,这里只有一个值node03

    总结:该Pod对象具有一个软节点亲和性规则,表示优先调度到具有主机名为node03的节点。权重为1,这意味着在具有多个软策略选项的情况下,优先级较高。然而,根据输出结果,该Pod最终被调度到了节点node02上,这是由于node02满足了调度要求并且优先级高于node03

    软硬策略结合示例

    如果把硬策略和软策略合在一起使用,则要先满足硬策略之后才会满足软策略

    1. # 定义 Pod 配置
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: affinity
    6. labels:
    7. app: node-affinity-pod
    8. spec:
    9. containers:
    10. - name: with-node-affinity
    11. image: soscscs/myapp:v1
    12. # 定义节点亲和性
    13. affinity:
    14. nodeAffinity:
    15. # 先满足硬策略,排除有 kubernetes.io/hostname=node02 标签的节点
    16. requiredDuringSchedulingIgnoredDuringExecution:
    17. nodeSelectorTerms:
    18. - matchExpressions:
    19. - key: kubernetes.io/hostname
    20. operator: NotIn
    21. values:
    22. - node02
    23. # 再满足软策略,优先选择有 aaa=a 标签的节点
    24. preferredDuringSchedulingIgnoredDuringExecution:
    25. - weight: 1
    26. preference:
    27. matchExpressions:
    28. - key: aaa
    29. operator: In
    30. values:
    31. - a

    这个示例中,定义了一个Pod对象,其中包含了硬节点亲和性规则和软节点亲和性规则。让我们分析一下:

    • requiredDuringSchedulingIgnoredDuringExecution:这是一个硬节点亲和性规则,表示在调度时必须满足的条件。在这个规则中,指定了排除具有主机名为node02的节点,即必须在不包括node02的节点上调度该Pod。

    • preferredDuringSchedulingIgnoredDuringExecution:这是一个软节点亲和性规则,表示在调度时优先考虑的条件,但在执行时会被忽略。在这个规则中,指定了优先选择具有标签aaa=a的节点,即希望将该Pod调度到具有aaa=a标签的节点上。

    根据这两个规则的组合,首先,调度器会先满足硬节点亲和性规则,即排除node02节点。然后,在满足了硬性要求的节点中,调度器会优先考虑软节点亲和性规则,即选择具有aaa=a标签的节点。这样,最终的调度结果将是在不包括node02节点的节点中,优先选择具有aaa=a标签的节点。

    pod亲和和反亲和

    • 在Kubernetes(k8s)中,Pod亲和性和反亲和性用于指定Pod与节点的关系。亲和性定义了Pod如何倾向于在同一节点上调度,而反亲和性则定义了Pod如何避免与特定节点调度在一起。

    • 通过使用nodeSelector字段,你可以在PodSpec中指定节点标签,使Pod倾向于调度到具有特定标签的节点上,这就是亲和性的一种实现方式。相反,反亲和性可以通过tolerations字段实现,该字段定义了Pod可以容忍的节点上的污点,从而避免在这些节点上被调度。

    • 这样的机制有助于优化Pod的调度,使其更好地适应节点资源和约束条件。

    调度策略

    当使用 Kubernetes 进行 Pod 调度时,可以使用三种不同的调度策略来控制 Pod 的部署位置,分别是 nodeAffinity(节点亲和性)、podAffinity(Pod 亲和性)和 podAntiAffinity(Pod 反亲和性)。

    • 节点亲和性(nodeAffinity)

    • 匹配标签:对节点的标签进行匹配。

    • 操作符:支持的操作符包括 InNotInExistsDoesNotExistGt(大于)和 Lt(小于)等。

    • 拓扑域支持:不支持拓扑域,只考虑节点的标签。

    • 调度目标:指定 Pod 应该调度到具有特定标签的节点上。

    • Pod 亲和性(podAffinity)

    • 匹配标签:对其他 Pod 的标签进行匹配。

    • 操作符:与节点亲和性相同,支持的操作符包括 InNotInExistsDoesNotExist 等。

    • 拓扑域支持:支持拓扑域,可以指定 Pod 应该与其他 Pod 在同一拓扑域(比如同一节点)还是不同拓扑域。

    • 调度目标:指定 Pod 应该与其他具有特定标签的 Pod 部署在同一拓扑域。

    • Pod 反亲和性(podAntiAffinity)

    • 匹配标签:同样对其他 Pod 的标签进行匹配。

    • 操作符:与节点亲和性和 Pod 亲和性相同。

    • 拓扑域支持:同样支持拓扑域,可以指定 Pod 应该与其他 Pod 在同一拓扑域还是不同拓扑域。

    • 调度目标:指定 Pod 应该与其他具有特定标签的 Pod 部署在不同的拓扑域,即不在同一节点或同一拓扑域。

    这些调度策略可以帮助用户更灵活地控制 Pod 的部署,根据业务需求和系统架构,优化资源利用和提高容错能力。

    Pod 亲和性调度策略的详细说明

    • 调度条件

    • 仅当节点和至少一个已运行且具有标签键为“app”且值为“myapp01”的 Pod 处于同一拓扑域时,才可以将该 Pod 调度到节点上。

    • 具体来说,如果节点 N 具有带有键为 lab 和某个值 V 的标签,则 Pod 有资格在节点 N 上运行,以便集群中至少有一个具有键为 lab和值为 V 的节点正在运行具有键“app”和值“myapp01”的 Pod。

    • topologyKey

    • topologyKey 是节点标签的键。如果两个节点使用此键标记并且具有相同的标签值,则调度器会将这两个节点视为处于同一拓扑域中。

    • 调度器试图在每个拓扑域中放置数量均衡的 Pod。

    • 拓扑域的定义

    • 如果 lab对应的值不一样就是不同的拓扑域。比如 Pod1 在 lab=a 的 Node 上,Pod2 在 lab=b 的 Node 上,Pod3 在 lab=a 的 Node 上,则 Pod2 和 Pod1、Pod3 不在同一个拓扑域,而 Pod1 和 Pod3 在同一个拓扑域。

    示例

    1. kubectl label node node01 lab=a
    2. kubectl label node node02 lab=b

    这两个命令的目的是给节点 node01node02 分别打上标签 lab=alab=b

    创建一个标签为 app=myapp01 的 Pod

    1. vim pod3.yaml
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: myapp01 # 设置 Pod 的名称为 myapp01
    6. labels:
    7. app: myapp01 # 给 Pod 添加标签 app: myapp01
    8. spec:
    9. containers:
    10. - name: with-node-affinity # 定义容器名称为 with-node-affinity
    11. image: soscscs/myapp:v1 # 使用镜像 soscscs/myapp:v1
    12. kubectl apply -f pod3.yaml
    13. kubectl get pods --show-labels -o wide

    这段代码创建了一个名为 myapp01 的 Pod,并为其打上了标签 app=myapp01。下面是对代码的说明:

    • vim pod3.yaml:创建了一个名为 pod3.yaml 的文件,并编辑该文件以定义 Pod 对象的配置。

    • metadata 部分指定了 Pod 的名称和标签。

    • spec 部分定义了 Pod 的规格,其中包含一个容器,使用镜像 soscscs/myapp:v1

    • kubectl apply -f pod3.yaml:使用 Pod 配置文件 pod3.yaml 创建 Pod 对象。

    • kubectl get pods --show-labels -o wide:显示所有 Pod 的信息,包括标签,以宽格式输出。可以看到 myapp01 Pod 已经成功创建,并且具有标签 app=myapp01,并且运行在 node01 节点上。

    这样就成功创建了一个名为 myapp01 的 Pod,并为其打上了指定的标签。

    使用 Pod 亲和性调度,创建多个 Pod 资源

    1. vim pod4.yaml
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: myapp02 # 设置 Pod 的名称为 myapp02
    6. labels:
    7. app: myapp02 # 给 Pod 添加标签 app: myapp02
    8. spec:
    9. containers:
    10. - name: myapp02 # 定义容器名称为 myapp02
    11. image: soscscs/myapp:v1 # 使用镜像 soscscs/myapp:v1
    12. affinity: # 定义亲和性
    13. podAffinity: # Pod 亲和性规则
    14. requiredDuringSchedulingIgnoredDuringExecution: # 在调度期间要求的 Pod 亲和性规则,在执行期间被忽略
    15. - labelSelector: # 标签选择器
    16. matchExpressions: # 匹配表达式列表
    17. - key: app # 标签键为 app
    18. operator: In # 使用 In 操作符
    19. values: # 值列表
    20. - myapp01 # 匹配值为 myapp01
    21. topologyKey: lab # 拓扑域键为 lab
    22. kubectl apply -f pod4.yaml
    23. kubectl get pods --show-labels -o wide

    这段代码创建了一个名为 myapp02 的 Pod,并使用了 Pod 亲和性调度策略,以确保它与具有特定标签的其他 Pod 在同一拓扑域上。下面是对代码的说明:

    • vim pod4.yaml:创建了一个名为 pod4.yaml 的文件,并编辑该文件以定义 Pod 对象的配置。

    • metadata 部分指定了 Pod 的名称和标签。

    • spec 部分定义了 Pod 的规格,其中包含一个容器,使用镜像 soscscs/myapp:v1

    • affinity 部分定义了 Pod 的亲和性策略,这里使用了 podAffinity 策略。

      • requiredDuringSchedulingIgnoredDuringExecution 指定了 Pod 调度时必须满足的条件。

      • labelSelector 指定了匹配其他 Pod 标签的条件,这里要求匹配的标签为 app=myapp01

      • topologyKey 指定了用于确定拓扑域的键,这里设置为 lab

    • 这段代码将确保创建的 myapp02 Pod 与具有标签 app=myapp01 的其他 Pod 在同一拓扑域上调度。

    使用 Pod 反亲和性调度

    1. vim pod5.yaml
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: myapp10 # Pod 的名称
    6. labels:
    7. app: myapp10 # Pod 的标签
    8. spec:
    9. containers:
    10. - name: myapp10 # 容器的名称
    11. image: soscscs/myapp:v1 # 容器所使用的镜像
    12. affinity:
    13. podAntiAffinity: # 反亲和性调度规则
    14. preferredDuringSchedulingIgnoredDuringExecution: # 在调度时优先考虑的规则,执行时忽略
    15. - weight: 100 # 权重
    16. podAffinityTerm: # 匹配的 Pod 亲和性条件
    17. labelSelector: # 标签选择器
    18. matchExpressions: # 匹配的表达式
    19. - key: app # 匹配的键
    20. operator: In # 匹配操作符
    21. values: # 匹配的值
    22. - myapp01 # 与该 Pod 亲和的标签值
    23. topologyKey: kubernetes.io/hostname # 拓扑域键
    24. kubectl apply -f pod5.yaml
    25. kubectl get pods --show-labels -o wide
    • 这个示例展示了如何在 Pod 中使用反亲和性调度。在这个例子中,Pod myapp10 的调度规则指定了反亲和性,即希望它不要与具有特定标签的其他 Pod 调度到同一个节点上。
    1. vim pod6.yaml
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: myapp20 # Pod 的名称
    6. labels:
    7. app: myapp20 # Pod 的标签
    8. spec:
    9. containers:
    10. - name: myapp20 # 容器的名称
    11. image: soscscs/myapp:v1 # 容器所使用的镜像
    12. affinity:
    13. podAntiAffinity: # 反亲和性调度规则
    14. requiredDuringSchedulingIgnoredDuringExecution: # 在调度时必须满足的规则,执行时忽略
    15. - labelSelector: # 标签选择器
    16. matchExpressions: # 匹配的表达式
    17. - key: app # 匹配的键
    18. operator: In # 匹配操作符
    19. values: # 匹配的值
    20. - myapp01 # 与该 Pod 亲和的标签值
    21. topologyKey: lab # 拓扑域键
    • 这样配置的 Pod 在调度时将会确保不与具有标签 app: myapp01 的其他 Pod 调度到同一个拓扑域上

    由于指定 Pod 所在的 node01 节点上具有带有键 lab和标签值 a 的标签,node02 也有这个lab=a的标签,所以 node01 和 node02 是在一个拓扑域中,反亲和要求新 Pod 与指定 Pod 不在同一拓扑域,所以新 Pod 没有可用的 node 节点,即为 Pending 状态。

    1. kubectl get pod --show-labels -owide
    2. kubectl label nodes node02 lab=b --overwrite
    3. kubectl get pod --show-labels -o wide
    • 根据输出,可以看出新的 Pod myapp20 因为反亲和性调度规则而处于 Pending 状态。由于 Pod myapp01 具有标签 app=myapp01,并且拓扑域键 lab 的值为 a,而节点 node01node02 都有拓扑域键 lab 的标签,因此它们被认为处于相同的拓扑域。

    • 由于新的 Pod myapp20 需要避免与具有标签 app=myapp01 的 Pod 调度到同一拓扑域,但在目前的节点中,没有节点符合该条件,因此该 Pod 保持在 Pending 状态。更新了 node02 的标签,但似乎仍然不符合新 Pod 的调度要求。

    • 最终,创建了一个新的 Pod myapp21,它成功在 node02 上运行,因为现在 node02 的标签为 lab=b,与之前的标签不同,因此不再满足与 Pod myapp20 的反亲和性调度要求。

    污点(Taint) 和 容忍(Tolerations)

    • 节点亲和性,是Pod的一种属性(偏好或硬性要求),它使Pod被吸引到一类特定的节点。Taint 则相反,它使节点能够排斥一类特定的 Pod。

    • Taint 和 Toleration 相互配合,可以用来避免 Pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 Pod,是不会被该节点接受的。如果将 toleration 应用于 Pod 上,则表示这些 Pod 可以(但不一定)被调度到具有匹配 taint 的节点上。

    • 使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。

    概念

    污点(Taints)

    • 污点是应用于节点的标记,用于阻止将新的Pod调度到带有该污点的节点上。

    • 污点由键值对(key=value)组成,其中键表示污点的名称,而值表示污点的效果,例如NoSchedule、PreferNoSchedule和NoExecute。

    • 通过在节点上设置污点,可以限制哪些Pod可以被调度到该节点上。

    容忍度(Tolerations)

    • 容忍度是Pod的属性,用于指定Pod可以被调度到带有特定污点的节点上。

    • 每个容忍度包含键值对(key=value),其中键表示要容忍的污点的名称,而值表示要容忍的污点的效果。

    • Pod只有在其定义了与节点上污点匹配的容忍度时,才能被调度到带有该污点的节点上。

    调度行为

    • 如果Pod的容忍度与节点上的污点匹配,那么该Pod可以被调度到带有该污点的节点上。

    • 如果Pod的容忍度与节点上的污点不匹配,且污点的效果是NoSchedule或PreferNoSchedule,那么该Pod将不会被调度到该节点上。

    • 如果Pod的容忍度与节点上的污点不匹配,但污点的效果是NoExecute,那么该节点上的已有Pod可能会被驱逐(Evicted)。

    示例用法

    • 可以使用污点和容忍度来实现特定的调度需求,例如将某些特殊的Pod调度到专门的节点上,或者确保某些Pod不会被调度到某些节点上。

    格式和支持的效果(选项)

    1. #污点的组成格式如下:
    2. key=value:effect
    3. 每个污点有一个 keyvalue 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。

    个污点由键值对(key=value)和一个效果(effect)组成。效果描述了污点的作用,而键值对表示该污点的标签。支持的效果包括:

    • NoSchedule(不调度): Kubernetes将不会将Pod调度到具有该污点的节点上。

    • PreferNoSchedule(尽量避免调度): Kubernetes将尽量避免将Pod调度到具有该污点的节点上,但不是绝对禁止。

    • NoExecute(不执行): Kubernetes将不会将Pod调度到具有该污点的节点上,并且会将节点上已经存在的Pod驱逐出去,确保节点不再运行这些Pod。

    这种机制为Kubernetes提供了更精细的调度控制,使得系统可以根据特定的需求和场景进行灵活的调度决策。

    污点的基本操作

    用一个具体的示例来说明如何在Kubernetes中执行这些操作。

    假设我们有一个名为node-1的节点,我们要给它添加一个污点,阻止Pod在这个节点上调度,除非它们具有特定的标签。我们将添加一个名为special=true:NoSchedule的污点。

    添加污点

    1. kubectl taint nodes <node-name> key=value:taint-effect
    2. kubectl taint nodes node-1 special=true:NoSchedule

    这将在node-1节点上添加一个名为special、值为true的污点,并且该污点的效果为NoSchedule,意味着除非Pod具有与此污点匹配的容忍(Toleration),否则不会在该节点上调度。

    查看污点

    1. kubectl describe node <node-name>
    2. kubectl describe node node-1

    运行此命令将显示有关node-1节点的详细信息,包括其上的污点。

    删除污点

    1. kubectl taint nodes <node-name> key:NoSchedule-
    2. kubectl taint nodes node-1 special:NoSchedule-

    这会从node-1节点上删除名为special的污点,并且污点的效果为NoSchedule

    示例

    1. # 显示集群中的节点信息,包括名称、状态、角色、年龄和版本
    2. kubectl get nodes
    3. NAME STATUS ROLES AGE VERSION
    4. master Ready master 11d v1.20.11
    5. node01 Ready <none> 11d v1.20.11
    6. node02 Ready <none> 11d v1.20.11
    7. # master 节点设置了一个 NoSchedule 类型的污点,导致不允许在此节点上调度 Pod
    8. kubectl describe node master
    9. ......
    10. Taints: node-role.kubernetes.io/master:NoSchedule
    11. # 给 node01 节点设置一个名为 key1,值为 value1 的 NoSchedule 类型的污点
    12. kubectl taint node node01 key1=value1:NoSchedule
    13. # 在节点说明中查找 Taints 字段,用于查看节点上设置的污点信息
    14. kubectl describe node node-name
    15. # 从 node01 节点中移除名为 key1 的污点
    16. kubectl taint node node01 key1:NoSchedule-
    17. # 显示 Pod 的信息,包括名称、就绪状态、状态、重启次数、年龄、IP 地址、所在节点等
    18. kubectl get pods -o wide
    19. # 给 node02 节点设置一个名为 check,值为 mycheck 的 NoExecute 类型的污点,导致 Pod 在此节点上被驱逐
    20. kubectl taint node node02 check=mycheck:NoExecute
    21. # 查看 Pod 状态,会发现 node02 上的 Pod 已经被全部驱逐
    22. # 注:如果是 Deployment 或者 StatefulSet 资源类型,为了维持副本数量则会在别的 Node 上再创建新的 Pod
    23. kubectl get pods -o wide

    容忍

    通过在 Pod 上设置容忍(Tolerations),可以允许 Pod 在存在污点的节点上被调度。这使得在一些特定情况下,例如需要部署某些特殊任务或者维护节点时,依然能够将 Pod 调度到被标记为污点的节点上。容忍(Tolerations)允许 Pod 忽略节点上的污点并允许被调度,从而灵活地管理集群资源。

    举例说明

    1. # 在节点 node01 上设置了一个名为 mycheck 的污点,并且指定了 NoExecute 效果
    2. kubectl taint node node01 check=mycheck:NoExecute
    3. # 编辑名为 pod3.yaml 的 Pod 配置文件
    4. vim pod3.yaml
    5. # 应用 Pod3 的配置文件
    6. kubectl apply -f pod3.yaml
    7. # 当在两个节点上都设置了污点后,Pod 将无法创建成功
    8. kubectl get pods -o wide
    9. # 此时输出显示 Pod 处于 Pending 状态,无法调度到任何节点运行
    10. # 编辑 pod3.yaml 文件,为 Pod 定义容忍策略,使其能够在具有污点的节点上运行
    11. vim pod3.yaml
    1. # pod3.yaml 文件内容
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: myapp01
    6. labels:
    7. app: myapp01
    8. spec:
    9. containers:
    10. - name: with-node-affinity
    11. image: soscscs/myapp:v1
    12. tolerations:
    13. - key: "check"
    14. operator: "Equal"
    15. value: "mycheck"
    16. effect: "NoExecute"
    17. tolerationSeconds: 3600
    1. # 为 Pod 设置容忍策略,确保其能够在具有指定污点的节点上运行
    2. # 其中的 key、value、effect 需要与节点上设置的污点保持一致
    3. # operator 的值为 Exists 将会忽略 value 值,即存在即可
    4. # tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在节点上继续保留运行的时间
    5. # 再次应用更新后的 Pod3 配置文件
    6. kubectl apply -f pod3.yaml
    7. # 验证 Pod 创建成功,并在指定的节点上正常运行
    8. kubectl get pods -o wide
    9. # 输出显示 Pod 已成功创建并运行在节点 node01 上

    值得注意的操作

    • 未指定 key 值时,表示容忍所有的污点 key。
    1. tolerations:
    2. - operator: "Exists"
    • 未指定 effect 值时,表示容忍所有的污点作用。
    1. tolerations:
    2. - key: "key"
    3. operator: "Exists"
    • 多个 Master 存在时,防止资源浪费,可设置如下:
    kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
    
    • 若某个 Node 更新升级系统组件,为防止业务中断,可先在该 Node 设置 NoExecute 污点,驱逐 Pod。
    kubectl taint node node01 check=mycheck:NoExecute
    
    • 若其他 Node 资源不足,可暂时给 Master 设置 PreferNoSchedule 污点,使 Pod 在 Master 上创建。
    kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule
    
    • 所有 Node 更新操作完成后,移除污点。
    kubectl taint node node01 check=mycheck:NoExecute-
    

    维护节点和应用程序操作

    管理节点的调度状态:

    • Cordon: 使用 kubectl cordon 命令将指定节点标记为不可调度状态。这将阻止新的 Pod 在此节点上调度。

    • Drain: 使用 kubectl drain 命令使节点进入排水状态。这将释放节点上的所有 Pod,并且不再接受新的 Pod。执行排水操作通常在需要维护节点或者从集群中移除节点时使用。

      • 注:执行 drain 命令,会自动做了两件事情: 1.设定此 node 为不可调度状态(cordon) 2.evict(驱逐)了 Pod
    • Uncordon: 使用 kubectl uncordon 命令将节点标记为可调度状态,恢复节点的正常调度功能。这允许新的 Pod 再次在该节点上调度。

    设置和移除污点:

    • 设置污点: 使用 kubectl taint node =: 命令在节点上设置污点。污点可以阻止 Pod 在具有特定标签和效果的节点上调度。

    • 移除污点: 使用 kubectl taint node =:- 命令在节点上移除指定的污点。这将允许 Pod 再次在该节点上调度。

    常见的污点效果(Effect):

    • NoSchedule: 阻止新的 Pod 调度到节点上,但不会驱逐现有的 Pod。

    • PreferNoSchedule: 倾向于不在该节点上调度新的 Pod,但不会阻止 Pod 调度。

    • NoExecute: 阻止新的 Pod 调度到节点上,并且将现有 Pod 驱逐出该节点。

    常见参数:

    • --ignore-daemonsets:

      • 当执行 kubectl drain 命令时,使用该选项可以忽略 DaemonSet 管理下的 Pod。DaemonSet 是 Kubernetes 中一种控制器类型,它确保在集群中的每个节点上运行一个副本的 Pod。通常情况下,节点的排水操作不会影响 DaemonSet 管理的 Pod,因为它们被认为是关键的系统组件,需要保持运行。使用 --ignore-daemonsets 选项可以确保在排水节点时不会影响 DaemonSet 的 Pod。
    • --delete-local-data:

      • 当执行 kubectl drain 命令时,如果节点上有挂载本地卷的 Pod,使用该选项可以强制删除这些 Pod。本地卷是直接挂载在节点上的存储卷,而不是通过网络挂载的。在某些情况下,需要强制删除这些 Pod,例如当节点需要被彻底清空时。
    • --force:

      • 当执行 kubectl drain 命令时,使用该选项可以强制释放不是由控制器管理的 Pod。控制器管理的 Pod 包括 Deployment、StatefulSet、DaemonSet 等。通常情况下,控制器会确保 Pod 的数量和状态符合预期,但是如果需要强制释放一些不是由控制器管理的 Pod,可以使用 --force 选项。

    通过合理管理节点的调度状态和设置/移除污点,可以有效地管理集群中的资源,确保应用程序的高可用性和稳定性。

    pod启动阶段的状态解读与排错技巧

    Pod启动阶段(相位 phase)

    Pod 创建完之后,一直到持久运行起来,中间有很多步骤,也就有很多出错的可能,因此会有很多不同的状态。

    • 调度到某台 node 上: Kubernetes 根据一定的优先级算法选择一个 node 节点来运行 Pod。

    • 拉取镜像: Pod 需要拉取其包含的镜像,以便在节点上创建容器。

    • 挂载存储配置等: Pod 可能需要挂载存储卷或配置文件等资源。

    • 运行起来: 当所有必需的资源准备就绪后,Pod 开始在节点上运行。如果定义了健康检查,系统会根据检查结果设置 Pod 的状态。

    pod可能的状态

    • Pending(挂起): 表示 Pod 资源对象已创建,但尚未完成调度或正在拉取镜像。

    • Running(运行中): Pod 已经被调度到节点上,并且至少有一个容器正在运行,或处于启动或重启状态。也就是说Running状态下的Pod不一定能被正常访问

    • Succeeded(成功): 表示 Pod 中的所有容器已成功终止,通常用于短期任务执行完毕后的状态反馈。有些pod不是长久运行的,比如job、cronjob,一段时间后Pod中的所有容器都被成功终止,并且不会再重启。需要反馈任务执行的结果。

    • Failed(失败): 所有容器都已终止,并且至少有一个容器由于失败而终止,可能是由于命令错误等原因。也就是说,容器以非0状态退出或者被系统终止,比如 command 写的有问题。

    • Unknown(未知): 表示无法读取 Pod 的状态,通常是由于控制器(kube-controller-manager)无法与 Pod 通信导致的。

    故障排除步骤

    需要排查 Pod 启动或运行中的问题时,以下是一些详细的故障排除步骤:

    • 查看 Pod 事件: 使用 kubectl describe 命令检查 Pod 事件,以了解 Pod 启动过程中可能出现的问题。这将提供关于 Pod 创建、调度和运行过程中的详细信息。
    kubectl describe pod <POD_NAME>
    

    期望输出: Pod 的事件日志,包括调度、镜像拉取、容器启动等信息。

    • 查看 Pod 日志: 如果 Pod 处于 Failed 状态,使用 kubectl logs 命令查看 Pod 的日志以获取失败的原因。可以通过指定容器名称来查看特定容器的日志。
    kubectl logs <POD_NAME> [-c <CONTAINER_NAME>]
    

    期望输出: 容器的标准输出和标准错误日志,显示应用程序的运行日志或错误信息。

    • 进入 Pod 内部: 如果 Pod 处于 Running 状态但服务没有提供,可以使用 kubectl exec 命令进入 Pod 内部。这样可以检查 Pod 内部的环境和运行状态,以便进一步诊断问题。
    kubectl exec -it <POD_NAME> -- /bin/bash
    

    期望操作: 在 Pod 内部运行命令进行故障排查,如检查网络配置、运行状态或日志文件。

    • 查看集群信息: 使用 kubectl get nodes 命令检查集群中节点的状态,以确保节点正常运行。这可以帮助排除可能导致 Pod 无法调度或运行的节点问题。
    kubectl get nodes
    

    期望输出: 集群中所有节点的列表,包括它们的状态(Ready、NotReady 或其他)。

    • 检查集群状态: 使用 kubectl cluster-info 命令检查整个集群的状态,包括控制平面和核心服务。这有助于确定是否存在集群范围的问题。
    kubectl cluster-info
    

    期望输出: 集群控制平面组件的状态和访问URL,如 Kubernetes master 和 kubeDNS。

    • 查看 kubelet 日志: 最后,查看 kubelet 的日志以发现与 Pod 启动或运行相关的任何问题。可以使用 journalctl 命令来查看 kubelet 的日志。
    journalctl -u kubelet
    

    期望输出: kubelet 服务的日志,提供与 Pod 生命周期和节点状态相关的详细信息。

    通过执行以上步骤,可以对 Pod 启动或运行中的问题进行详细的排查和诊断,从而有效地解决问题并确保应用程序正常运行。

  • 相关阅读:
    Observability:如何使用 Elastic Agents 把定制的日志摄入到 Elasticsearch 中
    ISP算法----AWB总结及源代码
    【计算机视觉40例】案例17:求解数独图像
    《视觉 SLAM 十四讲》V2 第 11 讲 回环检测【消除累积误差】
    Windows安装Node.js
    推荐模型复现(一):熟悉Torch-RecHub框架与使用
    【网络】网络编程——带你手搓简易TCP服务端(echo服务器)+客户端(四种版本)
    P3385 【模板】负环
    2. 排序二叉树
    golang设置socket选项参数SO_LINGER、SO_SNDBUF
  • 原文地址:https://blog.csdn.net/qq_51545656/article/details/136359699