k8s之pod

1 概述

Pod 的定义

<font color="#9bbb59">Pod 是 Kubernetes 集群中调度的最小单元,也是 Kubernetes 的核心概念之一。它是一个或多个容器(通常是 Docker 容器)的集合,这些容器共享相同的资源和网络命名空间</font>。Pod 的设计目标是支持多个容器之间的协作和通信。

Pod 的特点

  • 最小调度单元:Pod 是 Kubernetes 调度的最小单位。Kubernetes 会将 Pod 调度到集群中的某个节点(Node)上运行,而不会将一个 Pod 的不同部分分散到多个节点。

  • 容器共享资源:Pod 内的容器共享相同的网络命名空间、存储卷等资源。这意味着它们可以通过 localhost 相互通信,并且可以访问相同的文件系统。

  • 生命周期一致:Pod 内的容器共享相同的生命周期。如果 Pod 被删除,那么 Pod 内的所有容器都会被一起删除。

Pod 中的容器类型

你提到 Pod 中有三种类型的容器,这是非常准确的。以下是每种容器的详细说明:

(1)基础架构容器

  • 作用:基础架构容器是 Pod 中的第一个容器,由 Kubernetes 自动创建和管理。

  • 功能

    • 它的主要作用是为 Pod 提供一个稳定的网络命名空间。

    • 它使用一个特殊的镜像(如 k8s.gcr.io/pause),该镜像非常小,只包含必要的网络初始化工具。

    • 它在 Pod 启动时首先运行,为其他容器提供网络环境。

  • 特点

    • 每个 Pod 只有一个基础架构容器。

    • 它通常不会执行任何实际的业务逻辑。

    • 它的生命周期与 Pod 的生命周期一致。

(2)初始化容器

  • 作用:初始化容器用于在业务容器启动之前执行一些初始化任务。

  • 特点

    • 初始化容器是可选的,用户可以根据需要定义。

    • 它们在业务容器启动之前按顺序运行。

    • 每个初始化容器必须成功完成后,下一个初始化容器才会启动。

    • 如果某个初始化容器失败,Pod 会根据其重启策略决定是否重新启动该初始化容器。

  • 常见用途

    • 下载配置文件或脚本。

    • 检查依赖服务是否可用(如数据库是否启动)。

    • 设置环境变量或配置文件。

(3)业务容器

  • 作用:业务容器是 Pod 中实际运行用户业务逻辑的容器。

  • 特点

    • 一个 Pod 中可以有多个业务容器,但它们通常共享相同的上下文和资源。

    • 业务容器的启动顺序不保证,它们会在所有初始化容器成功完成后并行启动。

  • 常见用途

    • 运行应用程序、服务或微服务。

    • 执行数据处理或计算任务。

Pod 的生命周期

  • 基础架构容器的退出:如果基础架构容器退出,Pod 的网络命名空间将不再存在,此时所有业务容器也会被迫退出。这是因为 Pod 的网络依赖于基础架构容器提供的网络环境。

  • Pod 的重启策略:Pod 的重启策略(如 AlwaysOnFailureNever)决定了业务容器在失败时的行为。但请注意,Pod 本身不会自动重新调度到其他节点,除非它被删除并重新创建。

2 pod基础操作

创建 Pod

(1)通过 YAML 文件创建 Pod

  1. 编写 Pod 的 YAML 文件
    创建一个名为 mypod.yaml 的文件,内容如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
      - name: mycontainer
        image: nginx
    
  2. 使用 kubectl apply 创建 Pod
    kubectl apply -f mypod.yaml
    

(2)直接通过命令行创建 Pod

kubectl run mypod --image=nginx --restart=Never
  • --restart=Never 表示 Pod 不会自动重启。

查看 Pod

(1)查看所有 Pod

kubectl get pods
  • 添加 -o wide 选项可以显示更多的信息,例如 Pod 所在的节点:
    kubectl get pods -o wide
    

(2)查看 Pod 的详细信息

kubectl describe pod <pod-name>
  • 例如:
    kubectl describe pod mypod
    

删除 Pod

kubectl delete pod <pod-name>

kubectl delete pod <pod-name> --force --grace-period=0
  • 例如:
    kubectl delete pod mypod
    

进入 Pod 的容器

如果你需要进入 Pod 的容器进行调试,可以使用以下命令:

kubectl exec -it <pod-name> -- /bin/bash
  • 如果容器没有 /bin/bash,可以尝试 /bin/sh 或其他可用的 shell。
  • 例如:
    kubectl exec -it mypod -- /bin/bash
    
    kubectl exec -it test -c xx -- sh
    

查看 Pod 的日志

kubectl logs <pod-name>
  • 如果 Pod 中有多个容器,可以通过 -c 参数指定容器:
    kubectl logs -f <pod-name> -c <container-name>
    

pod之cp

# 从 Pod 复制文件到本地
kubectl cp my-namespace/my-pod:/tmp/logs.txt ./logs.txt

# 从本地复制文件到 Pod
kubectl cp ./config.yaml my-namespace/my-pod:/etc/config.yaml

更新 Pod

Pod 是不可变的,不能直接修改。如果需要更新 Pod,通常需要删除旧的 Pod 并重新创建一个新的 Pod。不过,如果 Pod 是通过 Deployment 或其他控制器管理的,可以通过更新控制器的配置来间接更新 Pod。

示例:更新 Deployment 中的 Pod

  1. 编辑 Deployment 的 YAML 文件:
    kubectl edit deployment <deployment-name>
    
  2. 修改 image 或其他配置。
  3. 保存并退出,Kubernetes 会自动更新 Pod。

暂停和恢复 Pod

虽然 Pod 本身没有暂停和恢复的操作,但可以通过以下方式实现类似的效果:

  • 暂停 Pod:将 Pod 的容器设置为 sleep 状态。
    kubectl exec -it <pod-name> -- /bin/sh -c "sleep infinity"
    
  • 恢复 Pod:删除 Pod 并重新创建。

查看 Pod 的资源使用情况

kubectl top pod <pod-name>
  • 这需要集群中安装了 Metrics Server。

查看 Pod 的事件

kubectl describe pod <pod-name>
  • Events 部分可以看到 Pod 的生命周期事件。

查看 Pod 的存储卷

kubectl describe pod <pod-name>
  • Volumes 部分可以看到 Pod 的存储卷信息。

好的!以下是关于 Kubernetes 标签(Labels)的整理,包括标签的概念、操作以及基于标签的资源管理。

3 k8s标签(Labels)

  • 概念:Kubernetes 中的标签是键值对(key-value pairs),用于对资源(如 Pod、Deployment、Service 等)进行分类和选择。
  • 作用
    • 标签可以用于组织和管理资源。
    • 标签可以用于选择特定的资源集,例如在部署、服务发现或资源监控中。
    • 标签不直接修改资源的行为,但可以通过控制器(如 Deployment、Service)间接影响资源的调度和管理。

标签的基本操作

(1)查看 Pod 的标签

kubectl get pods --show-labels
  • 使用 --show-labels 选项可以显示 Pod 的标签信息。

(2)为 Pod 添加标签

kubectl label pod <pod-name> key=value
  • 示例:
    kubectl label pod text01 school=oldboyedu
    

(3)修改标签

kubectl label pod <pod-name> key=value --overwrite
  • --overwrite 参数允许覆盖已存在的标签。
  • 示例:
    kubectl label pod text01 school=laonanhai --overwrite
    

(4)删除标签

kubectl label pod <pod-name> key-
  • 示例:
    kubectl label pod text01 school-
    

