1. 介绍说明
1.1 基础设施的变革
- 单机场景

单机(操作系统+app)--> 虚拟化(VM+OS+APP) --> 容器化(Container + APP)
- 集群场景 IAAS

- 集群场景 PAAS

-
Kubernetes优势
- 服务发现和负载均衡
- 存储编排(添加任何本地或云服务器)
- 自动部署和回滚
- 自动分配CPU/内存资源-弹性伸缩
- 自我修复
- Secrect和配置管理
- 开源
- 大规模(单个K8S集群为例)
- 节点数不超过5000
- 每个节点的Pod数量不超过110
- Pod总数不超过150000
- 容器总数不超过300000
-
历史
Borg(2003) -> Omega(2013) -> Kubernetes(2014)
- 不同公司使用K8S节点数

1.2 Kubernetes组件
| 组件类型 | 组件名称 | 主要职责 | 所在节点 |
|---|---|---|---|
| 控制平面 | kube-apiserver | 集群的统一请求入口,提供RESTful API,其他组件均通过其操作资源 | Master |
| (Master) | etcd | 集群的持久化存储,保存所有集群数据和状态 | Master |
| kube-scheduler | 负责调度 Pod 到合适的 Node 上 | Master | |
| kube-controller-manager | 运行控制器,确保集群的实际状态符合期望状态 | Master | |
| cloud-controller-manager | 与云厂商特定功能对接的控制器 | Master | |
| 节点组件 | kubelet | 在 Node 上运行的代理,管理 Pod 和容器的生命周期,确保它们健康运行 | Node (Worker) |
| (Node) | kube-proxy | 维护节点上的网络规则,实现 Service 的访问代理和负载均衡 | Node (Worker) |
| 容器运行时 (Container Runtime) | 负责运行容器(如 containerd, CRI-O) | Node (Worker) | |
| 附加组件 | CoreDNS / kube-dns | 为集群内部提供 DNS 服务和服务发现 | 通常作为 Pod 部署 |
| (Addons) | Ingress Controller | 提供 HTTP(S) 路由、负载均衡、SSL 终止等 | 通常作为 Pod 部署 |
| Dashboard | 提供基于 Web 的图形化集群管理界面 | 通常作为 Pod 部署 | |
| 网络插件 (CNI) | 为 Pod 提供网络连接和网络策略 | 通常作为 Pod 部署 |
1.3 Kubernetes内容简述
第一章.k8s介绍说明-k8s课程内容简述(同P1相同)_哔哩哔哩_bilibili
2. K8S安装前准备
2.1 Pod概念
容器组,最小的部署模块
- Pause容器特性
- Pod内部第一个启动的容器
- 初始化网格栈
- 挂载需要的存储卷
- 回收僵尸进程
- 其他容器特性
- 与Pause容器共享namespace(Network,PID,IPC)
2.2 k8s 网络
2.2.1 网络基本概念
- k8s网络模型
Kubernetes 的网络模型假定了所有 Pod 都在一个可以直接连通的扁平的网络空间中(pod之间可以通过ip访问),这在GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在而在私有云里搭建 Kubernetes 集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的 Docker 容器之间的互相访问先打通,然后运行 Kubernete
2.2.2 网络的原则
k8s 网络模型原则
- 在不使用网络地址转换(NAT)的情况下,集群中的 Pod 能够与任意其他 Pod 进行通信
- 在不使用网络地址转换(NAT)的情况下,在集群节点上运行的程序能与同一节点上的任何Pod 进行通信
- 每个 Pod 都有自己的 IP地址(IP-per-Pod),并且任意其他 Pod 都可以通过相同的这个地址访问它
2.2.3 CNI
- CNI介绍
借助 CNI(Container Network Interface) 标准,Kubernetes 可以实现容器网络问题的解决。通过插件化的方式来集成各种网络插件,实现集群内部网络相互通信,只要实现CNI标准中定义的核心接口操作(ADD,将容器添加到网络;DEL,从网络中删除一个容器;CHECK,检查容器的网络是否符合预期等)。CNI插件通常聚焦在容器到容器的网络通信。
- 默认 CNI
CNI的接口并不是指 HTTP,gRPC这种接口,CNI接口是指对可执行程序的调用(exec)可执行程序Kubernetes 节点默认的 CNI插件路径为/opt/cni/bin
- CNI 分类


- CNI 与K8S关系

- 插件对比-2023-11-20

2.2.4 网络区别:underlay 与overlay
-
underlay network(非封装网络)
- 现实的物理基础层网络设备
- underlay就是数据中心场景的基础物理设施,保证任何两个点路由可达,其中包含了传统的网络技术
-
overlay network(封装网络)
- 一个基于物理网络之上构建的逻辑网络
- overlay是在网络技术领域指的是一种网络架构上叠加的虚拟化技术模式
- overlay网络技术多种多样,一般采用TRILL, VxLan, GRE, NVGRE等隧道技术
2.2.5 calico网络插件
calico是一个纯三层的虚拟网络,它没有复用docker和docker0网桥,而是自己实现的,calico网络不对数据包进行额外封装,不需要NAT和端口映射
(1)架构

- Felix
- 管理网络接口
- 编写路由
- 编写ACL
- 报告状态
- bird(BGP Client)
- BGP Client通过BGP协议广播告诉剩余calico节点,从而实现网络互通
- confd
- 通过监听etcd以了解BGP配置和全局默认值的修改。confd根据ETCD中数据的更新,动态生成BIRD配置文件。当配置文件更改时,confd触发的BIRD重新加载新文件
(2)VXLAN
- 什么是VXLAN?
VXLAN,即 Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN 可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network)
基于三层的”二层“通信,层即 vxlan 包封装在 udp 数据包中,要求 udp 在 k8s 节点间三层可达;层即 vxlan 封包的源 mac 地址和目的 mac 地址是自己的 vxlan 设备 mac 和对端 vxlan 设备 mac 实现通讯。

- 配置方式
- name: CALICO_IPV4POOL_IPIPvalue: "Never"
- name: CALICO_IPV4POOL_VXLANvalue: "Always"
- name: CALICO_IPV6POOL_VXLANvalue: "Always"# calico_backend:"bird"
calico_backend: "vxlan"
# --bird-live
# --bird-ready
(3)IPIP
Linux原生内核支持
IPIP 隧道的工作原理是将源主机的IP数据包封装在一个新的 IP 数据包中,新的 IP 数据包的目的地址是隧道的另一端。在隧道的另一端,接收方将解封装原始 IP 数据包,并将其传递到目标主机。IPIP 隧道可以在不同的网络之间建立连接,例如在 IPv4 网络和 IPv6 网络之间建立连接。


-
数据包封包: 封包,在 tun10 设备上将 pod 发来的数据包的 mac 层去掉,留下ip 层封包。
外层数据包目的 ip 地址根据路由得到。 -
优点: 只要 k8s 节点间三层互通,可以跨网段,对主机网关路由没有特殊要求
-
缺点: 需要进行 IPIP 的数据包封包和解包会存在一定的性能损耗
-
配置
- name: CALICO_IPV4POOL_IPIPvalue: "Never"
- name: CALICO_IPV4POOL_VXLANvalue: "Always"
- name: CALICO_IPV6POOL_VXLANvalue: "Always"
(4)BGP
边界网关协议(Border Gateway Protocol,BGP) 是互联网上一个核心的去中心化自治路由协议。
它通过维护IP路由表或'前缀”表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单IP,BGP 机房的优点:服务器只需要设置一个IP地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。

