K8s学习笔记(二) Pod入门与实战
1 K8s核心资源Pod
1.1 Pod是什么?
官方文档:Pod | Kubernetes
Pod 是 Kubernetes(k8s)中最小的部署与调度单元,并非直接运行容器,而是对一个或多个 “紧密关联” 容器的封装。
核心特点可简单总结为 3 点:
- 容器的 “组合包”:通常包含 1 个主容器(业务核心,如 Web 服务),也可包含辅助容器(如日志收集、监控代理),所有容器共享 Pod 的资源。
- 共享基础环境:同一 Pod 内的容器共享网络命名空间(用
localhost
就能互相通信,无需跨网络)和存储卷(可共用文件目录),相当于 “在同一台迷你主机上运行”。 - 短暂且被管理:Pod 本身是 “一次性” 的(故障、重启后会生成新 Pod,IP 会变),不会自行修复,需依赖 k8s 的控制器(如 Deployment、StatefulSet)来管理其创建、扩缩容和故障恢复。
白话解释:
可以把 pod 看成是一个“豌豆荚”,里面有很多“豆子”(容器)。一个豌豆荚里的豆子,它们吸收着 共同的营养成分、肥料、水分等,Pod 和容器的关系也是一样,Pod 里面的容器共享 pod 的网络、存储等。
1.1.1 Pod如何管理多个容器
在 Kubernetes 中,Pod 管理多个容器的核心逻辑是 “协同调度、资源共享、生命周期绑定”,具体通过以下方式实现:
-
共享基础环境
同一 Pod 内的所有容器共享网络命名空间(相同的 IP 地址、端口空间)和存储卷(Volume):- 网络:容器间可通过
localhost
直接通信(如localhost:8080
访问同一 Pod 内的另一个容器),但需注意端口不冲突;对外表现为一个整体,共享 Pod 的 IP。 - 存储:Pod 中定义的 Volume(如临时目录
emptyDir
、持久化存储PersistentVolume
)可被所有容器挂载,实现数据共享(如日志容器读取主容器产生的日志文件)。
- 网络:容器间可通过
-
生命周期绑定
多个容器的生命周期与 Pod 强绑定:- 同时调度:Pod 被调度到某个节点后,其内所有容器会在同一节点启动。
- 整体管理:Pod 删除时,所有容器同时终止;Pod 重启(如节点故障重建)时,所有容器重新创建。
- 重启策略统一:Pod 通过
restartPolicy
(如Always
、OnFailure
)定义容器故障时的重启规则,适用于所有容器。
-
启动与依赖控制
若容器间有启动顺序或依赖关系,可通过以下机制控制:- Init 容器:在应用容器启动前运行的 “初始化容器”,完成前置任务(如配置加载、依赖检查),所有 Init 容器成功退出后,应用容器才会启动。
- 探针(Probe):通过
livenessProbe
(存活探针)、readinessProbe
(就绪探针)检测容器状态,确保容器按预期运行后再对外提供服务。
-
资源隔离与分配
每个容器可单独设置资源请求(resources.requests
)和限制(resources.limits
),Pod 会汇总这些需求向 Kubernetes 申请资源,确保容器间资源使用不冲突(如避免某容器耗尽内存影响其他容器)。
1.1.2 Pod网络
Pod 网络核心可总结为:
- 每个 Pod 有唯一集群内 IP,作为其网络身份;
- 同一 Pod 内容器共享网络命名空间,通过
localhost
直接通信; - 集群内 Pod 间可直接用 IP 互通(无 NAT),依赖 CNI 插件实现跨节点通信;
- Pod 访问外部靠节点 SNAT,外部访问 Pod 需通过 Service 作为稳定入口。
1.1.3 Pod存储
创建 Pod 的时候可以指定挂载的存储卷。 POD 中的所有容器都可以访问共享卷,允许这些容器共享数据。 Pod 只要挂载持久化数据卷,Pod 重启之后数据还是会存在的。
1.2 Pod工作方式
在 K8s 中,所有的资源都可以使用一个 yaml 文件来创建,创建 Pod 也可以使用 yaml 配置文件。或者使用 kubectl run 在命令行创建 Pod。
1.2.1 自主式 Pod
所谓的自主式 Pod,就是直接定义一个 Pod 资源,如下:
apiVersion: v1
kind: Pod
metadata:name: nginx-testnamespace: defaultlabels:app: nginx
spec:containers:- name: nginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresent# 更新资源清单
kubectl apply -f pod-nginx.yaml# 查看pod是否创建成功
kubectl get pods -o wide -l app=nginx
自主式Pod存在一个问题,加入不小心删除了Pod,那么就彻底被删除了,不会再创建一个新的Pod,这如果在生产环境中有非常大的风险,用控制器管理最好。
kubectl delete pods nginx-testkubectl get pods -l app=nginx
#结果为空说明pod已经被删除了
1.2.2 控制器管理的Pod
常见的管理 Pod 的控制器:Replicaset、Deployment、Job、CronJob、Daemonset、Statefulset。 控制器管理的 Pod 可以确保 Pod 始终维持在指定的副本数运行。 如,通过 Deployment 管理 Pod
vim nginx-deploy.yamlapiVersion: v1
kind: Deployment
metadata:name: nginx-testlabels:app: nginx-deploy
spec:selector:matchLabels:app: nginxreplicas: 2 # 副本数为2template:metadata:labels:app: nginx
spec:containers:- name: my-nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80# 更新资源清单文件
kubectl apply -f nginx-deploy.yaml# 查看Deployment
kubectl get deploy -l app=nginx-deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-test 2/2 2 2 16s#查看 Replicaset
kubectl get rs -l app=nginx
NAME DESIRED CURRENT READY AGE
nginx-test-75c685fdb7 2 2 2 71s#查看 pod
kubectl get pods -o wide -l app=nginx
NAME READY STATUS IP
nginx-test-85c885fdb7-6d4lx 1/1 Running 10.190.102.69
nginx-test-85c885fdb7-9s95h 1/1 Running 10.190.102.68#删除nginx-test-85c885fdb7-9s95h这个 podkubectl delete pods nginx-test-85c885fdb7-9s95h
kubectl get pods -o wide -l app=nginxNAME READY STATUS IP
nginx-test-85c885fdb7-6d4lx 1/1 Running 10.190.102.69
nginx-test-85c885fdb7-6s95h 1/1 Running 10.190.102.68# 发现重新创建了一个新的pod nginx-test-85c885fdb7-6s95h
通过上面可以发现通过 deployment 管理的 pod,可以确保 pod 始终维持在指定副本数量.
2 命名空间(namespace)
2.1 什么是命名空间?
在 Kubernetes 中,命名空间(Namespace)是用于对集群内资源进行逻辑隔离的机制,核心作用是在共享同一 K8s 集群的场景下,避免资源名称冲突、区分环境或团队,方便管理和权限控制。
核心特点:
-
资源隔离:同一命名空间内的资源名称必须唯一,但不同命名空间可以有同名资源(如两个命名空间都能有叫 “nginx” 的 Pod)。
-
环境 / 团队划分:通常用于隔离不同环境(如
dev
开发、test
测试、prod
生产)或不同团队的资源,避免互相干扰。 -
权限控制:可通过 RBAC(基于角色的访问控制)为不同命名空间设置独立的权限规则(如只允许某团队操作
dev
命名空间)。
常见默认命名空间:
-
default
:未指定命名空间时,资源默认创建于此。 -
kube-system
:K8s 系统组件(如 kube-proxy、调度器)所在的命名空间。 -
kube-public
:所有用户可见的公共资源(通常用于存储集群信息)。
简单说,命名空间就像集群内的 “虚拟分区”,让多场景共享集群时更有序。
2.2 namespace 应用场景
-
环境隔离:区分 dev(开发)、test(测试)、prod(生产)环境,避免相互干扰;
-
团队 / 项目隔离:为多团队 / 项目划分 “资源池”,防止资源名冲突与误操作;
-
资源配额控制:结合 ResourceQuota,限制各场景 / 团队的 CPU、内存等资源上限;
-
权限精细化控制:结合 RBAC,让不同角色仅能操作指定 Namespace 的资源,保障安全;
-
临时场景隔离:为实验、POC 等临时需求创建 Namespace,用完一键删除,清理高效。
核心是通过逻辑隔离,实现集群资源的有序管理与安全共享。
2.3 namespace 使用案例
# 创建一个命名空间
kubectl create ns test# 切换命名空间
kubectl config set-context --current --namespace=kube-system
# 切换了命名空间后,kubectl get pods 如果不指定-n,查看的就是kube-system命名空间的资源# 查看哪些资源属于命名空间级别的
kubectl api-resources --namespaced=true
2.4 namespace资源限额
kubectl config set-context --current -namespace=default# namespace 是命名空间,里面有很多资源,那么我们可以对命名空间资源做个限制,防止该命名空间
部署的资源超过限制。vim namespace-quota.yamlapiVersion: v1
kind: ResourceQuota
metadata: name: mem-cpu-quota namespace: test
spec: hard: requests.cpu: "2" requests.memory: 2Gi limits.cpu: "4" limits.memory: 4Gi
#创建的 ResourceQuota 对象将在 test 名字空间中添加以下限制:
每个容器必须设置内存请求(memory request),内存限额(memory limit),cpu 请求(cpu
request)和 cpu 限额(cpu limit)。
所有容器的内存请求总额不得超过 2GiB。
所有容器的内存限额总额不得超过 4 GiB。
所有容器的 CPU 请求总额不得超过 2 CPU。
所有容器的 CPU 限额总额不得超过 4CPU。
3 标签(Label)
3.1 什么是标签
标签是附加在对象(如 Pod、Node 等)上的键值对,用于标识、分类对象,可动态添加或修改。核心作用是通过标签选择器筛选、关联对象(如 Service 关联 Pod、Deployment 管理 Pod 等),是 K8s 中对象管理和关联的基础机制。
3.2 给pod资源打标签
给 Pod 打标签有两种方式:创建时指定标签,或为已存在的 Pod 添加 / 修改标签。
1. 创建 Pod 时指定标签(推荐)
apiVersion: v1
kind: Pod
metadata:name: my-podlabels: # 这里定义标签app: nginxenv: productionversion: v1
spec:containers:- name: nginximage: nginx:latest
创建 Pod:kubectl apply -f pod.yaml
2. 为已存在的 Pod 添加 / 修改标签
使用 kubectl label
命令:
# 给名为my-pod的Pod添加标签(如添加"team=backend")
kubectl label pods my-pod team=backend# 若标签已存在,需加--overwrite强制修改
kubectl label pods my-pod env=test --overwrite
3. 验证标签
# 查看Pod的标签
kubectl get pod my-pod --show-labels# 筛选带有特定标签的Pod(如app=nginx)
kubectl get pods -l app=nginx
标签可用于筛选 Pod、关联 Service/Deployment 等,是 K8s 对象管理的重要工具。
3.3 查看资源标签
在 Kubernetes 中,查看资源标签的常用方式是通过 kubectl
命令,支持查看单个资源、所有资源的标签,或筛选带有特定标签的资源。
1. 查看资源的所有标签(最常用)
使用 --show-labels
选项,可显示指定资源的所有标签:
# 查看所有 Pod 的标签
kubectl get pods --show-labels# 查看单个Pod的标签
kubectl get pods nginx-pod --show-labels# 查看所有 Node(节点) 的标签
kubectl get nodes --show-labels# 查看所有 Deployment 的标签
kubectl get deployment --show-labels
2. 筛选带有特定标签的资源
使用 -l
选项,可按标签筛选资源(支持 =
、!=
等条件):
# 查看标签为 app=nginx 的所有Pod
kubectl get pods -l app=nginx# 查看标签为 env!=production 的所有Pod
kubectl get pods -l env!=production# 查看同时带有 app=nginx和version=v1的所有Pod
kubectl get pods -l app=nginx,version=v1
3. 查看资源的详细标签信息
使用 describe
命令,可在资源详情的 Metadata.Labels
部分查看标签:
# 查看某个 Pod的详细信息(包含标签)
kubectl describe pod my-pod# 查看某个 Node 的详细信息(包含标签)
kubectl describe node node1
通过以上命令,可快速查看、筛选 Kubernetes 各类资源的标签,方便进行资源管理和关联操作。
4 Pod资源清单详细解读
Pod 资源清单(YAML/JSON 格式)是定义 Kubernetes Pod 运行规范的核心配置文件,包含了 Pod 的元数据、运行容器、资源需求、网络、存储等关键信息。以下是对 Pod 资源清单主要字段的详细解读(以 YAML 为例):
基础结构框架
一个完整的 Pod 清单通常包含 4 个顶级字段(缺一不可):
apiVersion: v1 # API 版本
kind: Pod # 资源类型
metadata: # 元数据(标识信息)...
spec: # 规格(核心配置,定义 Pod 如何运行)...
4.1 顶级字段
-
apiVersion: v1
指定 Kubernetes API 版本。Pod 是核心资源,稳定版本为v1
(其他资源可能有不同版本,如apps/v1
)。 -
kind: Pod
声明资源类型为 Pod(Kubernetes 中还有 Deployment、Service 等其他类型)。
4.2 metadata
:元数据(标识与属性)
用于唯一标识 Pod 并附加额外信息,常见字段:
metadata:name: my-pod # Pod 名称(必填,在命名空间内唯一,只能包含字母、数字、-、_、.)namespace: default # 所属命名空间(默认是 default,用于资源隔离,可选)labels: # 标签(键值对,用于筛选和关联其他资源,如 Service/Deployment)app: nginxenv: productionannotations: # 注解(键值对,用于存储非标识性元数据,如运维备注、工具配置)description: "This is a nginx pod"managed-by: "kubectl"uid: "xxxx-xxxx-xxxx" # 自动生成的唯一 ID(创建后由 K8s 分配,无需手动设置)
4.3 spec
:核心规格(定义 Pod 运行规则)
这是 Pod 配置的核心,包含容器、资源、网络、存储等关键信息。
4.3.1 容器配置(spec.containers
)
Pod 由一个或多个容器组成,containers
是必填列表,每个容器的配置如下:
spec:containers:- name: nginx-container # 容器名称(在 Pod 内唯一,必填)image: nginx:1.23 # 容器镜像(必填,格式:仓库地址/镜像名:标签,默认拉取 latest)imagePullPolicy: IfNotPresent # 镜像拉取策略(可选,默认 IfNotPresent)# - Always:每次都拉取镜像;# - IfNotPresent:本地有则用本地,否则拉取;# - Never:只使用本地镜像,不拉取ports: # 容器端口配置(可选,用于声明端口,不直接暴露到集群)- containerPort: 80 # 容器内监听的端口(必填,仅用于标识)hostPort: 8080 # 主机映射端口(可选,不推荐,可能导致端口冲突)protocol: TCP # 协议(默认 TCP,可选 UDP/SCTP)name: http # 端口名称(可选,用于区分多个端口)command: ["/bin/sh"] # 容器启动命令(可选,覆盖镜像默认命令)args: ["-c", "echo hello"] # 启动命令参数(可选,配合 command 使用)env: # 环境变量(可选,注入容器内的环境变量)- name: APP_ENV # 环境变量名称value: "production" # 直接设值- name: DB_PASSWORD # 从 Secret 中获取值(更安全)valueFrom:secretKeyRef:name: db-secret # Secret 名称key: password # Secret 中的键resources: # 资源需求与限制(可选,影响调度和资源分配)requests: # 申请的最小资源(调度时参考,确保节点有足够资源)cpu: "100m" # 100m = 0.1 CPU 核心memory: "128Mi" # 128 兆内存limits: # 资源上限(容器不能超过此限制,否则可能被终止)cpu: "500m"memory: "256Mi"volumeMounts: # 挂载存储卷(可选,将 spec.volumes 定义的存储挂载到容器内)- name: data-volume # 要挂载的卷名称(需与 spec.volumes 中名称一致)mountPath: /usr/share/nginx/html # 容器内挂载路径readOnly: false # 是否只读(默认 false)livenessProbe: # 存活探针(可选,检测容器是否"存活",失败则重启容器)httpGet:path: / # 探测路径port: 80 # 探测端口initialDelaySeconds: 5 # 容器启动后延迟多久开始探测(秒)periodSeconds: 10 # 探测间隔(秒,默认 10)readinessProbe: # 就绪探针(可选,检测容器是否"就绪",失败则从 Service 移除)httpGet:path: /readyport: 80initialDelaySeconds: 3periodSeconds: 5securityContext: # 容器级安全上下文(可选,如运行用户、权限)runAsUser: 1000 # 容器内进程的 UIDrunAsGroup: 3000 # 容器内进程的 GIDallowPrivilegeEscalation: false # 是否允许提权(默认 true)
4.3.2 初始化容器(spec.initContainers
)
在应用容器(containers
)启动前运行的容器,用于初始化工作(如拉取配置、等待依赖),执行完后退出(必须成功退出,否则 Pod 卡在 Init
状态)。配置格式与 containers
一致:
spec:initContainers:- name: init-configimage: busybox:1.35command: ["wget", "-O", "/config/index.html", "http://config-server/index"]volumeMounts:- name: data-volumemountPath: /config
4.3.3 存储卷(spec.volumes
)
定义 Pod 可使用的存储卷(供容器挂载),支持多种类型(如临时存储、主机路径、配置文件等):
spec:volumes:- name: data-volume # 卷名称(供 volumeMounts 引用)emptyDir: {} # 临时存储(Pod 生命周期内存在,删除后数据丢失)- name: host-path-volumehostPath: # 主机路径(挂载节点上的文件/目录,不推荐生产环境)path: /var/logtype: Directory- name: config-volumeconfigMap: # 挂载 ConfigMap(配置文件)name: nginx-config # ConfigMap 名称- name: secret-volumesecret: # 挂载 Secret(敏感信息,如密码)secretName: db-credentials
Pod 资源清单通过 metadata
定义标识信息,通过 spec
详细配置容器运行规则(包括镜像、资源、网络、存储、调度策略等)。理解这些字段是编写、调试 Pod 配置的基础,也是使用 Kubernetes 部署应用的核心技能。
4.3.4 调度与节点选择
控制 Pod 被调度到哪个节点:
spec:nodeSelector: # 节点选择器(简单匹配,仅支持等于)disk: ssd # 调度到带有 label "disk=ssd" 的节点affinity: # 亲和性规则(更灵活的调度策略)nodeAffinity: # 节点亲和性(倾向/必须调度到满足条件的节点)requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和性(必须满足)nodeSelectorTerms:- matchExpressions:- key: envoperator: Invalues: [production]preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性(优先满足)- weight: 100preference:matchExpressions:- key: zoneoperator: Invalues: [zone-1]podAntiAffinity: # Pod 反亲和性(避免与特定 Pod 调度到同一节点)preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues: [database]topologyKey: "kubernetes.io/hostname" # 按节点隔离tolerations: # 污点容忍(允许 Pod 调度到有特定污点的节点)- key: "node-type"operator: "Exists"effect: "NoSchedule"
5 节点选择器(nodeSelector)
在 Kubernetes 中,节点选择器(nodeSelector) 是一种简单的调度策略,用于将 Pod 限制在具有特定标签的节点上运行。它通过匹配节点的标签(Labels)来实现 Pod 与节点的绑定,是最基础的节点调度方式。
核心作用
让 Pod 只能被调度到拥有指定标签的节点上,确保 Pod 运行在符合预期的节点(如特定硬件、环境或功能的节点)。
5.1 为节点添加标签
首先需要给目标节点打上特定标签(若已有标签可跳过):
# 语法:kubectl label nodes <节点名称> <标签键>=<标签值>
kubectl label nodes node-1 env=production # 给节点 node-1 打标签 env=production
kubectl label nodes node-2 hardware=gpu # 给节点 node-2 打标签 hardware=gpu
验证节点标签:
kubectl get nodes --show-labels # 查看所有节点的标签
kubectl describe node node-1 | grep Labels # 查看单个节点的标签
5.2 在 Pod 中配置 nodeSelector
在 Pod 的资源清单中,通过 spec.nodeSelector
字段指定需要匹配的节点标签,Pod 会被调度到所有标签完全匹配的节点上。
apiVersion: v1
kind: Pod
metadata:name: my-pod
spec:containers:- name: nginximage: nginx:latestnodeSelector: # 节点选择器:仅调度到同时满足以下标签的节点env: production # 匹配标签 env=productionhardware: gpu # 匹配标签 hardware=gpu# 查看pod调度到哪个节点
kubectl get pods -o wideNAME READY STATUS RESTARTS
my-pod 1/1 Running 0 node2
创建 Pod 后,Kubernetes 调度器会自动将其分配到符合标签条件的节点。
特点与限制
- 优点:简单直观,适合基础的节点筛选场景。
- 限制:
- 仅支持精确匹配(标签键和值必须完全一致),不支持
!=
、In
、NotIn
等复杂逻辑。 - 是 “硬性要求”:如果没有匹配标签的节点,Pod 会一直处于
Pending
状态(调度失败)。
- 仅支持精确匹配(标签键和值必须完全一致),不支持
适用场景
- 将 Pod 调度到特定环境的节点(如
env=production
或env=test
)。 - 将需要特殊硬件的 Pod 调度到对应节点(如
hardware=gpu
或disk=ssd
)。
如果需要更灵活的调度策略(如 “优先调度到某类节点”“避免调度到某类节点” 等),可以使用 节点亲和性(Node Affinity) 替代 nodeSelector。
6 污点和容忍度
6.1 node 节点亲和性(Node Affinity)
在 Kubernetes 中,节点亲和性(Node Affinity) 是一种比 nodeSelector
更灵活的 Pod 调度策略,用于根据节点的标签(Labels)控制 Pod 被调度到哪些节点上。它支持更复杂的匹配逻辑(如 “包含”“不包含”“存在” 等),并分为 “硬性要求” 和 “软性偏好” 两种类型,满足不同调度场景的需求。
核心作用
让 Pod 按照自定义规则 “主动选择” 合适的节点(基于节点标签),既可以强制要求必须满足某些条件,也可以优先选择符合条件的节点(不强制)。
节点亲和性的两种类型
节点亲和性通过 spec.affinity.nodeAffinity
配置,分为以下两种:
类型 | 关键字 | 含义 | 特点 |
---|---|---|---|
硬亲和性 | requiredDuringSchedulingIgnoredDuringExecution | 必须满足的条件,否则 Pod 无法调度(一直处于 Pending 状态) | 强制约束,类似 “我必须吃饭,不吃饭就会饿” |
软亲和性 | preferredDuringSchedulingIgnoredDuringExecution | 优先满足的条件,不满足也可以调度到其他节点 | 柔性偏好,类似 “最好是现在吃饭,晚一点吃也没事” |
匹配表达式(Operator)
节点亲和性通过 matchExpressions
定义匹配规则,支持多种操作符(比 nodeSelector
更灵活):
操作符 | 含义 | 示例 |
---|---|---|
In | 节点标签的值必须在指定列表中 | key: "env" , values: ["prod", "test"] → 匹配 env=prod 或 env=test |
NotIn | 节点标签的值必须不在指定列表中 | key: "env" , values: ["dev"] → 不匹配 env=dev |
Exists | 节点必须存在指定标签(不校验值) | key: "gpu" → 只要节点有 gpu 标签(无论值是什么) |
DoesNotExist | 节点必须不存在指定标签 | key: "disk" → 节点不能有 disk 标签 |
Gt | 节点标签的值(数字)必须大于指定值 | key: "cpu-cores" , values: ["4"] → 匹配 cpu-cores>4 |
Lt | 节点标签的值(数字)必须小于指定值 | key: "memory-gb" , values: ["32"] → 匹配 memory-gb<32 |
配置示例
假设需要将 Pod 调度到 “生产环境(env=prod
)的节点,且优先选择 SSD 磁盘(disk=ssd
)的节点”,配置如下:
apiVersion: v1
kind: Pod
metadata:name: affinity-pod
spec:containers:- name: nginximage: nginx:latestaffinity: # 亲和性配置nodeAffinity:# 硬亲和性:必须满足的条件requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms: # 多个条件组(满足任意一组即可)- matchExpressions: # 条件组内的多个表达式(需同时满足)- key: envoperator: Invalues: ["prod"] # 节点必须有 env=prod 标签# 软亲和性:优先满足的条件preferredDuringSchedulingIgnoredDuringExecution:- weight: 100 # 权重(0-100,数值越大优先级越高)preference:matchExpressions:- key: diskoperator: Invalues: ["ssd"] # 优先选择 disk=ssd 的节点
- 硬亲和性确保 Pod 只能调度到
env=prod
的节点(不满足则无法调度); - 软亲和性让调度器在满足硬亲和性的节点中,优先选择
disk=ssd
的节点(若无则选择其他env=prod
节点)。
与其他调度策略的区别
策略 | 特点 | 适用场景 |
---|---|---|
nodeSelector | 仅支持精确匹配(key=value ) | 简单的标签匹配场景 |
节点亲和性 | 支持复杂匹配(In /Exists 等),分硬 / 软亲和性 | 需灵活条件的调度(如 “必须在生产环境,优先用 SSD”) |
污点(Taints)+ 容忍度(Tolerations) | 节点主动排斥 Pod,Pod 需 “容忍” 才能被调度 | 节点隔离(如 “GPU 节点只允许 AI 任务调度”) |
典型使用场景
- 环境隔离:强制 Pod 只能在
env=prod
节点运行(硬亲和性)。 - 资源偏好:优先将计算密集型 Pod 调度到
cpu=high
的节点(软亲和性)。 - 硬件依赖:必须将需要 GPU 的 Pod 调度到
gpu=true
的节点(硬亲和性)。
节点亲和性通过灵活的匹配规则和软硬约束,让 Pod 调度更符合实际业务需求,是 Kubernetes 中控制节点选择的核心机制之一。
6.2 Pod节点亲和性(Pod Affinity)
在 Kubernetes 中,Pod 亲和性(Pod Affinity) 是一种基于已运行 Pod 的标签来调度新 Pod 的策略。它用于控制新 Pod 与集群中已存在的 Pod 之间的 “位置关系”—— 即新 Pod 应该和哪些 Pod 调度到同一位置(亲和),或应该远离哪些 Pod(反亲和)。
与 “节点亲和性(Node Affinity)” 基于节点标签调度不同,Pod 亲和性基于其他 Pod 的标签调度,更适合控制服务之间的关联关系(如 “前端 Pod 和后端 Pod 尽量在同一节点”“数据库 Pod 尽量分散在不同节点”)。
核心概念
- Pod 亲和性(Pod Affinity):新 Pod 倾向于与 “具有特定标签的已有 Pod” 调度到同一拓扑域(如同一节点、同一机房等)。
- Pod 反亲和性(Pod Anti-Affinity):新 Pod 倾向于与 “具有特定标签的已有 Pod” 调度到不同拓扑域,避免集中部署。
拓扑域(Topology Domain):通过 topologyKey
定义,通常是节点的标签(如 kubernetes.io/hostname
表示 “同一节点”,topology.kubernetes.io/zone
表示 “同一可用区”),用于划分 “位置范围”。
类型与配置
Pod 亲和性 / 反亲和性也分为 “硬性要求” 和 “软性偏好” 两种类型,配置位于 spec.affinity.podAffinity
或 spec.affinity.podAntiAffinity
字段:
类型 | 关键字 | 含义 |
---|---|---|
硬约束 | requiredDuringSchedulingIgnoredDuringExecution | 必须满足条件,否则 Pod 无法调度 |
软约束 | preferredDuringSchedulingIgnoredDuringExecution | 优先满足条件,不满足也可调度到其他位置 |
匹配规则
通过 labelSelector
匹配目标 Pod 的标签,语法与节点亲和性类似,支持 In
/NotIn
/Exists
等操作符。
配置示例
1. Pod 亲和性(让新 Pod 与目标 Pod 在同一节点)
需求:新的 frontend
Pod 尽量与已有的 app=backend
Pod 调度到同一节点(降低网络延迟)。
apiVersion: v1
kind: Pod
metadata:name: frontend-podlabels:app: frontend
spec:containers:- name: frontendimage: nginx:latestaffinity:podAffinity: # Pod 亲和性配置preferredDuringSchedulingIgnoredDuringExecution: # 软约束(优先满足)- weight: 80 # 权重(0-100)podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues: ["backend"] # 匹配标签为 app=backend 的已有 PodtopologyKey: "kubernetes.io/hostname" # 拓扑域:同一节点(按主机名划分)
2. Pod 反亲和性(让新 Pod 与目标 Pod 不在同一节点)
需求:新的 db
Pod 必须与其他 app=db
Pod 调度到不同节点(避免单点故障)。
apiVersion: v1
kind: Pod
metadata:name: db-pod-2labels:app: db
spec:containers:- name: dbimage: mysql:5.7affinity:podAntiAffinity: # Pod 反亲和性配置requiredDuringSchedulingIgnoredDuringExecution: # 硬约束(必须满足)- labelSelector:matchExpressions:- key: appoperator: Invalues: ["db"] # 匹配标签为 app=db 的已有 PodtopologyKey: "kubernetes.io/hostname" # 拓扑域:不同节点(按主机名划分)
- 若集群中已有
app=db
的 Pod 运行在节点 A,新的db-pod-2
会被调度到节点 B、C 等(不会再到节点 A)。 - 若所有节点都已有
app=db
的 Pod,新 Pod 会因不满足硬约束而处于Pending
状态。
关键参数:topologyKey
topologyKey
是节点的标签键,用于定义 “同一位置” 的范围,常见取值:
kubernetes.io/hostname
:同一节点(最常用)。topology.kubernetes.io/zone
:同一可用区。topology.kubernetes.io/region
:同一地域。
例如,topologyKey: "topology.kubernetes.io/zone"
表示 “亲和 / 反亲和范围是同一可用区”,而非同一节点。
适用场景
- 服务就近部署:前端与后端 Pod 用亲和性调度到同一节点,减少网络延迟。
- 高可用分散:数据库、缓存等核心组件用反亲和性分散到不同节点 / 可用区,避免单点故障。
- 资源隔离:不同团队的 Pod 用反亲和性调度到不同节点,避免资源竞争。
与节点亲和性的区别
特性 | 节点亲和性(Node Affinity) | Pod 亲和性(Pod Affinity) |
---|---|---|
依赖对象 | 节点的标签 | 其他 Pod 的标签 |
调度依据 | 节点本身的属性(如硬件、环境) | 已有 Pod 的分布位置 |
核心作用 | 让 Pod 选择符合条件的节点 | 让 Pod 与其他 Pod 保持特定位置关系 |
Pod 亲和性通过关联已有 Pod 的分布,实现更精细化的调度策略,是构建高可用、高性能集群的重要工具。
6.3 污点(Taints)
6.3.1 为什么需要污点?
假设有一个 Kubernetes 集群,里面有两类节点:
-
普通节点:只有 CPU,供一般应用使用;
-
特殊节点:带 GPU,专门给 AI 训练任务用。
如果不做任何限制,普通应用的 Pod 可能会被调度到 GPU 节点上,导致 GPU 资源被浪费(普通应用用不到 GPU)。
这时候就需要一种机制:让 GPU 节点 “主动拒绝” 普通 Pod,只允许 AI 任务的 Pod 进来。这种 “主动拒绝” 的规则,就是污点。
6.3.2 污点是什么?
污点是给节点(Node) 打上的 “排斥性标记”,格式是 key=value:effect
,由三部分组成:
-
key
:污点的名字(比如dedicated
、env
); -
value
:污点的具体值(比如gpu
、prod
,可选,可空); -
effect
:排斥的 “力度”,决定如何拒绝 Pod(核心!)。
重点:effect 的三种 “排斥力度”
effect 类型 | 通俗解释 | 例子场景 |
---|---|---|
NoSchedule | 不准新 Pod 进来,但已经在节点上的 Pod 可以继续运行。 | GPU 节点只允许新的 AI Pod 进来,老 Pod 不动 |
PreferNoSchedule | 尽量不让新 Pod 进来(非强制),如果实在没其他节点,也能进来。 | 某个节点性能较差,尽量不调度新 Pod,但不绝对禁止 |
NoExecute | 不准新 Pod 进来,且已经在节点上的旧 Pod 也会被赶走(如果旧 Pod 没 “通行证”)。 | 节点要维护了,先把上面的 Pod 赶走,再禁止新 Pod 进来 |
6.3.3 怎么操作污点?
1. 给节点添加污点
语法:kubectl taint nodes <节点名> <key>=<value>:<effect>
比如给名为 node-gpu-1
的节点添加一个 “禁止普通 Pod 调度” 的污点:
kubectl taint nodes node-gpu-1 dedicated=gpu:NoSchedule
含义:节点 node-gpu-1
现在有一个污点 dedicated=gpu:NoSchedule
,表示 “只允许能容忍这个污点的 Pod 调度进来”。
2. 查看节点的污点
想知道节点上有哪些污点,用 describe
命令:
kubectl describe node node-gpu-1 | grep Taints
如果看到 Taints: dedicated=gpu:NoSchedule
,说明污点添加成功。
3. 删除节点的污点
语法:在污点后面加一个 -
,比如删除上面添加的污点:
kubectl taint nodes node-gpu-1 dedicated=gpu:NoSchedule-
6.3.4 总结:污点的核心作用
污点是节点的 “主动防御机制”,通过 effect
控制对 Pod 的排斥力度:
-
NoSchedule
:挡新 Pod,保旧 Pod; -
NoExecute
:挡新 Pod,赶旧 Pod; -
PreferNoSchedule
:尽量挡新 Pod,不绝对。
配合容忍度,就能实现 “节点专用化”“环境隔离”“节点维护” 等场景,让集群资源调度更合理。
6.4 容忍度(Tolerations)
污点是节点的 “排斥规则”,但如果某个 Pod 确实需要用到这个节点(比如 AI 任务需要 GPU),就需要给 Pod 一个 “通行证”——容忍度(Tolerations)。
6.4.1 容忍度的配置
容忍度定义在 Pod 配置中,声明 “我能容忍节点的某个污点”。例如,给 AI 任务的 Pod 加一个容忍度,匹配节点的 dedicated=gpu:NoSchedule
污点:
apiVersion: v1
kind: Pod
metadata:name: ai-training-pod
spec:containers:- name: ai-workerimage: ai-training-imagetolerations: # 容忍度配置- key: "dedicated" # 匹配污点的 keyoperator: "Equal" # 精确匹配value: "gpu" # 匹配污点的 valueeffect: "NoSchedule" # 匹配污点的 effecttolerationSeconds: 30 # 仅对effect=NoExecute有效:被驱逐前的宽限期(秒)
1. key
:要 “容忍” 的污点的名字
必须和节点上污点的key
完全一致。比如节点污点是dedicated=gpu:NoSchedule
,那么容忍度的key
必须是dedicated
。
2. operator
:匹配方式(关键!)
有两种匹配方式,决定了容忍度如何匹配污点:
operator: "Equal"
:精确匹配。需要容忍度的value
和污点的value
完全一致(比如污点是dedicated=gpu
,容忍度value
必须是gpu
)。operator: "Exists"
:只要存在就匹配。不关心污点的value
是什么,只要节点有这个key
和effect
的污点,就允许调度(此时value
字段可以省略)。
3. value
:污点的值
只有当operator: "Equal"
时才需要填,且必须和节点污点的value
完全一致。如果operator: "Exists"
,可以不写value
。
4. effect
:要 “容忍” 的污点的排斥力度
必须和节点污点的effect
完全一致(NoSchedule
/PreferNoSchedule
/NoExecute
)。比如节点污点是NoSchedule
,容忍度的effect
也必须是NoSchedule
。
5. tolerationSeconds
:宽限期(仅用于NoExecute
)
当节点污点是NoExecute
(会驱逐没有容忍度的 Pod)时,这个字段表示:如果 Pod 有容忍度,会在多少秒后再被驱逐(给 Pod 留时间处理收尾工作)。默认不填的话,会立即驱逐。
6.4.2 实战示例:给 Pod 配置容忍度
假设节点node-gpu
有污点dedicated=gpu:NoSchedule
,配置两个 Pod 的容忍度,看看效果。
示例 1:用Equal
精确匹配
# ai-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: ai-pod
spec:containers:- name: ai-workerimage: tensorflow/tensorflow # 需要GPU的AI任务tolerations:- key: "dedicated" # 匹配污点的keyoperator: "Equal" # 精确匹配value: "gpu" # 匹配污点的valueeffect: "NoSchedule" # 匹配污点的effect
创建 Pod:kubectl apply -f ai-pod.yaml
结果:这个 Pod 会被正常调度到node-gpu
节点(因为容忍度完全匹配污点)。
示例 2:用Exists
简化匹配
如果节点污点的value
可能变化(比如有时是gpu
,有时是nvidia-gpu
),但key
始终是dedicated
,可以用Exists
匹配:
# ai-pod-simple.yaml
apiVersion: v1
kind: Pod
metadata:name: ai-pod-simple
spec:containers:- name: ai-workerimage: tensorflow/tensorflowtolerations:- key: "dedicated" # 只看key是否存在operator: "Exists" # 不关心valueeffect: "NoSchedule" # 匹配effect# 这里省略了value,因为Exists不需要
创建 Pod 后,无论节点污点的value
是gpu
还是nvidia-gpu
,这个 Pod 都能被调度到node-gpu
上。
反例:没有容忍度的 Pod
# normal-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: normal-pod
spec:containers:- name: nginximage: nginx # 普通应用,不需要GPU# 没有配置任何容忍度
创建 Pod 后,会发现它一直处于Pending
状态(调度失败),因为它没有 “通行证”,被node-gpu
的污点拒绝了。
6.4.3 容忍度的常见场景
-
访问专用节点:比如 GPU 节点、高性能计算节点,只有带容忍度的 Pod 才能使用。
-
节点维护时不被驱逐:如果节点加了
NoExecute
污点(用于维护),给需要持续运行的 Pod 配置容忍度,可以避免被驱逐。 -
灵活匹配动态污点:用
operator: "Exists"
可以匹配同一key
下不同value
的污点,减少配置复杂度。
6.4.4 总结:容忍度的核心逻辑
-
容忍度是 Pod 的 “通行证”,用来匹配节点的污点;
-
必须满足:
key
和effect
与污点完全一致; -
operator: Equal
需要value
也一致,operator: Exists
忽略value
; -
没有容忍度的 Pod,会被有对应污点的节点拒绝。
未完待续.............