(5)批量操作

  • 为多个 Pod 打标签
    kubectl label pod text01 text03 school=oldboyedu
    
  • 删除所有 Pod 的某个标签
    kubectl label pods --all key-
    

基于标签的资源选择

(1)使用标签选择 Pod

kubectl get pods -l key=value
  • 示例:
    kubectl get pods -l school=oldboyedu
    

(2)使用多个标签选择 Pod

kubectl get pods -l key1=value1,key2=value2
  • 示例:
    kubectl get pods -l class=linux97,school=yitiantian
    

(3)使用标签范围选择 Pod

kubectl get pods -l 'key in (value1,value2)'
  • 示例:
    kubectl get pods -l 'school in (oldboyedu,laonanhai)'
    

(4)删除匹配标签的 Pod

kubectl delete pods -l key=value
  • 示例:
    kubectl delete pods -l class=linux97
    

总结

  • 标签 是 Kubernetes 中用于分类和选择资源的键值对。
  • 标签可以用于管理资源、选择特定资源集或进行资源监控。
  • 通过 kubectl label 命令可以添加、修改或删除标签。
  • 使用 -l 参数可以基于标签过滤资源。
  • 标签是 Kubernetes 资源管理的重要工具,能够帮助你更高效地组织和操作资源。

4 声明式管理pod

4.1 编写资源清单


cat 01-pods-text.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: cmy
  name: text-v1
spec:
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
    name: v1
#应用资源清单
kubectl apply -f 01-pods-text.yaml

#查看资源清单创建的资源
kubectl get -f 01-pods-text.yaml -o wide
NAME         READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
text-v1   1/1     Running   0          8m34s   10.100.203.138   worker232   <none>           <none>

#删除资源清单创建的资源
kubectl delete -f 01-pods-text.yaml


5 pod故障排查技巧总结!!!

- 故障排查技巧总结
	如果Pod非Runing状态,说明该Pod处于不正常状态,因此需要借助K8S相关技术栈来解决问题。
	
	具体解决思路如下:
		- 1.kubectl describe <资源类型>  名称|标签 
			思路解读:
				- 使用该命令可以对Pod故障做一些基础性拍错,包括但不限于镜像拉取失败,容器启动失败,探针检测失败,存储卷挂载失败,资源不足,网络插件,调度失败,认证失败等各种故障原因。
			
			
		- 2.kubectl logs POD -c CONTAINER 
			思路解读:
				- 使用该命令的前提是Pod已经完成了调度工作,且启动过容器才会有日志产生。如果Pod无法完成调度,则该命令无效。看不到任何有效的帮助信息。
				
				
				面试题:
					--since 20m
						查看20分钟内的日志。
						
					-p 
						查看上一次容器重启的日志。前提是有重启过,如果没有重启或者容器不存在,则此参数无效。
						
				
		- 3.kubectl exec POD -c CONTAINER 
			思路解决:
				- 相当于传统的Linux运维,进入到了Linux服务器,可以实现各种操作,从而快速定位问题。
				- 如果想要执行该命令的前提是pod已经能够启动成功。说白了,就是其正常运行。
				
		- 4.command & args 
			思路解决:
				- 解决容器无法正常启动的情况,启动后,使用exec进入到容器进行结合排查。
				
		- 5.cp
			思路解决:
				- 一般情况下,如果有需要将本地文件或者容器的某个文件进行互相拷贝的时候,就可以使用该命令。
				

6 pod状态!!!

1. Pending(等待中)

  • 状态描述:Pod 已被 Kubernetes 系统接受,但尚未创建容器。通常是因为镜像正在下载,或者调度器正在寻找合适的节点来运行 Pod。

  • 常见原因

    • 镜像拉取失败(如镜像不存在、网络问题)。

    • 调度器无法找到合适的节点(如资源不足、节点亲和性规则不匹配)。

    • Pod 的初始化容器尚未运行完成。

2. Running(运行中)

  • 状态描述:Pod 已经绑定到某个节点上,且所有容器都已创建并正在运行。至少有一个容器处于运行状态,或者处于启动或重启过程中。

  • 特点

    • Pod 的状态被设置为 Running,表示它已经成功调度到节点上。

    • 容器的生命周期管理(如启动、重启)由 kubelet 负责。

    • 如果容器崩溃,kubelet 会根据 RestartPolicy(重启策略)来决定是否重启容器。

3. Succeeded(成功)

  • 状态描述:Pod 中的所有容器都已成功运行完成,并且不会再重启。通常用于执行一次性任务的 Pod,如批量处理作业。

  • 特点

    • Pod 的生命周期结束,但不会被自动删除。可以通过设置 ttlSecondsAfterFinished 来指定 Pod 在完成后保留的时间。

    • Pod 的状态不会再次变为其他状态。

4. Failed(失败)

  • 状态描述:Pod 中至少有一个容器以失败状态退出,并且不会被重启。通常是因为容器运行时出现错误,或者达到了重启策略的限制。

  • 常见原因

    • 容器运行时错误(如程序崩溃、资源耗尽)。

    • 容器健康检查失败(如就绪探针或存活探针失败)。

    • 重启策略为 Never,且容器退出状态码非零。

5. Unknown(未知)

  • 状态描述:Pod 的状态无法确定,通常是因为与 Pod 所在节点的通信出现问题。例如,节点网络故障或 kubelet 崩溃。

  • 特点

    • Kubernetes 会尝试重新获取 Pod 的状态,如果长时间无法获取,可能会自动删除 Pod 或重新调度。

    • 这是一个临时状态,通常需要人工干预来解决节点问题。

6.2 容器3种状态

Waiting(等待):
	
	如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。

Running(运行中):

	Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时, 你也会看到关于容器进入 Running 状态的信息。

Terminated(已终止):
	处于 Terminated 状态的容器开始执行后,或者运行至正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间。

6.3 Pod 重启策略!!!

  • restartPolicy 的值可以是 AlwaysOnFailureNever
    • Always:无论容器是否正常退出,都会重启容器。
    • OnFailure:容器异常退出时会重启,正常退出时不会重启。
    • Never:容器退出后不会重启。
  • 如果不指定 restartPolicy,默认值为 Always

Pod 重启策略配置文件

apiVersion: v1
kind: Pod
metadata:
  labels:
    name: cmy
  name: lx
spec:
  restartPolicy: "OnFailure"
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
    name: c1
    command:
    - sh
    - -c
    - "sleep 60; exit 1"

7 pod创建流程 !!!!!


Pod的创建,删除,修改流程:
      1.执行kubectl命令时会加载"~/.kube/config",从而识别到apiserver的地址,端口及认证证书;
      2.apiserver进行证书认证,鉴权,语法检查,若成功则可以进行数据的读取或者写入;
      3.若用户是写入操作(创建,修改,删除)则需要修改etcd数据库的信息;
      4.如果创建Pod,此时scheduler负责Pod调度,将Pod调度到合适的worker节点,并将结果返回给ApiServer,由apiServer负责存储到etcd中;
      5.kubelet组件会周期性上报给apiServer节点,包括Pod内的容器资源(cpu,memory,disk,gpu,...)及worker宿主机节点状态,apiServer并将结果存储到etcd中,若有该节点的任务也会直接返回给该节点进行调度;
      6.kubelet开始调用CRI(Container Runtime Interface)接口创建容器(依次创建pause,initContainers,containers);
      7.在运行过程中,若Pod容器,正常或者异常退出时,kubelet会根据重启策略是否重启容器(Never,Always,OnFailure);
      8.若一个节点挂掉,则需要controller manager介入维护,比如Pod副本数量缺失,则需要创建watch事件,要求控制器的副本数要达到标准,从而要创建新的Pod,此过程重复步骤4-6。