-
数据包封包: 不需要进行数据包封包
-
优点: 不用封包解包,通过 BGP 协议可实现 pod 网络在主机间的三层可达
-
缺点:跨网段时,配置较为复杂网络要求较高,主机网关路由也需要充当 BGP Speaker。
-
配置方式
- name: CALICO_IPV4POOL_IPIPvalue: "Off"
- name: CALICO_IPV4POOL_VXLANvalue: "Never"
- name: CALICO_IPV6POOL_VXLANvalue: "Never"
3. K8S安装
3.1 基础网络结构说明
3.2 k8s集群安装
kubeadm特性
4. k8s 资源清单
4.1 什么是资源清单
在 Kubernetes 中,一切皆为资源,资源实例化后称为对象。资源清单(Resource Manifest)是用于定义和管理 Kubernetes 资源的配置文件,通常采用 YAML 或 [JSON 格式](https://so.csdn.net/so/search?q=JSON 格式&spm=1001.2101.3001.7020)编写,用于创建、更新或删除集群中的资源。
4.1.1 名称空间级别
(1) 工作负载型资源(workload):
- Pod:Kubernetes中最基本的可调度单位,可以包含一个或多个容器,共享存储和网络资源。
- ReplicaSet:确保集群中始终运行着指定数量的Pod副本,是Deployment的基础。
- Deployment:提供声明式的更新能力,用于管理应用的生命周期,包括滚动更新和回滚。
- StatefulSet:为有状态应用提供管理,确保每个Pod都有一个稳定的唯一标识和持久存储。
- DaemonSet:确保所有(或某些)节点上运行一个Pod的副本,常用于系统日志、监控等服务。
- Job:用于完成一次性任务的资源,确保Pod成功执行并完成其工作。
- CronJob:用于定时执行Jobs,类似于Linux的cron。
(2) 服务发现及负载均衡型资源(ServiceDiscovery LoadBalance)
- Service:定义应用的服务端点,用于在集群内部或外部访问应用。Service可以实现负载均衡和服务发现。
- Ingress:提供了外部访问集群内服务的路由规则,通常与负载均衡器或反向代理结合使用。
(3) 配置与存储型资源:
- Volume:持久化存储的抽象,可以被Pod使用,支持多种存储类型,如空目录、主机路径、云存储等。
- CSI:容器存储接口,允许Kubernetes与外部存储系统集成,支持广泛的存储解决方案。
(4) 特殊类型的存储卷:
- ConfigMap:用于存储非机密的配置数据,可以被Pod作为环境变量或文件挂载。
- Secret:用于存储敏感信息,如密码、SSH密钥、TLS证书等,加密存储并安全传递给Pod。
- Downward API:允许Pod访问自身和Pod的元数据,如Pod IP、节点名称、重启次数等
4.1.2 集群级资源
- Namespace:用于逻辑隔离资源,便于多租户和资源配额管理。
- Node:代表集群中的物理或虚拟机器,是Pod运行的实际环境。
- Role & ClusterRole:定义权限,用于RBAC(基于角色的访问控制)。
- RoleBinding & ClusterRoleBinding:将Role或ClusterRole绑定到用户或用户组,授予他们特定的权限。
4.1.3 元数据型资源
通过指标进行操作
- HPA (Horizontal Pod Autoscaler):根据CPU使用率或其他指标自动调整Pod副本的数量。
- PodTemplate:Pod的模板,用于创建具有相同配置的Pod。
- LimitRange:定义资源配额,限制Pod和容器能使用的资源量,如CPU、内存。
4.2 资源清单的编写
apiVersion: v1 # (1) group/apiVersion 接口组/版本 ,Pod是core组,默认略写。Deployment是apps组
kind: Pod # (2) 资源类别
metadata: # (3) 元数据name: pod-demonamespace: defaultlables: app: myapp
spec: # (4) 期望, 声明式表达,containers:- name: myapp-1image: xxx/myapp:latest- name: busyboximage: xx/busybox:latestcommand:- "/bin/sh"- "-c"- "sleep 3600"
status: # (5) 状态, 资源状态xxxx:- xxx: xx
- 资源的操作
# 获取当前资源
kubectl get pod-A, --all-namespaces -n--show-labels-l 筛选资源、 key\key=value-o wide# 进入pod, 默认进入唯一容器内部
kubectl exec -it podname -c Cname --command# 查看资源描述
kubectl explain pod.spec# 查看pod内部容器日志
kubectl logs podName -c cName
4.3 Pod的生命周期

4.3.1 initC
多个initc不能同时存在,单个initc退出时返回码必须是0,否则代表当前initC没有成功。
init容器与普通容器非常像,除了:
- init容器都是运行到成功完成为止
- 每一个init容器必须再下一个init容器启动之前成功完成
- init container权限很高,需要全部成功完成后,MainC 才能开始。
如果pod的init容器失败,kubernetes会不断重启该pod,直到init容器成功完成。不过如果pod对应的restartPolicy为Never,它不会重新启动。
apiVersion: v1
kind: Pod
metadata:name: myapp-podlabels:app: myapp
spec:containers:- name: myapp-container # 主容器image: busyboxcommand: ['sh', '-c', 'echo The app is running! && sleep 3600']initContainers: # 初始化容器部分- name: init-myservice # 第一个 Init 容器image: busyboxcommand: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']- name: init-mydb # 第二个 Init 容器image: busyboxcommand: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
4.3.2 探针
深针是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三种类别:
- ExecAction
- TCPSocketAction
- HttpGetAction
每次探测结果:
- 诊断成功
- 诊断失败
- 诊断失败,未知
(1)readinessProbe 就绪探测
标记当前容器是否就绪, 就绪了就可以暴露给其他应用进行访问。
apiVersion: v1
kind: Pod
metadata:name: myapp-podlabels:app: myapp
spec:containers:- name: myapp-container # 主容器image: busyboxreadinessProbe: # 就绪探测httpGet:port:80path: /index.htmlinitialDelaySeconds: 1periodSeconds: 3livenessProbe: # 存活探测exec:command: ["/bin/sh", "-c", "echo postStart"]initialDelaySeconds: 1periodSeconds: 3
(2)livenessProbe 存活探测
检测当前容器是否还存活,保证当前容器都存活可供使用
(3)startupProbe 启动探测
检测容器是否启动,启动探测成功之后才会做 存活探测和就绪探测。
4.3.3 钩子
Pod hook(钩子)是由 Kubernetes 管理的 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook
Hook类型:
- HTTP: 发送HTTP请求
- exec: 执行一段命令
postStart 启动后勾子
spec:containers:- name: myapp-container # 主容器image: busyboxreadinessProbe:httpGet:port:80path: /index.htmlinitialDelaySeconds: 1periodSeconds: 3lifecycle:postStart:exec:command: ["/bin/sh", "-c", "echo postStart"]preStop:httpGet:host: 192.168.56.2path: hostname.htmlport: 8989
preStop 结束前钩子
preStop:
httpGet:host: 192.168.56.2path: hostname.htmlport: 8989
5. K8S 控制器
5.1 控制器概念
在 Kubernetes 中运行了一系列控制器来确保集群的当前状态与期望状态保持一致,它们就是 Kubernetes集群内部的管理控制中心或者说是”中心大脑”。例如,ReplicaSet 控制器负责维护集群中运行的 Pod 数量Node 控制器负责监控节点的状态,并在节点出现故障时,执行自动化修复流程,确保集群始终处于预期的工作状态。
5.2 Pod控制器
5.2.1 RC(ReplicationController) 和 RS (ReplicaSet)
ReplicationControler(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;
在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector.
apiversion: v1
kind: ReplicationController
metadata:name: rc-demo
spec: # rc的期望replicas: 3 # 定义pod数量selector: # 匹配器app: rc-demo # 只要是rc-demo的标签pod,都归当前控制器管理。 需要是当前pod模板标签的子集template: # 创建pod的模板metadata:lables: app: rc-demoos: linuxspec: # 当前pod的期望containers:- name: rc-demo-containerimage: xx/xx:latestenv:- name: E1value: V1name: E2value: V2ports:- containerPort: 80
5.2.2 RS (ReplicaSet)
ReplicaSet 支持集合式的 selector
- matchLables
- matchExpressions
- In:lable的值在某个列表中
- NotIn:lable的值不在列表中
- Exists:某个lable存在
- DoesNotExist: 某个lable不存在
apiversion: apps/v1
kind: ReplicaSet
metadata:name: rs-demo
spec: # rs的期望replicas: 3 # 定义pod数量selector: # 匹配器matchLabels: # 与下列标签匹配的pod就可以管理app: rs-demo # 只要是rc-demo的标签pod,都归当前控制器管理。 需要是当前pod模板标签的子集doma: anntemplate: # 创建pod的模板metadata:lables: app: rc-demoos: linuxspec: # 当前pod的期望containers:- name: rs-demo-containerimage: xx/xx:latestenv:- name: E1value: V1- name: E2value: V2ports:- containerPort: 80
selector:matchExpressions:- key: appoperation: Existsselector:matchExpressions:- key: app2operation: Invalues:- spring- hh
5.2.3 Deployment
# 定义 API 版本,Deployment 资源通常使用 apps/v1
apiVersion: apps/v1
# 定义资源类型,Deployment 用于管理 Pod 的部署和更新
kind: Deployment
# 元数据部分,定义资源的名称和标签等信息
metadata:# Deployment 的名称,在命名空间中必须唯一name: my-nginx-deployment# 为 Deployment 添加标签,可用于识别和选择labels:app: nginxenvironment: test
# 规格说明,定义 Deployment 的期望状态
spec:# 指定要运行的 Pod 副本数量replicas: 3# 标签选择器,用于识别由该 Deployment 管理的 Podselector:matchLabels:app: nginx # 必须与 template.metadata.labels 匹配# 定义 Pod 模板,用于创建新的 Podtemplate:# Pod 的元数据metadata:# 为 Pod 添加标签,Deployment 通过此标签识别其管理的 Podlabels:app: nginx # 必须与 selector.matchLabels 匹配environment: test# Pod 的规格说明spec:# 定义 Pod 中的容器列表containers:# 第一个容器定义- name: nginx-container # 容器的名称image: nginx:1.25.3 # 容器使用的镜像ports:# 容器暴露的端口列表- containerPort: 80 # 容器内部监听的端口protocol: TCP # 端口协议,默认为 TCP# 资源限制,定义容器可使用的最大资源量resources:limits:cpu: "500m" # CPU 限制,500m 表示 0.5 个 CPU 核心memory: "512Mi" # 内存限制,512 MiB# 资源请求,定义容器运行所需的最小资源量requests:cpu: "250m" # CPU 请求,250m 表示 0.25 个 CPU 核心memory: "256Mi" # 内存请求,256 MiB# 存活性探针,用于检查容器是否仍在健康运行livenessProbe:httpGet: # 使用 HTTP GET 请求进行检查path: / # 检查的路径port: 80 # 检查的端口initialDelaySeconds: 15 # 容器启动后等待多少秒开始第一次探测periodSeconds: 20 # 执行探测的频率(单位:秒)# 就绪性探针,用于检查容器是否已准备好接收流量readinessProbe:httpGet:path: /port: 80initialDelaySeconds: 5periodSeconds: 10# 定义容器重启策略,对于 Pod 中的容器,此值始终为 AlwaysrestartPolicy: Always# 定义部署策略,控制如何用新 Pod 替换旧 Podstrategy:type: RollingUpdate # 滚动更新策略,默认值rollingUpdate:maxSurge: 25% # 更新过程中可以创建的超出期望副本数的最大 Pod 数量或比例maxUnavailable: 25% # 更新过程中不可用的 Pod 的最大数量或比例
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的 ReplicationController 来方便的管理应用。
典型的应用场景包括:
-
定义Deployment来创建Pod和ReplicaSet
-
滚动升级和回滚应用
-
扩容和缩容
-
暂停和继续Deployment
-
替换方式
-
kubectl replace:使用新的配置完全替换掉现有资源的配置。这意味着新配置将覆盖现有资源的所
-
有字段和属性,包括未指定的字段,会导致整个资源的替换kubectl apply: 使用新的配置部分地更新现有资源的配置。它会根据提供的配置文件或参数,只更新与新配置中不同的部分,而不会覆盖整个资源的配置
-
-
字段级别的更新
-
kubectl replace:由于是完全替换,所以会覆盖所有字段和属性,无论是否在新配置中指定
-
kubectl apply: 只更新与新配置中不同的字段和属性,保留未指定的字段不受影响
-
apiversion: apps/v1
kind: Deployment
metadata:name: dp-demo labels:app: myapp-deployspec: # rs的期望selector: # 匹配器matchLabels: # 与下列标签匹配的pod就可以管理. 除了RC的其他控制器都有此功能app: dp-apptemplate: # 创建pod的模板metadata:lables: app: dp-appspec: # 当前pod的期望containers:- name: rs-demo-containerimage: xx/xx:latestenv:- name: E1value: V1- name: E2value: V2ports:- containerPort: 80
- Deployment和RS的关系

- 更新策略
deploy.spec.strategy.type- Recreate
- rollingUpdate
- maxSurge: 超出副本数量:
数字或者百分比 - maxUnavailable: 最多不可用数
- maxSurge: 超出副本数量:
spec: # rs的期望selector: # 匹配器matchLabels: # 与下列标签匹配的pod就可以管理. 除了RC的其他控制器都有此功能app: dp-appstrategy: Recreatetemplate: # 创建pod的模板metadata:lables: app: dp-appspec: # 当前pod的期望containers:
- 扩缩容
5.2.4 DaemonSet
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除DaemonSet 将会删除它创建的所有 Pod
使用 DaemonSet 的一些典型用法:
- 运行集群存储 daemon,例如在每个 Node 上运行
glusterd、ceph - 在每个 Node 上运行日志收集 daemon,例如
fluentd、`ogstash - 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、
collectdDatadog 代理、New Relic 代理,或 Ganglia`gmond)
# 指定 API 版本,DaemonSet 属于 apps/v1
apiVersion: apps/v1
# 定义资源类型为 DaemonSet
kind: DaemonSet
metadata:# DaemonSet 的名称name: fluentd-logging# 部署到 kube-system 命名空间,通常用于系统级组件namespace: kube-system# 为 DaemonSet 本身设置标签labels:k8s-app: fluentd-loggingversion: "v1"
spec:# 修订历史记录限制,指定保留的旧 ReplicaSet 数量用于回滚revisionHistoryLimit: 3# 更新策略配置updateStrategy:# 更新策略类型,RollingUpdate 表示滚动更新type: RollingUpdate# 滚动更新具体参数rollingUpdate:# 滚动更新期间,最多允许 1 个 Pod 不可用maxUnavailable: 1# 标签选择器,用于识别由该 DaemonSet 管理的 Podselector:matchLabels:name: fluentd-elasticsearch # 此标签必须与 template.metadata.labels 匹配# Pod 模板,定义要创建的 Pod 的规格template:metadata:# 为 Pod 设置标签,DaemonSet 通过此标签识别其管理的 Podlabels:name: fluentd-elasticsearch # 必须与 spec.selector.matchLabels 匹配spec:# 容忍度配置,允许 Pod 调度到带有特定污点的节点(如 Master 节点)tolerations:# 第一个容忍度:允许调度到带有 node-role.kubernetes.io/control-plane 污点且效果为 NoSchedule 的节点- key: node-role.kubernetes.io/control-planeoperator: Exists # 只要存在该键的污点即容忍effect: NoSchedule# 第二个容忍度:允许调度到带有 node-role.kubernetes.io/master 污点且效果为 NoSchedule 的节点- key: node-role.kubernetes.io/masteroperator: Existseffect: NoSchedule# 容器定义containers:- name: fluentd-elasticsearch # 容器名称image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2 # 容器镜像# 资源限制和请求resources:limits:memory: "200Mi" # 内存限制requests:cpu: "100m" # CPU 请求 (0.1 core)memory: "200Mi" # 内存请求# 容器卷挂载volumeMounts:- name: varlog # 挂载宿主机日志目录mountPath: /var/log- name: varlibdockercontainers # 挂载 Docker 容器目录mountPath: /var/lib/docker/containersreadOnly: true # 以只读方式挂载# 容器终止宽限期,优雅终止的时间terminationGracePeriodSeconds: 30# 卷定义volumes:- name: varlog# 使用宿主机路径作为卷源hostPath:path: /var/log- name: varlibdockercontainershostPath:path: /var/lib/docker/containers
5.2.5 Job
创建Job操作应该是幂等的!!!
Job负责批处理任务,即仅仅执行一次任务,它保证批处理任务的一个或多个Pod成功结束(返回值为0)
特殊说明:
spec.template格式同 PodRestartPolicy仅支持 Never 或 OnFailure- 单个 Pod 时,默认 Pod 成功运行后 Job 即结束
.spec.completions标志 Job 结束需要成功运行的 Pod 个数,默认为 1。成功执行几次.spec.parallelism标志并行运行的 Pod 的个数,默认为 1。 同一时间运行的pod数spec.activeDeadlineSeconds标志失败 Pod 的重试最大时间,超过这个时间不会继续重试
apiVersion: batch/v1
kind: Job
metadata:name: simple-job
spec:completions: 1 # 需要成功完成的任务总数parallelism: 1 # 同时运行的Pod数量backoffLimit: 4 # 失败前的重试次数template:spec:containers:- name: workerimage: busyboxcommand: ["sh", "-c", "echo 'Hello from Kubernetes Job!' && sleep 30"] # 执行命令并睡眠30秒restartPolicy: Never # Pod失败后不重启,但Job会创建新Pod重试任务
5.2.6 CronJob
只能做到分钟级别的控制
- 在给定的时间只运行一次
- 周期性地运行
apiVersion: batch/v1
kind: CronJob
metadata:name: daily-cleanup
spec:schedule: "0 3 * * *" # 每天凌晨3点执行一次 (cron表达式) #分 时 日 月 周concurrencyPolicy: Forbid # 禁止并发执行,如果上次任务未完成则跳过本次successfulJobsHistoryLimit: 3 # 保留3个成功Job的历史记录failedJobsHistoryLimit: 1 # 保留1个失败Job的历史记录jobTemplate: # Job模板,定义CronJob创建的Job规格spec:template:spec:containers:- name: cleanup-agentimage: busyboxcommand: ["sh", "-c", "echo 'Performing daily cleanup...'; find /tmp -type f -mtime +7 -delete"] # 执行清理命令restartPolicy: OnFailure # 容器运行失败才重启
5.2.7 StatefulSet
StatefulSet 是 Kubernetes 中专门用于管理有状态应用的控制器,它为每个 Pod 提供稳定的网络标识符和独立的持久化存储,并确保 Pod 的有序部署、扩缩容和更新。这与 Deployment 等用于无状态应用的控制器形成鲜明对比。
下面这个表格汇总了 StatefulSet 与 Deployment 的核心区别,帮助你快速理解它的独特价值:
| 特性 | StatefulSet | Deployment |
|---|---|---|
| 适用场景 | 有状态应用(如数据库、消息队列) | 无状态应用(如 Web 服务器) |
| Pod 名称 | 稳定唯一(如 web-0, web-1) |
随机生成 |
| 网络标识 | 稳定的 DNS 域名(需配合 Headless Service) | 不稳定,通常通过 Service 负载均衡访问 |
| 存储 | 每个 Pod 拥有独立的持久化存储(通过 volumeClaimTemplates) |
所有 Pod 共享存储卷(或无持久化存储) |
| 部署顺序 | 有序(从 0 到 N-1 顺序创建,逆序删除) | 无序(所有 Pod 并行创建) |
| 更新策略 | 支持有序的滚动更新(RollingUpdate)和手动更新(OnDelete) | 支持多种滚动更新策略 |
# 以下示例用于部署一个简单的 Nginx 服务,但为其每个 Pod 提供稳定的名称和独立的存储。
---
# 首先定义一个 Headless Service,用于为 StatefulSet Pod 提供稳定的网络标识
# Headless Service 是 StatefulSet 正常工作的关键组件之一
apiVersion: v1
kind: Service
metadata:name: nginx-headless # Service 名称,StatefulSet 将通过 serviceName 字段引用它labels:app: nginx
spec:clusterIP: None # 明确指定为 None,表示这是一个 Headless Service,不分配集群 IPports:- port: 80 # 服务端口name: web # 端口名称selector:app: nginx # 选择标签为 app: nginx 的 Pod
---
# 定义 StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web # StatefulSet 的名称,生成的 Pod 将命名为 web-0, web-1, ...
spec:serviceName: "nginx-headless" # 必须指定,用于 Pod 身份标识和网络发现,指向前面定义的 Headless Servicereplicas: 2 # 需要创建的 Pod 副本数量selector:matchLabels:app: nginx # 必须与 template.metadata.labels 匹配template:metadata:labels:app: nginx # Pod 的标签,与 selector 和 Service 的 selector 匹配spec:containers:- name: nginximage: nginx:1.25.3 # 容器镜像imagePullPolicy: IfNotPresent # 镜像拉取策略ports:- containerPort: 80 # 容器暴露的端口name: web # 端口名称volumeMounts:- name: www-data # 要挂载的卷名称,必须与 volumeClaimTemplates 中定义的名称匹配mountPath: /usr/share/nginx/html # 容器内的挂载路径resources:requests: # 资源请求,调度依据memory: "64Mi"cpu: "250m"limits: # 资源限制,容器最大可用资源memory: "128Mi"cpu: "500m"volumeClaimTemplates: # 存储卷申请模板,这是 StatefulSet 提供独立持久存储的关键- metadata:name: www-data # PVC 的名称,Pod 中通过此名称引用spec:accessModes: [ "ReadWriteOnce" ] # 访问模式,ReadWriteOnce 表示可被单个节点读写storageClassName: "managed-nfs-storage" # 存储类名称,需与集群中已存在的 StorageClass 匹配resources:requests:storage: 1Gi # 请求的存储空间大小
6. K8S 服务- Service
6.1 Service概念
Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略-- 通常称为微服务。这一组Pod 能够被Service访问到,通常是通过Label Selector

6.2 Service工作原理及使用
6.2.1 ClusterIP
apiVersion: v1
kind: Service
metadata:name: my-clusterip-service
spec:type: ClusterIP # 类型,不指定时默认为 ClusterIPselector: # 标签选择器,选择要关联的Podapp: my-appports:- protocol: TCPport: 80 # Service 监听的端口targetPort: 8080 # Pod 上应用程序实际监听的端口
ClusterIP 是默认的 Service 类型,它为集群内部的一组 Pod 提供一个固定的虚拟 IP(ClusterIP),用于内部通信和负载均衡
6.2.2 NodePort
NodePort 在 ClusterIP 的基础上,在每个 Node 的静态端口(NodePort)上暴露 Service,从而允许从集群外部通过 <NodeIP>:<NodePort>访问服务
apiVersion: v1
kind: Service
metadata:name: my-nodeport-service
spec:type: NodePort # 服务类型selector:app: my-appports:- protocol: TCPport: 80 # Service 的端口(ClusterIP:80)targetPort: 8080 # Pod 的目标端口nodePort: 30001 # 可选字段,指定节点上的端口(范围通常为30000-32767)。不指定则由系统自动分配
6.2.3 LoadBalancer
LoadBalancer 是 NodePort 的扩展,它会在云平台上自动配置一个外部负载均衡器,将流量引导到集群各个节点的 NodePort,再转发到 Pod
apiVersion: v1
kind: Service
metadata:name: my-loadbalancer-service
spec:type: LoadBalancer # 服务类型selector:app: my-appports:- protocol: TCPport: 80targetPort: 8080# 在支持的环境中,云提供商会自动分配一个外部可访问的 IP# 可选:指定负载均衡器的IP# loadBalancerIP: "1.2.3.4" # 在某些云平台,你可以请求一个特定的静态 IP 地址。但通常省略此项,由云平台自动分配。
6.2.4 ExternalName
ExternalName 类型的 Service 将 Service 映射到一个外部域名(例如 external.example.com),通过返回该域名的 CNAME 记录来实现,不提供负载均衡,也不代理任何流量
apiVersion: v1
kind: Service
metadata:name: my-externalname-service # 可以通过my-externalname-service服务名访问外网
spec:type: ExternalName # 服务类型externalName: external.example.com # 外部域名
# 注意:ExternalName Service 没有 selector 和 ports 定义。
6.2.5 Headless Service(无头服务)
对于有状态应用(如数据库集群),有时需要直接与每个 Pod 通信,而不是通过负载均衡。这时可以使用 Headless Service,通过设置 clusterIP: None来实现
apiVersion: v1
kind: Service
metadata:name: my-headless-service
spec:clusterIP: None # 这是关键,表示无头服务selector:app: my-stateful-appports:- protocol: TCPport: 80targetPort: 8080
6.3 EndPoints

Kubernetes 中的 Service,它定义了一组 Pods 的逻辑集合和一个用于访问它们的策略。一个 Service 的目标 Pod 集合通常是由 Label Selector 来决定的。
Endpoints 是一组实际服务的端点集合。一个 Endpoint 是一个可被访问的服务端点,即一个状态为 running 的 pod 的可访问端点。一般 Pod 都不是一个独立存在,所以一组 Pod 的端点合在一起称为 EndPoints。只有被 Service Selector 匹配选中并且状态为 Running 的才会被加入到和 Service 同名的Endpoints 中。
创建Service时会自动创建Endpoints

6.4 特性-publishNotReadyAddresses
publishNotReadyAddresses是 Kubernetes Service 的一个配置字段。为了让你快速理解它的核心作用
| 特性 | 默认行为 (publishNotReadyAddresses: false) |
启用后 (publishNotReadyAddresses: true) |
|---|---|---|
| 核心作用 | Service 只关联就绪的 Pod | Service 同时关联就绪和未就绪的 Pod |
| Endpoints 记录 | 仅更新到 Addresses字段 |
未就绪 Pod 的地址会更新到 NotReadyAddresses字段 |
| 流量路由 | 不会将流量路由到未就绪的 Pod | 不会将流量路由到未就绪的 Pod (Kubernetes 负载均衡器行为不变) |
| 主要应用场景 | 通用无状态应用 | StatefulSet 的无头服务 (Headless Service),用于服务发现 |
| DNS 记录 (Headless Service) | 仅包含就绪 Pod 的地址 | 包含所有匹配 Pod 的地址(就绪+未就绪) |
apiVersion: v1
kind: Service
metadata:name: my-stateful-service
spec:clusterIP: None # 创建一个无头服务 (Headless Service)publishNotReadyAddresses: true # 关键配置:发布未就绪地址selector:app: my-stateful-appports:- port: 80targetPort: 8080
7. K8S 存储
7.1 存储分类
- 元数据
- configMap:用于保存配置数据 (明文)
- Secret:用于保存敏感性数据 (编码)
- Downward API: 容器在运行时从 Kubernetes API 服务器获取有关它们自身的信息真实数据(cpu限制,内存限制等)
- Volume:用于存储临时或者持久性数据◆PersistentVolume:申请制的持久化存储
7.2 ConfigMap
- config配置
# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:name: app-confignamespace: default
data:# 简单键值对APP_ENV: "production"LOG_LEVEL: "INFO"# 完整的配置文件内容server.conf: |server.port=8080server.name=my-applogging.level=INFO
- 在pod中使用configmap
apiVersion: v1
kind: Pod
metadata:name: configmap-envfrom-pod
spec:containers:- name: test-containerimage: busyboxcommand: ["/bin/sh", "-c", "sleep 3600"]envFrom:- configMapRef:name: app-config # 将 app-config 中的所有键值对都注入为环境变量
7.3 Secret
- 创建
apiVersion: v1
kind: Secret
metadata:name: mysecret-yaml
type: Opaque # 默认类型,用于存储任意键值对
data:# 值必须为 base64 编码后的字符串username: YWRtaW4= # echo -n "admin" | base64password: UzNjdXJlITIwMjM= # echo -n "S3cure!2023" | base64
- 使用 (文件挂载方式)
apiVersion: v1
kind: Pod
metadata:name: pod-with-secret-volume
spec:containers:- name: appimage: nginxvolumeMounts:- name: secret-volumemountPath: "/etc/secrets" # 挂载路径 readOnly: truevolumes:- name: secret-volumesecret:secretName: mysecret # 指定要挂载的 Secret 支持热更新# items: # 可选:只挂载特定键,并可重命名文件# - key: username# path: my-username # 在 /etc/secrets/my-username 中
7.4 Downward API
将 Pod/容器的元数据(名称、标签、资源限制等)暴露给容器
- 创建
apiVersion: v1
kind: Pod
metadata:name: downward-demo-envlabels:app: demo-appannotations:build: "2025"
spec:containers:- name: main-containerimage: busyboxcommand: ["sh", "-c", "sleep 3600"]env:- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.name # 注入 Pod 名称- name: POD_IPvalueFrom:fieldRef:fieldPath: status.podIP # 注入 Pod IP- name: CPU_LIMITvalueFrom:resourceFieldRef:containerName: main-containerresource: limits.cpu # 注入 CPU 限制divisor: 1m # 除数,结果单位为 millicores
- 使用
apiVersion: v1
kind: Pod
metadata:name: downward-demo-volumelabels:environment: productionapp: myappannotations:owner: "team-a"commit: "a1b2c3d"
spec:containers:- name: main-containerimage: busyboxcommand: ["sh", "-c", "sleep 3600"]volumeMounts:- name: podinfomountPath: /etc/podinfo # 元数据挂载目录volumes:- name: podinfodownwardAPI:items:- path: "pod_name" # 生成的文件名fieldRef:fieldPath: metadata.name # Pod 名称- path: "labels" # 将所有标签写入此文件fieldRef:fieldPath: metadata.labels- path: "annotations" # 将所有注解写入此文件fieldRef:fieldPath: metadata.annotations- path: "cpu_limit" # 容器资源限制resourceFieldRef:containerName: main-containerresource: limits.cpudivisor: 1m
7.4.1 存在意义
7.4.2 env
7.4.3 volume
7.4.4 ApiServer接口读取数据的扩展
7.5 Volume
7.5.1 存在意义
Kubernetes Volume 为 Pod 中的容器提供了灵活的数据存储和共享能力,其生命周期可以与 Pod 一致,也可以独立于 Pod 实现持久化。下面我用一个表格汇总主要的 Volume 类型和核心特性,然后通过具体案例进行说明。
7.5.2 emptyDir 共享内存 临时存储
emptyDir在 Pod 被调度到节点时创建,适用于临时数据存储和同一 Pod 内容器间的数据共享。Pod 删除,数据随之丢失
用途:Pod 内容器间共享数据,例如一个容器生成日志,另一个容器处理日志。
apiVersion: v1
kind: Pod
metadata:name: shared-volume-pod
spec:containers:- name: writerimage: alpine:3.18command: ["sh", "-c", "echo 'Hello from writer!' > /shared-data/message && sleep 3600"]volumeMounts:- name: shared-storagemountPath: /shared-data # 写入器容器挂载路径- name: readerimage: alpine:3.18command: ["sh", "-c", "cat /shared-data/message && sleep 3600"]volumeMounts:- name: shared-storagemountPath: /shared-data # 读取器容器挂载路径volumes:- name: shared-storageemptyDir: {} # 定义 emptyDir 卷
7.5.3 hostPath
hostPath将节点上的一个目录或文件挂载到 Pod 中,允许 Pod 访问节点文件系统
用途:需要访问节点主机文件系统的场景,例如监控代理收集节点日志、或需要访问 Docker 引擎(如 /var/run/docker.sock)
apiVersion: v1
kind: Pod
metadata:name: hostpath-demo-pod
spec:containers:- name: app-containerimage: alpine:3.18command: ["sh", "-c", "tail -f /host-logs/syslog"]volumeMounts:- name: host-log-volumemountPath: /host-logs # 容器内的挂载点readOnly: true # 建议设置为只读以提高安全性volumes:- name: host-log-volumehostPath:path: /var/log # 节点上的源目录路径type: Directory # 确保该路径是已存在的目录
7.6 PV & PVC
PV 和 PVC 是 Kubernetes 中用于管理持久化存储的核心抽象。PV 是集群中的存储资源,由管理员提供;PVC 是用户对存储的请求
- 静态供应需要管理员预先创建好 PV
# 1. 先创建一个PersistentVolume (PV)
apiVersion: v1
kind: PersistentVolume
metadata:name: example-pv
spec:capacity:storage: 10Gi # PV的容量accessModes:- ReadWriteOnce # 访问模式:单节点读写persistentVolumeReclaimPolicy: Retain # 回收策略:删除PVC后保留PV和数据storageClassName: manualhostPath: # 此例使用hostPath,生产环境建议使用网络存储如NFS、云存储path: /mnt/data---
# 2. 创建一个PersistentVolumeClaim (PVC)来请求存储
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: example-pvc
spec:storageClassName: manualaccessModes:- ReadWriteOnceresources:requests:storage: 5Gi # 请求的存储大小,需小于等于PV的容量---
# 3. 在Pod中通过PVC使用持久化存储
apiVersion: v1
kind: Pod
metadata:name: pv-pod
spec:containers:- name: app-containerimage: nginx:alpinevolumeMounts:- name: persistent-storagemountPath: /usr/share/nginx/htmlvolumes:- name: persistent-storagepersistentVolumeClaim:claimName: example-pvc # 使用指定的PVC
- 动态供应通过 StorageClass 实现,当创建 PVC 时,系统会根据 StorageClass 自动创建对应的 PV
# 1. 定义一个StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: fast-ssd
provisioner: kubernetes.io/aws-ebs # 此例使用AWS EBS,需根据环境更改
parameters:type: gp3---
# 2. 创建PVC时指定StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: dynamic-pvc
spec:storageClassName: fast-ssd # 指定StorageClass名称accessModes:- ReadWriteOnceresources:requests:storage: 20Gi # 请求20Gi存储,系统会自动创建符合要求的PV---
# 3. Pod中使用此PVC的方式与静态供应相同
7.6.1 关联条件
7.6.2 回收策略
7.6.3 状态
7.6.4 PVC保护
7.6.5 StatefulSet控制器演示
7.7 StorageClass
概念
Kubernetes 中的 StorageClass 是定义存储类型的资源对象,它允许管理员描述他们提供的“存储类别”,从而实现动态的存储供应。
| 存储类型 | 适用场景 | 动态供应 | 回收策略 | 绑定模式 | 扩容支持 | 特点简述 |
|---|---|---|---|---|---|---|
| AWS GP3 (通用型SSD) | 云上通用工作负载 | ✅ | Delete/Retain | WaitForFirstConsumer | ✅ | 平衡成本与性能,支持指定IOPS和吞吐量 |
| NFS (网络文件系统) | 多Pod共享读写的场景 | ✅ | Delete/Retain | Immediate | ❌ | 易于搭建,适合共享存储,但性能有限 |
| 本地存储 (Local) | 高性能需求,如数据库 | ❌ | Retain | WaitForFirstConsumer | ❌ | 延迟最低,但需手动预配PV,无节点高可用 |
| Ceph RBD (块存储) | 私有云/大规模分布式存储 | ✅ | Delete/Retain | Immediate | ✅ | 高可用、可扩展,但部署和配置较复杂 |
StorageClass 是一种资源对象,用于定义持久卷(Persistent Volumes)的动态供给(DynamicProvisioning)策略。StorageClass 允许管理员定义不同类型的存储,并指定如何动态创建持久卷以供应用程序使用。这使得 Kubernetes 集群中的存储管理更加灵活和自动化。

nfs-client-provisioner

7.8 其他
kubectl命令自动补全
8. K8S 调度器
Kubernetes Scheduler(kube-scheduler)是 Kubernetes 集群的核心组件之一,它负责为新创建的 Pod 自动选择一个最合适的 Node(节点)来运行。
你可以把它想象成集群的“智能调度中心”,其核心目标是实现集群资源的优化分配和负载均衡
8.1 调度器概念

Sheduler 是作为单独的程序运行的,启动之后会一直监听 API Server,获取PodSpec.NodeName为空的 pod,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上
概念听起来是非常简单的,但有很多要考虑的问题:
- 公平: 如何保证每个节点都能被分配资源
- 资源高效利用: 集群所有资源最大化被使用
- 效率: 调度的性能要好,能够尽快地对大批量的 pod 完成调度工作
- 灵活: 允许用户根据自己的需求控制调度的逻辑、
8.1.1 自定义调度器
# 这是一个用于演示的调度器配置,展示了如何启用自定义插件
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
leaderElection:leaderElect: false
profiles:- schedulerName: label-a-b-scheduler # 调度器名称plugins:filter:enabled:- name: labelAB # 启用名为 labelAB 的 Filter 插件disabled:- name: "*" # 禁用所有默认的 Filter 插件preScore:enabled:- name: labelAB # 启用名为 labelAB 的 PreScore 插件disabled:- name: "*" # 禁用所有默认的 PreScore 插件
# 注意:实际部署时,此配置通常保存在 ConfigMap 中供调度器挂载
- go语言编写插件
// 1. 定义插件并实现相关接口
package label_a_bimport ("context""log"v1 "k8s.io/api/core/v1""k8s.io/apimachinery/pkg/runtime"framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1" // 引入调度器框架包
)// 2. 定义插件名称
const Name = "labelAB"// 3. 定义插件结构体
type labelAB struct{}// 4. 确保插件实现了所需的接口(FilterPlugin 和 PreScorePlugin)
var _ framework.FilterPlugin = &labelAB{}
var _ framework.PreScorePlugin = &labelAB{}// 5. 插件工厂函数,用于创建插件实例
func New(_ runtime.Object, _ framework.FrameworkHandle) (framework.Plugin, error) {return &labelAB{}, nil // 返回插件实例
}// 6. 返回插件名称
func (pl *labelAB) Name() string {return Name
}// 7. 实现 Filter 方法
// Filter 是调度周期中用于过滤不满足条件的节点的阶段
func (pl *labelAB) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {// 检查节点是否拥有标签 "a"="b"if nodeInfo.Node().Labels["a"] != "b" {// 如果节点没有 "a=b" 的标签,返回 Unschedulable 状态,并说明原因return framework.NewStatus(framework.Unschedulable, "Node: "+nodeInfo.Node().Name+" does not have the required label a=b")}// 节点满足条件,返回 Success 状态return framework.NewStatus(framework.Success, "Node: "+nodeInfo.Node().Name+" has the required label a=b")
}// 8. 实现 PreScore 方法
// PreScore 在 Score 阶段之前执行,可用于进行一些预处理或信息记录
func (pl *labelAB) PreScore(ctx context.Context, state *framework.CcleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {// 这里可以记录日志或准备评分所需的数据log.Println("Entering PreScore for pod:", pod.Name)return framework.NewStatus(framework.Success, "Pod: "+pod.Name)
}
- 使用
apiVersion: v1
kind: Pod
metadata:name: my-test-pod
spec:# 为Pod指定调度器schedulerName: label-a-b-scheduler # 与你在配置中定义的 schedulerName 一致containers:- name: nginximage: nginx
8.1.2 预选 Predicates / Filtering
调度器会检查集群中所有可用的节点,并根据一系列预定义的强制性规则(如资源是否充足、节点标签是否匹配、是否存在端口冲突、Pod 是否能容忍节点的污点等)过滤掉那些不满足条件的节点。通过此阶段的节点列表将进入下一阶段
调度分为几个部分: 首先是过滤掉不满足条件的节点,这个过程称为预选
然后对通过的节点按照优先级排序,这个是优选;
最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误
PodFitsResources: 节点上剩余的资源是否大于pod 请求的资源
PodFitsHost: 如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
PodFitsHostPorts: 节点上已经使用的 port 是否和 pod 申请的 port 冲突
PodSelectorMatches: 过滤掉和 pod 指定的 label 不匹配的节点
NoDiskConflict: 已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读
8.1.3 优选 Priorities / Scoring
调度器会为通过预选的所有候选节点进行打分。打分策略可以包括
-
LeastRequestedPriority:优先选择资源请求剩余最多的节点(即更空闲的节点)。 -
BalancedResourceAllocation:优先选择资源使用率更均衡的节点(避免 CPU 用完而内存剩余很多的情况)。 -
ImageLocalityPriority:优先选择已存在 Pod 所需容器镜像的节点,加速启动。 -
NodeAffinityPriority:根据节点亲和性规则打分。最终,调度器会选择得分最高的节点作为 Pod 的运行位置。
8.2 亲和性
一种调度的偏好特性
8.2.1 nodeAffinity
(1)软性策略 尽量满足
apiVersion: v1
kind: Pod
metadata:name: memory-pod
spec:affinity:nodeAffinity:# 调度器会首先尝试寻找满足 memory-speed > 3200的节点。如果存在多个,则会进一步筛选其中 storage-type=nvme的节点。即使找不到任何满足条件的节点,Pod 仍然会被成功调度到某个可用节点上。preferredDuringSchedulingIgnoredDuringExecution:- weight: 80 # 权重越高,优先级越高(范围1-100)preference:matchExpressions:- key: memory-speedoperator: Gt # 操作符,表示“大于”values:- "3200" # 优先选择内存速度超过3200MHz的节点- weight: 20 # 权重较低的次要偏好preference:matchExpressions:- key: storage-typeoperator: Invalues:- "nvme" # 其次,优先选择存储类型为NVMe的节点containers:- name: my-containerimage: nginx
(2)硬性策略 必须满足
apiVersion: v1
kind: Pod
metadata:name: gpu-pod
spec:affinity:nodeAffinity:#如果集群中没有同时拥有 gpu=true和 disktype=ssd标签的节点,这个 Pod 将无法被调度(保持 Pending状态)requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: gpu # 节点标签的键operator: In # 操作符,表示“在...之中”values:- "true" # 节点标签的值必须是 "true"- key: disktype # 可以同时指定多个条件,是“与”的逻辑关系operator: Invalues:- "ssd"containers:- name: my-containerimage: nginx
8.2.2 podAffinity/podAntiAffinity
PodAffinity 和 PodAntiAffinity 是 Kubernetes 中用于精细控制 Pod 调度位置的高级策略,它们关注的是 Pod 与 Pod 之间的“吸引”或“排斥”关系,而不仅仅是 Pod 与 Node 的关系。
| 特性 | PodAffinity (Pod 亲和性) | PodAntiAffinity (Pod 反亲和性) |
|---|---|---|
| 核心目标 | 吸引:让 Pod 靠近 具有特定标签的其他 Pod | 排斥:让 Pod 远离 具有特定标签的其他 Pod |
| 调度逻辑 | “我愿意和它在一起” | “我不想和它在一起” |
| 典型应用 | 将需要紧密协作、低延迟通信的服务部署在一起(如前端与后端) | 实现高可用,避免单点故障(如将同一服务的副本分散到不同节点或可用区) |
| 配置强度 | 支持 requiredDuringScheduling...(硬策略) 和 preferredDuringScheduling...(软策略) |
同样支持 硬策略 和 软策略 |
(1) podAffinity
apiVersion: apps/v1
kind: Deployment
metadata:name: log-collector
spec:replicas: 2selector:matchLabels:app: log-collectortemplate:metadata:labels:app: log-collectorspec:affinity:podAffinity: # 使用Pod亲和性requiredDuringSchedulingIgnoredDuringExecution: # 使用硬策略- labelSelector:matchExpressions:- key: appoperator: Invalues:- my-web-app # 寻找标签为app=my-web-app的PodtopologyKey: kubernetes.io/hostname # 必须与目标Pod在同一节点containers:- name: collectorimage: busybox
(2) podAntiAffinity
apiVersion: apps/v1
kind: Deployment
metadata:name: my-web-app
spec:replicas: 3selector:matchLabels:app: my-web-apptemplate:metadata:labels:app: my-web-appspec:affinity:podAntiAffinity: # 使用Pod反亲和性preferredDuringSchedulingIgnoredDuringExecution: # 使用软策略- weight: 100 # 权重值,范围1-100,用于在多个软策略中区分优先级podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues:- my-web-app # 避免与自身应用的Pod在同一拓扑域topologyKey: kubernetes.io/hostname # 拓扑域为节点级别containers:- name: nginximage: nginx:latest
8.3 污点(Taint) 和容忍 (Toleration)
Kubernetes 中的污点(Taint)和容忍度(Toleration) 是一对用于控制 Pod 能否调度到特定 Node 上的机制。它们通过定义“排斥”和“接受”的规则,共同实现了对集群资源的精细调度管理。
8.3.1 概念
| 特性 | 污点 (Taint) | 容忍度 (Toleration) |
|---|---|---|
| 作用对象 | Node(节点) | Pod |
| 核心目的 | 排斥:拒绝不能容忍该污点的 Pod 被调度到本节点 | 接受:允许 Pod 被调度到带有匹配污点的节点上 |
| 强制力 | 是节点的属性,具有强制性 | 是 Pod 的属性,是声明式的(允许但不强制) |
| 效果 (Effect) | NoSchedule, PreferNoSchedule, NoExecute |
需与污点的 key, value(可选), effect匹配 |
8.3.2 污点组成
污点有三种不同的效果(Effect),它们决定了 Pod 被排斥的强度和行为:
| 效果 (Effect) | 对新建 Pod 的调度影响 | 对节点上已存在 Pod 的影响 | 特点 |
|---|---|---|---|
NoSchedule |
禁止不能容忍此污点的新 Pod 调度到该节点 | 无影响 | 硬性限制,常用于专用节点 |
PreferNoSchedule |
尽量避免调度不能容忍的 Pod,但非强制 | 无影响 | 软性限制,倾向性建议 |
NoExecute |
禁止不能容忍此污点的新 Pod 调度到该节点 | 驱逐(Evict)已运行且不能容忍此污点的 Pod | 最强限制,影响现有Pod |
8.3.3 污点设置和去除
# 使用 kubectl taint命令为节点添加或删除污点
# 添加污点 value为空时等号也需要添加
kubectl taint nodes <node-name> <key>=<value>:<effect># 示例:给节点 node1 添加一个污点,键为 gpu,值为 dedicated,效果为 NoSchedule
kubectl taint nodes node1 gpu=dedicated:NoSchedule# 删除污点(在 effect 后加短横线 -,)
kubectl taint nodes node1 gpu=dedicated:NoSchedule-
effect 类型:
- NoSchedule: 表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上
- PreferNoSchedule: 表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上
- NoExecute: 表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的Pod 驱逐出去
8.3.4 容忍设置
apiVersion: v1
kind: Pod
metadata:name: my-pod
spec:containers:- name: nginximage: nginxtolerations: # 容忍度配置- key: "gpu" # 需要匹配的污点的键operator: "Equal" # 操作符,Equal 表示值必须完全匹配, Exists:只要存在具有该 key的污点即可,无需关心 value是什么。value: "dedicated" # 需要匹配的污点的值effect: "NoSchedule" # 需要匹配的污点的效果
8.3.5 容忍特殊类型
(1) 当不指定value时,表示容忍所有的污点值
tolerations:
- key: "gpu"operator: "Exists"effect: "NoSchedule"
(2) 当不指定 key 值时,表示容忍所有的污点 key
tolerations:
- operator: "Exists"
(3) 当不指定 effect 值时,表示容忍所有的污点作用
tolerations:
- key: "gpu"operator: "Exists"
(4) 有多个 Master 存在时,防止资源浪费,可以如下设置;
# 默认是Noschedule
kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoschedule
8.4 固定节点调度
将pod直接调度到指定的Node节点上,会跳过Scheduler的调度策略,该匹配规则是强制匹配
8.4.1 nodeName
apiVersion: v1
kind: Pod
metadata:name: nginx-pod
spec:nodeName: node01 # 关键字段:直接指定节点名称containers:- name: nginximage: nginx:latest
8.4.2 nodeSelector
- 给节点打标签
kubectl label nodes <node-name> <key>=<value>
# 示例:给节点 node01 打上 disktype=ssd 和 env=prod 的标签
kubectl label nodes node01 disktype=ssd env=prod
- 在 Pod 中配置 nodeSelector
apiVersion: v1
kind: Pod
metadata:name: nginx-pod
spec:nodeSelector: # 关键字段:节点选择器disktype: ssd # 选择具有 disktype=ssd 标签的节点env: prod # 同时选择具有 env=prod 标签的节点 (多个标签是"与"关系)containers:- name: nginximage: nginx:latest
9. K8S 安全机制
9.1 安全机制说明
Kubernetes 作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。APIServer 是集群内部各个组件通信的中介,也是外部控制的入口。所以Kubernetes 的安全机制基本就是围绕保护 APIServer 来设计的
9.2 认证
认证是安全的第一道关卡,用于验证用户或组件的身份。K8s API Server 支持多种认证方式:
| 认证方式 | 描述 | 适用场景 |
|---|---|---|
| SSL/TLS 证书认证 | 最严格和安全的方式,基于 CA 根证书签名的双向身份验证。 | 组件间通信 (kubectl, kubelet, kube-proxy) |
| Bearer Token | 通过一个长长的、难以模仿的 Token 字符串来识别用户。Token 存储在 API Server 可访问的文件中。 | 服务账户 (ServiceAccount) 认证 |
| HTTP Base 认证 | 使用用户名和密码,通过 Base64 编码后放在 HTTP Header 中。 | 简单测试环境 (不推荐用于生产) |
9.3 鉴权
一旦身份被确认,鉴权机制便会决定该身份拥有哪些操作的权限。K8s 主要采用 RBAC (基于角色的访问控制)
- Role & ClusterRole:定义一组权限规则(能对什么资源做什么操作)。
Role是命名空间作用域的。ClusterRole是集群作用域的,可以定义对集群级别资源(如 Node)或跨所有命名空间资源的权限。
- RoleBinding & ClusterRoleBinding:将角色绑定到特定的用户、组或 ServiceAccount,从而授予其权限。
RoleBinding在特定命名空间内授予权限。ClusterRoleBinding在集群范围授予权限。
创建一个允许读取 Pod 信息的角色并绑定给用户
# 定义一个Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: defaultname: pod-reader
rules:
- apiGroups: [""] # "" 代表核心API组resources: ["pods"]verbs: ["get", "list", "watch"] # 被允许的操作---
# 将Role绑定给一个用户
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: read-podsnamespace: default
subjects:
- kind: Username: "zhangsan" # 用户名apiGroup: rbac.authorization.k8s.io
roleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.io
9.4 准入控制
准入控制是 API 请求在经过认证和鉴权之后的一个可配置的拦截层。它由一系列准入控制器 Webhook 组成,可以对请求进行验证(Validating)或修改(Mutating)
-
常用内置控制器:
-
ResourceQuota:限制命名空间的资源总量。 -
LimitRange:为命名空间中的资源设置默认或限制范围。
-
-
动态扩展 (Webhook):
ValidatingWebhookConfiguration:用于执行复杂的自定义验证逻辑(如:镜像来源检查)。MutatingWebhookConfiguration:用于在对象持久化前对其进行修改(如:自动注入 Sidecar 容器)。
# 网络策略: NetworkPolicy 是一种以 Pod 为中心的网络隔离机制,它允许你通过标签选择器来控制 Pod 之间以及 Pod 与外部世界的网络流量
# 示例:允许带有特定标签的 Pod 接收 80 端口的流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: allow-web
spec:podSelector:matchLabels:app: webpolicyTypes:- Ingressingress:- ports:- protocol: TCPport: 80
10. Helm V3
10.1 Helm概念
在没使用 helm 之前,向 kubernetes 部署应用,我们要依次部署 deployment、svc 等,步骤较繁琐。况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm 通过打包的方式,支持发布的版本管理和控制,很大程度上简化了Kubernetes 应用的部署和管理
Helm 本质就是让 K8s的应用管理(Deployment,Service 等)可配置,能动态生成。通过动态生成 K8s资源清单文件(deployment.yaml,service.yaml)。然后调用 Kubectl 自动执行 K8s 资源部署
AI: Helm 是 Kubernetes 的包管理器,你可以把它想象成 Kubernetes 生态里的 “应用商店”或“软件包管理工具”,类似于 Ubuntu 中的
apt或 CentOS 中的yum。它的核心价值在于简化 Kubernetes 应用的打包、部署、版本管理和生命周期管理
| 核心概念 | 解释 | 简单类比 |
|---|---|---|
| Chart | Helm 的软件包,包含了一个应用所需的全部 Kubernetes 资源定义(YAML 模板)和配置参数。 | 类似于 Linux 系统中的 .deb或 .rpm安装包文件。 |
| Release | Chart 在集群中运行的一个实例。同一个 Chart 可以用不同的配置安装多次,每次都会生成一个独立的 Release。 | 类似于安装同一个软件包的多个副本,每个副本有自己独立的配置和数据。 |
| Repository (Repo) | Chart 的存放仓库,用于存储和共享 Chart。 | 类似于手机的应用商店(App Store)或 Linux 的软件源。 |
| Values | 一套配置参数(通常在 values.yaml文件中定义),用于在安装或升级时注入到 Chart 模板中,生成最终的 Kubernetes 资源清单。 |
类似于安装软件时让你选择的安装路径、语言等选项。 |
# 添加 Bitnami 仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
# 更新本地仓库缓存
helm repo update# 搜索 Redis Chart
helm search repo bitnami/redis
# 安装 Redis Chart,并设置密码
helm install my-redis-release bitnami/redis --set auth.password="my-secret-password"# 列出已安装的 Release
helm list
# 查看 Release 的状态和详细信息
helm status my-redis-release
# 升级 Release(如修改密码)
helm upgrade my-redis-release bitnami/redis --set auth.password="new-password"
# 如果升级出问题,回滚到上一个版本
helm rollback my-redis-release 1
# 卸载 Release
helm uninstall my-redis-release
- 自定义helm chart
# 生成一个名为 my-nginx 的 Chart 模板
helm create my-nginx# 这会创建一个包含以下结构的目录:
my-nginx/
├── Chart.yaml # Chart 元信息(名称、版本、依赖等)
├── values.yaml # 【核心】默认配置参数
└── templates/ # Kubernetes 资源模板├── deployment.yaml # 会引用 values.yaml 中的参数├── service.yaml└── ... # 其他可能存在的模板文件(如 ingress、hpa 等)
# 编辑 my-nginx/values.yaml文件,定义部署参数。以下是一个基础示例:
# my-nginx/values.yaml
# 副本数量
replicaCount: 1# 镜像配置
image:repository: nginx # 镜像仓库tag: "1.25-alpine" # 镜像标签pullPolicy: IfNotPresent # 镜像拉取策略# 服务配置
service:type: ClusterIP # 服务类型 (ClusterIP, NodePort, LoadBalancer)port: 80 # 服务端口# 资源限制(可选)
resources:limits:cpu: "500m" # CPU 限制memory: "256Mi" # 内存限制requests:cpu: "250m" # CPU 请求memory: "128Mi" # 内存请求# 自定义环境变量(可选)
env:LOG_LEVEL: "info"
10.2 Helm安装及演示
# 安装 Helm(以 Linux 为例)
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash# 验证安装
helm version
service:type: NodePort # 只需要修改需要修改的地方,helm会自动替换不同的地方
helm install -f values.yaml bitnami/apache --generate-name
10.3 ingress-nginx
10.3.1 七层负载的模拟演示
10.3.2 http代理
10.3.3 https代理
10.3.4 Basic Auth代理
10.3.5 域名重定向
10.3.6 Rewrite
匹配请求头
配置黑白名单
速率限制
灰色或金丝雀发布
代理后端https协议
四层代理
链路追踪