基于资源清单创建 Pod

  • 用户通过 kubectl apply 或其他工具提交 Pod 的资源清单文件到 Kubernetes API Server。
  • API Server 验证资源清单的合法性,并将其存储到 etcd 数据库中。
  • 补充说明
    • etcd 是 Kubernetes 的分布式存储系统,用于存储集群的状态信息。
    • API Server 是 Kubernetes 的核心组件,负责处理所有资源的增删改查操作,并将数据持久化到 etcd。

调度器(Scheduler)调度 Pod

  • 调度决策
    • Scheduler 负责决定将 Pod 调度到哪个 Worker 节点。
    • Scheduler 会根据多种因素进行调度决策,包括节点的资源利用率(CPU、内存等)、亲和性规则、污点与容忍等。
  • 调度结果上报
    • Scheduler 将调度结果发送给 API Server。
    • API Server 将调度结果(即 Pod 被分配到的节点信息)存储到 etcd 中。
  • 补充说明
    • 如果调度失败(例如没有合适的节点),Pod 会处于 Pending 状态,直到找到合适的节点。

Controller Manager 维护集群状态

  • Pod 控制器(Replication Controller/ReplicaSet/Deployment 等)
    • Controller Manager 组件中的 Pod 控制器会监控集群中 Pod 的状态。
    • 如果发现某个 Pod 出现故障或被删除,控制器会根据定义的期望状态(如副本数量)自动创建新的 Pod。
  • Watch 事件处理
    • Controller Manager 通过监听 etcd 中的资源变更事件(如 Pod 的创建、更新或删除),确保集群的实际状态与期望状态一致。
  • 补充说明
    • Controller Manager 还负责其他资源的管理,例如 Service、DaemonSet 等。

Worker 节点上报状态信息

  • 状态上报
    • 各个 Worker 节点上的 kubelet 组件会定期向 API Server 上报自己节点上 Pod 的运行状态(如容器的健康状态、资源使用情况等)。
    • 同时,kubelet 也会上报节点自身的资源使用情况(如 CPU、内存的利用率等)。
  • 调度命令同步
    • API Server 将 etcd 中记录的调度命令(即 Pod 被分配到的节点信息)同步到对应的 Worker 节点。
  • 补充说明
    • kubelet 是 Kubernetes 在每个节点上的代理组件,负责管理 Pod 的生命周期。

Worker 节点创建 Pod

  • 容器运行时接口(CRI)调用
    • Worker 节点上的 kubelet 根据调度命令,调用容器运行时接口(CRI)来创建 Pod。
    • CRI 是 Kubernetes 提供的一种标准化接口,用于与容器运行时(如 Docker、containerd 等)进行交互。
  • 容器创建
    • 容器运行时通过调用底层的容器运行时工具(如 runc)来创建容器。
    • 容器运行时会拉取指定的镜像,并启动容器。
  • 网络配置
    • Kubernetes 网络插件(如 Flannel、Calico 等)会为 Pod 分配 IP 地址,并配置网络,确保 Pod 之间可以相互通信。
  • 补充说明
    • Pod 的生命周期由 kubelet 管理,包括启动、停止和删除容器。
- kubelet启动容器的原理图解【了解】
	1.kubelet创建Pod的全流程:
     - 1.kubelet调用CRI接口创建容器,底层支持docker|containerd作为容器运行时;
     - 2.底层基于runc(符合OCI规范)创建容器:
     - 3.优先创建pause基础镜像;
     - 4.创建初始化容器
     - 5.业务容器,业务容器如果定义了优雅终止,探针则顺序如下:
          - 5.1 启动命令【COMMAND】
          - 5.2 启动postStart;
          - 5.3 Probe
                     - StartupProbe
                     - LivenessProbe | readinessProbe
          - 5.4 启动PreStop
                    受限于优雅终止时间(默认30s)。

总结

Kubernetes 创建 Pod 的流程涉及多个组件的协同工作:

  1. API Server:接收用户请求,验证并存储资源清单到 etcd。
  2. Scheduler:负责调度决策,将 Pod 分配到合适的 Worker 节点。
  3. Controller Manager:监控集群状态,确保 Pod 按期望状态运行。
  4. Worker 节点(kubelet):接收调度命令,调用 CRI 创建 Pod,并上报状态信息。
  5. 容器运行时(如 Docker、containerd):实际创建和管理容器。

8 玩转pod调度

8.1 使用 nodeName 将 Pod 调度到指定节点

通过在 Pod 的配置中指定 nodeName,可以将 Pod 直接调度到指定的节点。这种方式简单直接,但缺乏灵活性。

示例配置

01-nodeName.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: text-nodename
spec:
  replicas: 5
  selector:
    matchLabels:
      apps: v1
  template:
    metadata:
      labels:
        apps: v1
    spec:
      # 指定 Pod 调度到名为 worker232 的节点
      nodeName: worker232
      containers:
        - name: c1
          image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1

8.2 hostPort 绑定宿主机端口

通过设置 hostPort,Pod 内的容器可以直接绑定宿主机的端口,从而实现外部访问。
hostPort是Pod使用worker节点进行NAT转发,从而达到暴露服务到K8S集群外部的一种方式。

早期K8S 1.5.2 版本会监听相应的端口,现在新版本中并不会监听端口。

示例配置

03-hostPorts.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: text-ports
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: v1
  template:
    metadata:
      labels:
        apps: v1
    spec:
      containers:
        - name: c1
          image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
          ports:
            - containerPort: 80
              hostPort: 30080

[root@worker233 ~]# iptables -t nat -vnL | grep 30080 | grep DNAT
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:30080 to:10.100.140.73:80


<font color="#9bbb59">发现底层调用的是DNAT做端口转发</font>
注意:如果宿主机的端口已经被占用,Pod 会处于 Pending 状态,无法完成调度。

8.3 hostNetwork 共享宿主机网络命名空间

通过设置 hostNetwork: true,Pod 内的容器将直接使用宿主机的网络命名空间,共享网络接口和端口。

- hostNetwork之DNS解析策略
	1.编写资源清单 
[root@master231 pods]# cat 15-pods-text-dnsPolicy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pods-text
  labels:
    apps: text
spec:
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
    name: c1
    ports:
    - containerPort: 80
      name: web
    - containerPort: 8080
      name: security

---
apiVersion: v1
kind: Service
metadata:
  name: svc-text
spec:
  # 自定义CLusterIP地址,通常情况下不建议使用该字段,因为可能会导致端口冲突的问题!
  clusterIP: 10.200.0.100
  ports:
  - port: 90
    targetPort: web
  selector:
    apps: text
  type: ClusterIP


---

apiVersion: v1
kind: Pod
metadata:
  name: pods-dnspolicy
spec:
  hostNetwork: true
  # 如果使用了宿主机网络,通常情况下要指定DNS解析策略,否则就无法使用内部的svc名称解析了
  dnsPolicy: ClusterFirstWithHostNet
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
    name: c1


[root@master231 pods]# 


	2.测试验证
[root@master231 pods]# kubectl apply -f  15-pods-text-dnsPolicy.yaml
pod/pods-text created
service/svc-text created
pod/pods-dnspolicy created
[root@master231 pods]# 
[root@master231 pods]# kubectl get pods,svc -o wide
NAME                 READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod/pods-dnspolicy   1/1     Running   0          5s    10.0.0.232       worker232   <none>           <none>
pod/pods-text     1/1     Running   0          5s    10.100.203.157   worker232   <none>           <none>

NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/kubernetes    ClusterIP   10.200.0.1     <none>        443/TCP   9d    <none>
service/svc-text   ClusterIP   10.200.0.100   <none>        90/TCP    5s    apps=text
[root@master231 pods]# 
[root@master231 pods]# kubectl -n kube-system get svc kube-dns 
NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.200.0.10   <none>        53/UDP,53/TCP,9153/TCP   17d
[root@master231 pods]# 
[root@master231 pods]# kubectl exec -it pods-dnspolicy -- sh
/ # cat /etc/resolv.conf 
nameserver 10.200.0.10
search default.svc.oldboyedu.com svc.oldboyedu.com oldboyedu.com 
options ndots:5
/ # 
/ # ping svc-text -c 3
PING svc-text (10.200.0.100): 56 data bytes
64 bytes from 10.200.0.100: seq=0 ttl=64 time=0.045 ms
64 bytes from 10.200.0.100: seq=1 ttl=64 time=0.076 ms
64 bytes from 10.200.0.100: seq=2 ttl=64 time=0.049 ms

注意

  • 使用 hostNetwork 时,Pod 内的容器可以直接使用宿主机的网络接口,但可能会导致端口冲突。
  • 如果多个 Pod 使用了相同的宿主机端口,可能会导致调度失败或端口冲突。

8.4 资源限制resources

resources可以对Pod的容器进行资源的限制。

有两个字段可以进行配置:
requests:
容器的期望资源,如果worker节点无法满足该期望,则Pod不会调度到该节点。
调度到该节点后,也并不会即可消耗掉所有的期望资源。

limits:
	容器资源的使用上限。

温馨提示:
<font color="#9bbb59"> – 1.若没有定义resources资源,则Pod的容器默认可以使用worker节点的所有资源(CPU,内存,磁盘);</font>
<font color="#9bbb59"> – 2.若定义了resources资源,但没有配置limits,也会默认使用宿主机的所有资源;</font>
<font color="#9bbb59"> – 3.若定义了resources资源,但没有配置requests,则requests的资源和limits一致;</font>

示例配置

04-resources.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: text-resources
spec:
  replicas: 3
  selector:
    matchLabels:
      apps: v1
  template:
    metadata:
      labels:
        apps: v1
    spec:
      containers:
        - name: c1
          image: harbor.oldboyedu.com/oldboyedu-elasticstack/filebeat:ubuntu-v7.17.21
          # 定义资源限制
          resources:
            # 定义期望资源,不满足该条件时无法调度到指定节点
            requests:
              cpu: 0.5
              memory: 200Mi
            # 定义资源使用的上限,容器不会超过该资源限制
            limits:
              cpu: 1500m
              memory: 500Mi

注意

  • requests 是容器期望分配的资源量,调度时会考虑该值。
  • limits 是容器可以使用的最大资源量,容器运行时不会超过该值。
  • 如果宿主机的资源不足,Pod 可能无法被调度。

8.5 污点(Taints)

污点(Taint)​​ 是一种节点级别的标记机制,用于​​阻止或限制 Pod 调度到特定节点​​。污点通常与 Pod 的​​容忍度(Toleration)​​ 配合使用,实现精细化的调度控制。

常见的污点类型(Effect)

  1. NoSchedule
    • 不接受新的 Pod 调度,但已经调度到该节点的 Pod 不会被驱逐。
  2. PreferNoSchedule
    • 尽可能不调度 Pod 到该节点,但如果其他节点无法满足调度条件,Pod 仍可能被调度到该节点。
  3. NoExecute
    • 不接受新的 Pod 调度,并且会驱逐已经调度到该节点的 Pod。

污点的操作

(1)查看现有的污点信息

kubectl describe nodes | grep Taints

(2)打污点

kubectl taint node <node-name> key=value:effect
  • 示例:
    kubectl taint node worker232 school=oldboyedu:NoSchedule
    kubectl taint node worker232 class:NoSchedule
    

(3)修改污点

kubectl taint node <node-name> key=value:effect --overwrite
  • 示例:
    kubectl taint node worker232 class=linux91:NoSchedule --overwrite
    

(4)删除污点

kubectl taint node <node-name> key:effect-
  • 示例:
    kubectl taint node worker232 class:NoSchedule-
    

实战案例

cat 05-taints-NoSchedule.yaml
apiVersion:  apps/v1
kind: Deployment
metadata:
  name: scheduler-taints-noschedule
spec:
  replicas: 5
  selector:
    matchLabels:
      apps: text
  template:
    metadata:
      labels:
        apps: text
        version: v1
    spec:
      containers:
      - image: harbor.cmy.cn/caswdemo/tool:v1
        command:
        - tail
        - -f
        - /etc/hosts
        name: c1
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 400m
            memory: 2Gi

 kubectl taint node worker232 name=donottouchme:NoSchedule
node/worker232 tainted
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl describe nodes | grep Taints
Taints:             node-role.kubernetes.io/master:NoSchedule
Taints:             name=donottouchme:NoSchedule
Taints:             <none>

kubectl get pods -o wide
NAME                                          READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
scheduler-taints-noschedule-b57558bfd-4smlj   0/1     Pending   0          9s    <none>           <none>      <none>           <none>
scheduler-taints-noschedule-b57558bfd-bh4mk   1/1     Running   0          9s    10.100.140.103   worker233   <none>           <none>
scheduler-taints-noschedule-b57558bfd-j4hfr   0/1     Pending   0          9s    <none>           <none>      <none>           <none>
scheduler-taints-noschedule-b57558bfd-mdxtm   1/1     Running   0          9s    10.100.140.77    worker233   <none>           <none>
scheduler-taints-noschedule-b57558bfd-q7jth   1/1     Running   0          9s    10.100.140.90    worker233   <none>           <none>
[root@master-231 /oldboyedu/manifests/scheduler]#

解释
worker233 只能运行3个POD,worker232污点不允许pod调度

kubectl get pods -o wide
NAME                                          READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
scheduler-taints-noschedule-b57558bfd-4smlj   1/1     Running   0          2m17s   10.100.203.150   worker232   <none>           <none>
scheduler-taints-noschedule-b57558bfd-bh4mk   1/1     Running   0          2m17s   10.100.140.103   worker233   <none>           <none>
scheduler-taints-noschedule-b57558bfd-j4hfr   0/1     Pending   0          2m17s   <none>           <none>      <none>           <none>
scheduler-taints-noschedule-b57558bfd-mdxtm   1/1     Running   0          2m17s   10.100.140.77    worker233   <none>           <none>
scheduler-taints-noschedule-b57558bfd-q7jth   1/1     Running   0          2m17s   10.100.140.90    worker233   <none>           <none>
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl describe nodes | grep Taints
Taints:             node-role.kubernetes.io/master:NoSchedule
Taints:             name=ifokdonttouchme:PreferNoSchedule
Taints:             <none>

解释
修改worker232污点为PreferNoSchedule ,则232资源不够时可以调度到233

kubectl taint node worker233 name=alldonottouchme:NoExecute
node/worker233 tainted
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl describe nodes | grep Taints
Taints:             node-role.kubernetes.io/master:NoSchedule
Taints:             name=ifokdonttouchme:PreferNoSchedule
Taints:             name=alldonottouchme:NoExecute

kubectl get pods -o wide
NAME                                          READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
scheduler-taints-noschedule-b57558bfd-4smlj   1/1     Running   0          4m30s   10.100.203.150   worker232   <none>           <none>
scheduler-taints-noschedule-b57558bfd-g7z8j   0/1     Pending   0          33s     <none>           <none>      <none>           <none>
scheduler-taints-noschedule-b57558bfd-j4hfr   0/1     Pending   0          4m30s   <none>           <none>      <none>           <none>
scheduler-taints-noschedule-b57558bfd-xvf8c   0/1     Pending   0          33s     <none>           <none>      <none>           <none>
scheduler-taints-noschedule-b57558bfd-zjvdn   0/1     Pending   0          33s     <none>           <none>      <none>           <none>
[root@master-231 /oldboyedu/manifests/scheduler]#

解释
233打上NoExecute污点后驱逐所有污点且不允许调度到233

8.6 污点容忍(Tolerations)

Pod 的容忍配置允许它被调度到带有特定污点的节点。如果 Pod 配置了容忍某个污点,它将能够被调度到该节点。

  • 示例配置(06-tolerations.yaml):
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: text-tolerations
    spec:
      replicas: 10
      selector:
        matchLabels:
          apps: v1
      template:
        metadata:
          labels:
            apps: v1
        spec:
          tolerations:
          # 指定key和value之间的关系,有效值为: Exists, Equal(默认值)
          #  Exists: 
          #    只要key存在,则匹配所有的value,因此可以不定义value。
          #  Equal:
          # 	 要求key的值必须是value指定的值。 
            - key: school      # 容忍特定污点
              value: oldboyedu
              effect: NoSchedule
              operator: Equal
            - key: class   #匹配所有key为class的污点
              operator: Exists
              
            - operator: Exists   #不定义key,value,effect,则默认匹配所有的值,如果你这样做将无视任何污点!
    
          containers:
            - name: c1
              image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
    

8.7 nodeSelector

1.什么是nodeSelector 

nodeSelector是节点选择器,选择pod调度到特定节点。

和nodeName不同的是,<font color="#9bbb59">nodeSelector可以调度到多个符合选择的节点</font>。

1.给指定节点打标签
kubectl label nodes master-231 worker233 school=oldboyedu

2.根据标签选择节点

cat 07-ds-nodeselector.yaml
apiVersion:  apps/v1
kind: DaemonSet
metadata:
  name: scheduler-nodeselector
spec:
  selector:
    matchLabels:
      apps: text
  template:
    metadata:
      labels:
        apps: text
        version: v1
    spec:
      # 配置Pod的污点容忍
      nodeSelector:
        school: oldboyedu
      tolerations:
      - operator: Exists
      containers:
      - image: harbor.cmy.cn/caswdemo/tool:v1
        command:
        - tail
        - -f
        - /etc/hosts
        name: c1
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 400m
            memory: 2Gi

3.查看效果
kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
scheduler-nodeselector-c85r9   1/1     Running   0          10s   10.100.209.35   master-231   <none>           <none>
scheduler-nodeselector-m4v5x   1/1     Running   0          10s   10.100.140.66   worker233    <none>           <none>
[root@master-231 /oldboyedu/manifests/scheduler]#

8.8 cordon与uncordon

1.cordon

cordon可以标记节点不可调度,本质上是给改节点打了污点。
2.uncordon
uncordon的作用是cordon的反向操作,说白了就是取消节点不可调度,底层也会删除污点。

	2.1 操作前查看污点情况 
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             school=oldboyedu:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             class=linux97:NoExecute
                    class=LINUX97:PreferNoSchedule
Unschedulable:      false
[root@master231 ~]# 
[root@master231 ~]# 

		
		2.2 将节点标记为不可调度 
[root@master231 scheduler-pods]# kubectl get nodes
NAME        STATUS   ROLES                  AGE    VERSION
master231   Ready    control-plane,master   6d4h   v1.23.17
worker232   Ready    <none>                 6d4h   v1.23.17
worker233   Ready    <none>                 6d4h   v1.23.17
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl cordon worker232 
node/worker232 cordoned
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl get nodes
NAME        STATUS                     ROLES                  AGE    VERSION
master231   Ready                      control-plane,master   6d4h   v1.23.17
worker232   Ready,SchedulingDisabled   <none>                 6d4h   v1.23.17
worker233   Ready                      <none>                 6d4h   v1.23.17
[root@master231 scheduler-pods]# 


		2.3 再次查看节点污点
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             node.kubernetes.io/unschedulable:NoSchedule
                    school=oldboyedu:NoSchedule
Unschedulable:      true
--
Taints:             class=linux97:NoExecute
                    class=LINUX97:PreferNoSchedule
Unschedulable:      false
[root@master231 ~]# 



- 玩转Pod调度之uncordon



	2.实战案例 
		2.1 操作前污点查看 
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             node.kubernetes.io/unschedulable:NoSchedule
                    school=oldboyedu:NoSchedule
Unschedulable:      true
--
Taints:             class=linux97:NoExecute
                    class=LINUX97:PreferNoSchedule
Unschedulable:      false
[root@master231 ~]# 

		
		2.2 取消节点不可调度 
[root@master231 scheduler-pods]# kubectl get nodes
NAME        STATUS                     ROLES                  AGE    VERSION
master231   Ready                      control-plane,master   6d4h   v1.23.17
worker232   Ready,SchedulingDisabled   <none>                 6d4h   v1.23.17
worker233   Ready                      <none>                 6d4h   v1.23.17
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl uncordon worker232 
node/worker232 uncordoned
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl get nodes
NAME        STATUS   ROLES                  AGE    VERSION
master231   Ready    control-plane,master   6d4h   v1.23.17
worker232   Ready    <none>                 6d4h   v1.23.17
worker233   Ready    <none>                 6d4h   v1.23.17
[root@master231 scheduler-pods]# 


		2.3 操作后污点查看 
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             school=oldboyedu:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             class=linux97:NoExecute
                    class=LINUX97:PreferNoSchedule
Unschedulable:      false
[root@master231 ~]# 

8.9 驱逐(Drain)节点

驱逐节点是将节点上的 Pod 驱逐到其他节点的过程,通常用于节点维护或下线。

[root@master231 scheduler-pods]# kubectl describe nodes | grep Taints -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             school=oldboyedu:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             class=linux97:NoExecute
                    class=LINUX97:PreferNoSchedule
Unschedulable:      false
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl taint node worker233  class-
node/worker233 untainted
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl taint node worker232  school-
node/worker232 untainted
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl describe nodes | grep Taints -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             <none>
Unschedulable:      false
Lease:
--
Taints:             <none>
Unschedulable:      false
Lease:
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl apply -f  07-scheduler-tolerations.yaml 
deployment.apps/scheduler-taints-tolerations created
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl get pods -o wide
NAME                                           READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
scheduler-taints-tolerations-99f696b5d-2kfsq   1/1     Running   0          3s    10.100.140.72    worker233   <none>           <none>
scheduler-taints-tolerations-99f696b5d-hvhfj   1/1     Running   0          3s    10.100.160.152   master231   <none>           <none>
scheduler-taints-tolerations-99f696b5d-khpfk   1/1     Running   0          3s    10.100.140.65    worker233   <none>           <none>
scheduler-taints-tolerations-99f696b5d-p4lpq   1/1     Running   0          3s    10.100.203.146   worker232   <none>           <none>
scheduler-taints-tolerations-99f696b5d-vhmkc   1/1     Running   0          3s    10.100.203.153   worker232   <none>           <none>
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# 

		2.2 驱逐worker233节点 
[root@master231 scheduler-pods]# kubectl drain worker233 --ignore-daemonsets
node/worker233 already cordoned
WARNING: ignoring DaemonSet-managed Pods: calico-system/calico-node-82zlb, calico-system/csi-node-driver-pxq6d, kube-system/kube-proxy-w678l
evicting pod tigera-operator/tigera-operator-8d497bb9f-bnflh
evicting pod default/scheduler-taints-tolerations-99f696b5d-2kfsq
evicting pod default/scheduler-taints-tolerations-99f696b5d-khpfk
pod/tigera-operator-8d497bb9f-bnflh evicted
pod/scheduler-taints-tolerations-99f696b5d-khpfk evicted
pod/scheduler-taints-tolerations-99f696b5d-2kfsq evicted
node/worker233 drained
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl get pods -o wide
NAME                                           READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
scheduler-taints-tolerations-99f696b5d-hvhfj   1/1     Running   0          3m43s   10.100.160.152   master231   <none>           <none>
scheduler-taints-tolerations-99f696b5d-jmxlk   1/1     Running   0          2m2s    10.100.160.153   master231   <none>           <none>
scheduler-taints-tolerations-99f696b5d-m27kf   1/1     Running   0          2m2s    10.100.203.190   worker232   <none>           <none>
scheduler-taints-tolerations-99f696b5d-p4lpq   1/1     Running   0          3m43s   10.100.203.146   worker232   <none>           <none>
scheduler-taints-tolerations-99f696b5d-vhmkc   1/1     Running   0          3m43s   10.100.203.153   worker232   <none>           <none>
[root@master231 scheduler-pods]# 


		2.3 drain驱逐底层调用了cordon
[root@master231 scheduler-pods]# kubectl get nodes
NAME        STATUS                     ROLES                  AGE    VERSION
master231   Ready                      control-plane,master   6d5h   v1.23.17
worker232   Ready                      <none>                 6d4h   v1.23.17
worker233   Ready,SchedulingDisabled   <none>                 6d4h   v1.23.17
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl describe nodes | grep Taints  -A 2
Taints:             node-role.kubernetes.io/master:NoSchedule
Unschedulable:      false
Lease:
--
Taints:             <none>
Unschedulable:      false
Lease:
--
Taints:             node.kubernetes.io/unschedulable:NoSchedule
Unschedulable:      true
Lease:
[root@master231 scheduler-pods]# 

		2.4 取消节点不可调度 
[root@master231 scheduler-pods]# kubectl uncordon worker233 
node/worker233 uncordoned
[root@master231 scheduler-pods]# 
[root@master231 scheduler-pods]# kubectl get nodes
NAME        STATUS   ROLES                  AGE    VERSION
master231   Ready    control-plane,master   6d5h   v1.23.17
worker232   Ready    <none>                 6d4h   v1.23.17
worker233   Ready    <none>                 6d4h   v1.23.17
[root@master231 scheduler-pods]# 

		2.5 扩大Pod副本数量测试验证worker233节点是否正常工作
[root@master231 scheduler-pods]# kubectl edit deployments.apps scheduler-taints-tolerations 

节点下线

  1. 驱逐节点上的 Pod

    kubectl drain <node-name> --ignore-daemonsets
    
    • 示例:
      kubectl drain worker233 --ignore-daemonsets
      
  2. 停止 kubelet 组件

    systemctl disable --now kubelet
    
  3. 重置节点

    kubeadm reset -f
    
  4. 清理残留文件

    rm -rf /etc/cni/net.d/
    ipvsadm --clear
    rm -f $HOME/.kube/config
    
  5. 重启系统

    init 0
    
  6. 从 Master 节点移除下线的节点信息

    kubectl delete nodes <node-name>
    
    • 示例:
      kubectl delete nodes worker233
      

节点的下线和上线流程

(1)节点下线

  1. 驱逐节点上的 Pod

    kubectl drain worker233 --ignore-daemonsets
    
  2. 标记节点不可调度

    kubectl cordon worker233
    
  3. 停止 kubelet 组件

    systemctl disable --now kubelet
    
  4. 重置节点

    kubeadm reset -f
    
  5. 清理残留文件

    rm -rf /etc/cni/net.d/
    ipvsadm --clear
    rm -f $HOME/.kube/config
    
  6. 重启系统

    init 0
    
  7. 从 Master 节点移除下线的节点信息

    kubectl delete nodes worker233
    

(2)节点上线

  1. 标记节点可调度

    kubectl uncordon worker233
    
  2. 验证节点状态

    kubectl get nodes
    

节点加入集群

(1)在 Master 节点生成 token

kubeadm token create <token-name> --ttl 0 --print-join-command
  • 示例:
    kubeadm token create  --print-join-command
    

(2)在 Worker 节点加入集群

kubeadm join <master-ip>:6443 --token <token-name> --discovery-token-ca-cert-hash sha256:<hash>
  • 示例:
    kubeadm join 10.0.0.231:6443 --token oldboy.cmyjason --discovery-token-ca-cert-hash sha256:72f9bf97faf36b7448822d2c32717cd9eb90b08020e76b8d415d187ed6d954be
    

(3)在 Master 节点验证节点是否加入成功

kubectl get nodes

总结

  • 污点(Taints):用于标记节点,防止某些 Pod 调度到该节点。
  • 容忍(Tolerations):允许 Pod 调度到带有特定污点的节点。
  • 驱逐(Drain):将节点上的 Pod 驱逐到其他节点,通常用于节点维护或下线。
  • 节点下线和上线:通过标记节点不可调度、驱逐 Pod、停止 kubelet 组件、重置节点等步骤完成节点的下线和上线操作。
  • 节点加入集群:通过生成 token 和加入命令,将 Worker 节点加入 Kubernetes 集群。

8.10 亲和性

1.affinity概述

affinity的作用就是让Pod按照我们的日常需求进行倾向性调度。
affinity有三种实现方式:
nodeAffinity
让Pod更加倾向于哪些节点进行调度。
其功能和nodeSelector类似,但更加灵活。
podAffinity
可以基于拓扑域进行调度,当第一个Pod调度到该拓扑域后,则后续的所有Pod都会往该拓扑域调度。

	为了方便大家理解,此处的拓扑域可以暂时理解为'机房'。

podAntiAffinity
和podAntiAffinity相反,,当第一个Pod调度到该拓扑域后,则后续的所有Pod都不会往该拓扑域调度。

9.1 nodeAffinity实战案例

[root@master-231 ~]# kubectl get nodes --show-labels |grep class
master-231   Ready    control-plane,master   6d22h   v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,school=oldboyedu
worker232    Ready    <none>                 6d22h   v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233    Ready    <none>                 16h     v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=CMY,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux


 cat 08-nodeAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-text-nodeaffinity
spec:
  replicas: 5
  selector:
    matchLabels:
      apps: text
  template:
    metadata:
      labels:
        apps: text
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
             nodeSelectorTerms:
             - matchExpressions:
               - key: class
                 values:
                 - cmy
                 - CMY
                 # 声明key和values之间的关系,有效值为: In, NotIn, Exists, DoesNotExist. Gt, and Lt.
                 operator: In
      tolerations:
      - operator: Exists
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
        name: c1


[root@master-231 /oldboyedu/manifests/scheduler]# kubectl apply -f 08-nodeAffinity.yaml
deployment.apps/deploy-text-nodeaffinity created
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl get pods -o wide
NAME                                         READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
deploy-text-nodeaffinity-9c478f9c-fjnxm   1/1     Running   0          10s   10.100.140.68    worker233    <none>           <none>
deploy-text-nodeaffinity-9c478f9c-fnpd8   1/1     Running   0          10s   10.100.209.42    master-231   <none>           <none>
deploy-text-nodeaffinity-9c478f9c-k2jmh   1/1     Running   0          10s   10.100.203.134   worker232    <none>           <none>
deploy-text-nodeaffinity-9c478f9c-kknnr   1/1     Running   0          10s   10.100.203.137   worker232    <none>           <none>
deploy-text-nodeaffinity-9c478f9c-nc94x   1/1     Running   0          10s   10.100.140.67    worker233    <none>           <none>


可以发现,与nodeselector对比,nodeAffinity更加灵活,可以调度节点到相同key不同value标签的节点

8.11 podAffinity实战案例

kubectl get nodes --show-labels | grep dc
master-231   Ready    control-plane,master   6d22h   v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=beijing,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,school=oldboyedu
worker232    Ready    <none>                 6d22h   v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=shanghai,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233    Ready    <none>                 17h     v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=CMY,dc=shenzhen,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux

 cat 09-podAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-text-podaffinity
spec:
  replicas: 5
  selector:
    matchLabels:
      apps: text
  template:
    metadata:
      labels:
        apps: text
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            # 指定拓扑域
          - topologyKey: dc
            # 匹配对应的Pod
            labelSelector:
              matchLabels:
                apps: text
      tolerations:
      - operator: Exists
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
        name: c1

kubectl apply -f 09-podAffinity.yaml
deployment.apps/deploy-text-podaffinity created

kubectl get pods -o wide
NAME                                         READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
deploy-text-podaffinity-9b4c679ff-5qxmc   1/1     Running   0          8s    10.100.140.73   worker233   <none>           <none>
deploy-text-podaffinity-9b4c679ff-5s8fr   1/1     Running   0          8s    10.100.140.72   worker233   <none>           <none>
deploy-text-podaffinity-9b4c679ff-kj5xd   1/1     Running   0          8s    10.100.140.69   worker233   <none>           <none>
deploy-text-podaffinity-9b4c679ff-lsns6   1/1     Running   0          8s    10.100.140.71   worker233   <none>           <none>
deploy-text-podaffinity-9b4c679ff-qjfwz   1/1     Running   0          8s    10.100.140.70   worker233   <none>           <none>


8.11 podAntiAffinity实战案例

 kubectl get nodes --show-labels | grep dc
master-231   Ready    control-plane,master   6d22h   v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=beijing,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,school=oldboyedu
worker232    Ready    <none>                 6d22h   v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=shanghai,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233    Ready    <none>                 17h     v1.23.17   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=CMY,dc=shenzhen,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux

 cat 10-podAntiAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-text-podantiaffinity
spec:
  replicas: 5
  selector:
    matchLabels:
      apps: text
  template:
    metadata:
      labels:
        apps: text
    spec:
      affinity:
        # 定义Pod的反亲和性
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: dc
            labelSelector:
              matchLabels:
                apps: text
      tolerations:
      - operator: Exists
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
        name: c1

kubectl apply -f 10-podAntiAffinity.yaml
deployment.apps/deploy-text-podantiaffinity created
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl get pods -o wide
NAME                                              READY   STATUS              RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
deploy-text-podantiaffinity-64597f4865-2fcf4   1/1     Running             0          2s    10.100.140.74    worker233    <none>           <none>
deploy-text-podantiaffinity-64597f4865-7lptf   0/1     Pending             0          2s    <none>           <none>       <none>           <none>
deploy-text-podantiaffinity-64597f4865-q7pcf   1/1     Running             0          2s    10.100.203.188   worker232    <none>           <none>
deploy-text-podantiaffinity-64597f4865-qq79z   0/1     Pending             0          2s    <none>           <none>       <none>           <none>
deploy-text-podantiaffinity-64597f4865-zw488   0/1     ContainerCreating   0          2s    <none>           master-231   <none>           <none>

8.11 nodeselector和nodeAffinity对比

在 Kubernetes 中,nodeSelectorNode Affinity 都用于控制 Pod 的调度位置,但它们在功能和使用方式上有显著区别。以下是两者的详细对比:


​1. 功能对比​

特性 nodeSelector Node Affinity
​基本功能​ 根据节点标签选择目标节点 基于节点标签的复杂规则(支持逻辑组合)
​灵活性​ 仅支持简单的键值匹配 支持 InNotInExistsDoesNotExist 等复杂条件
​逻辑组合​ 不支持多个条件的组合(OR/AND) 支持通过 matchExpressions 实现复杂逻辑
​软性规则​ 仅支持硬性规则(必须匹配) 支持软性规则(PreferredDuringScheduling
​动态更新​ 需手动修改 Pod 的 nodeSelector 可通过配置动态调整规则

​2. 语法对比​

​(1) nodeSelector

  • ​语法简单​​,仅支持键值匹配:

    spec:
      nodeSelector:
        disktype: ssd
    
  • ​硬性规则​​:Pod 必须调度到标签完全匹配的节点,否则调度失败。

​(2) Node Affinity

  • ​支持复杂规则​​,例如:

    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: disktype
              operator: In
              values:
              - ssd
            - key: region
              operator: NotIn
              values:
              - us-west
        preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
            - key: env
              operator: In
              values:
              - production
    
  • ​支持逻辑组合​​:

    • matchExpressions 可以组合多个条件(AND 关系)。
    • nodeSelectorTerms 是 OR 关系(满足任意一个即可)。
  • ​软性规则​​:

    • preferredDuringScheduling 允许设置权重(weight),调度器会优先满足高权重的规则。

​3. 使用场景对比​

场景 nodeSelector Node Affinity
​简单标签匹配​ ✅ 适合(如 disktype=ssd ⚠️ 可用,但过于复杂
​多条件组合​ ❌ 不支持 ✅ 支持(如 disktype=ssd AND region!=us-west
​软性调度偏好​ ❌ 不支持 ✅ 支持(如优先调度到 env=production 的节点)
​动态调整规则​ ❌ 需手动修改 Pod ✅ 可通过 ConfigMap 或 Operator 动态更新

​4. 兼容性与演进​

  • nodeSelector​ 是早期功能,简单但功能有限。
  • Node Affinity​ 是后续引入的增强版,兼容 nodeSelector 的功能(可通过简单规则实现相同效果),并提供了更强大的能力。
  • ​推荐​​:在新项目中优先使用 Node Affinity,除非需求非常简单。

​5. 如何选择?​

  • ​使用 nodeSelector 如果​​:
    • 只需简单的标签匹配(如 env=prod)。
    • 不需要复杂的逻辑组合或软性规则。
  • ​使用 Node Affinity 如果​​:
    • 需要多条件组合(如 disktype=ssd AND region!=us-west)。
    • 需要软性规则(如优先调度到高性能节点,但不强制)。
    • 需要动态调整调度策略。

​6. 示例对比​

​(1) 简单场景(nodeSelector 足够)​

# 使用 nodeSelector
spec:
  nodeSelector:
    disktype: ssd

等价于:

# 使用 Node Affinity 的简单形式
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: disktype
          operator: In
          values:
          - ssd

​(2) 复杂场景(必须用 Node Affinity)​

# 需求:调度到 disktype=ssd 且 region!=us-west 的节点,优先选择 env=production 的节点
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: disktype
          operator: In
          values:
          - ssd
        - key: region
          operator: NotIn
          values:
          - us-west
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: env
          operator: In
          values:
          - production

9 HPA!!!

1.什么是hpa
hpa是k8s集群内置的资源,全称为"HorizontalPodAutoscaler"。

可以自动实现Pod水平伸缩,说白了,在业务高峰期可以自动扩容Pod副本数量,在集群的低谷期,可以自动缩容Pod副本数量。

9.1 验证水平伸缩


		2.1 创建Pod
[root@master231 horizontalpodautoscalers]# cat 01-deploy-hpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-stress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: stress
  template:
    metadata:
      labels:
        app: stress
    spec:
      containers:
      # - image: jasonyin2020/oldboyedu-linux-tools:v0.1
      - image: harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1
        name: oldboyedu-linux-tools
        args:
        - tail
        - -f
        - /etc/hosts
        resources: 
          requests:
            cpu: 0.2
            memory: 300Mi
          limits:
            cpu: 0.5
            memory: 500Mi

---

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: stress-hpa
spec:
  maxReplicas: 5
  minReplicas: 2
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: deploy-stress
  targetCPUUtilizationPercentage: 95
[root@master231 horizontalpodautoscalers]# 
[root@master231 horizontalpodautoscalers]# kubectl apply -f 01-deploy-hpa.yaml 
deployment.apps/deploy-stress created
horizontalpodautoscaler.autoscaling/stress-hpa created
[root@master231 horizontalpodautoscalers]# 


 
		2.2 测试验证
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide  # 第一次查看发现Pod副本数量只有1个
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS              IMAGES                                                                  SELECTOR
deployment.apps/deploy-stress   1/1     1            1           11s   oldboyedu-linux-tools   harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1   app=stress

NAME                                             REFERENCE                  TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/stress-hpa   Deployment/deploy-stress   <unknown>/95%   2         5         0          11s

NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod/deploy-stress-5d7c796c97-rzgsm   1/1     Running   0          11s   10.100.140.121   worker233   <none>           <none>
[root@master231 horizontalpodautoscalers]# 
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide  # 第N次查看发现Pod副本数量只有2个
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS              IMAGES                                                                  SELECTOR
deployment.apps/deploy-stress   2/2     2            2           51s   oldboyedu-linux-tools   harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1   app=stress

NAME                                             REFERENCE                  TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/stress-hpa   Deployment/deploy-stress   0%/95%    2         5         2          51s

NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod/deploy-stress-5d7c796c97-f9rff   1/1     Running   0          36s   10.100.203.150   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-rzgsm   1/1     Running   0          51s   10.100.140.121   worker233   <none>           <none>
[root@master231 horizontalpodautoscalers]# 



彩蛋:(响应式创建hpa)
[root@master231 horizontalpodautoscalers]# kubectl autoscale deploy deploy-stress --min=2 --max=5 --cpu-percent=95  -o yaml --dry-run=client




		2.3 压力测试
[root@master231 ~]# kubectl exec deploy-stress-5d7c796c97-f9rff -- stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd




		2.4 查看Pod副本数量
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS              IMAGES                                                                  SELECTOR
deployment.apps/deploy-stress   3/3     3            3           4m3s   oldboyedu-linux-tools   harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1   app=stress

NAME                                             REFERENCE                  TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/stress-hpa   Deployment/deploy-stress   105%/95%   2         5         2          4m3s

NAME                                 READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
pod/deploy-stress-5d7c796c97-f9rff   1/1     Running   0          3m48s   10.100.203.150   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-rzgsm   1/1     Running   0          4m3s    10.100.140.121   worker233   <none>           <none>
pod/deploy-stress-5d7c796c97-zxgp6   1/1     Running   0          3s      10.100.140.122   worker233   <none>           <none>
[root@master231 horizontalpodautoscalers]# 
[root@master231 horizontalpodautoscalers]# 


		2.5 再次压测
[root@master231 ~]# kubectl exec deploy-stress-5d7c796c97-rzgsm  -- stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10m
stress: info: [6] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd

[root@master231 ~]# kubectl exec deploy-stress-5d7c796c97-zxgp6 -- stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd



		2.6 发现最多有5个Pod创建 
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS              IMAGES                                                                  SELECTOR
deployment.apps/deploy-stress   5/5     5            5           5m50s   oldboyedu-linux-tools   harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1   app=stress

NAME                                             REFERENCE                  TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/stress-hpa   Deployment/deploy-stress   249%/95%   2         5         5          5m50s

NAME                                 READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
pod/deploy-stress-5d7c796c97-dnlzj   1/1     Running   0          34s     10.100.203.180   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-f9rff   1/1     Running   0          5m35s   10.100.203.150   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-ld8s9   1/1     Running   0          19s     10.100.140.123   worker233   <none>           <none>
pod/deploy-stress-5d7c796c97-rzgsm   1/1     Running   0          5m50s   10.100.140.121   worker233   <none>           <none>
pod/deploy-stress-5d7c796c97-zxgp6   1/1     Running   0          110s    10.100.140.122   worker233   <none>           <none>
[root@master231 horizontalpodautoscalers]# 
[root@master231 horizontalpodautoscalers]# 


		2.7 取消压测后
需要等待10min会自动缩容Pod数量到2个。


 
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS              IMAGES                                                                  SELECTOR
deployment.apps/deploy-stress   2/2     2            2           20m   oldboyedu-linux-tools   harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1   app=stress

NAME                                             REFERENCE                  TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/stress-hpa   Deployment/deploy-stress   0%/95%    2         5         5          20m

NAME                                 READY   STATUS        RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod/deploy-stress-5d7c796c97-dnlzj   1/1     Running       0          15m   10.100.203.180   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-f9rff   1/1     Running       0          20m   10.100.203.150   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-ld8s9   1/1     Terminating   0          14m   10.100.140.123   worker233   <none>           <none>
pod/deploy-stress-5d7c796c97-rzgsm   1/1     Terminating   0          20m   10.100.140.121   worker233   <none>           <none>
pod/deploy-stress-5d7c796c97-zxgp6   1/1     Terminating   0          16m   10.100.140.122   worker233   <none>           <none>
[root@master231 horizontalpodautoscalers]# 
[root@master231 horizontalpodautoscalers]# 
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS              IMAGES                                                                  SELECTOR
deployment.apps/deploy-stress   2/2     2            2           21m   oldboyedu-linux-tools   harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1   app=stress

NAME                                             REFERENCE                  TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/stress-hpa   Deployment/deploy-stress   0%/95%    2         5         2          21m

NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod/deploy-stress-5d7c796c97-dnlzj   1/1     Running   0          16m   10.100.203.180   worker232   <none>           <none>
pod/deploy-stress-5d7c796c97-f9rff   1/1     Running   0          21m   10.100.203.150   worker232   <none>           <none>
[root@master231 horizontalpodautoscalers]# 



10 pod健康检查

[[pod探针probe]]

11 Pod的优雅终止及容器的生命周期postStart和preStop

root@master231 pods]# cat 16-pods-lifecycle-postStart-preStop.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-poststart-prestop-001
spec:
  volumes:
  - name: data
    hostPath:
      path: /oldboyedu-linux
  # 在pod优雅终止时,定义延迟发送kill信号的时间,此时间可用于pod处理完未处理的请求等状况。
  # 默认单位是秒,若不设置默认值为30s。
  # terminationGracePeriodSeconds: 60
  terminationGracePeriodSeconds: 3
  containers:
  - name: c1
    image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
    volumeMounts:
    - name: data
      mountPath: /data
    # 定义容器的生命周期。
    lifecycle:
      # 容器启动(command)之后做的事情,如果此函数未执行完成,容器始终处于:' ContainerCreating'状态。
      postStart:
        exec:
          # command:  ["tail","-f","/etc/hosts"]
          command: 
          - "/bin/sh"
          - "-c"
          - "sleep 30;echo \"postStart at $(date +%F_%T)\" >> /data/postStart.log"
      # 容器停止之前做的事情,这个时间受限于: terminationGracePeriodSeconds 
      preStop:
        exec:
         command: 
         - "/bin/sh"
         - "-c"
         - "sleep 20;echo \"preStop at $(date +%F_%T)\" >> /data/preStop.log"
[root@master231 pods]# 

上一篇
下一篇