K8S AI 云原生架构师开箱即用高效学习方法
就是:不从头啃书,不先学理论,直接从「环境 + 工具 + 场景」入手,边跑边懂,边用边体系化。核心三句话:最简可落地方案:目标:10 分钟内能出来结果。基于 Docker Desktop 分别搭建 Kind 和 Minikube 这两种本地 Kubernetes 环境,我会为你提供分步、可落地的搭建教程,包括环境准备、安装步骤、验证方法和常见问题解决,两种方案都会覆盖。无论搭建 Kind 还是 M
一、什么是「云原生架构师 开箱学习法」
就是:不从头啃书,不先学理论,直接从「环境 + 工具 + 场景」入手,边跑边懂,边用边体系化。
核心三句话:
- 先有环境,再学概念
- 先跑通流程,再抠原理
- 先做项目,再补理论
二、K8S + AI 云原生架构师「开箱即用学习方法」
1)环境开箱:1 天内拥有自己的云原生实验场
最简可落地方案:
- 本地:Docker Desktop + Kind / Minikube
- 云:阿里云 / 腾讯云 / 华为云 轻量 K8s 集群
目标:10 分钟内 kubectl get nodes 能出来结果。
Docker Desktop + Kind / Minikube
基于 Docker Desktop 分别搭建 Kind 和 Minikube 这两种本地 Kubernetes 环境,我会为你提供分步、可落地的搭建教程,包括环境准备、安装步骤、验证方法和常见问题解决,两种方案都会覆盖。
一、前置环境准备(通用)
无论搭建 Kind 还是 Minikube,都需要先完成以下基础配置:
-
安装 Docker Desktop
- 下载地址:https://www.docker.com/products/docker-desktop/
- 安装完成后,打开 Docker Desktop,确保:
- 在
Settings > Resources > Advanced中,分配至少 2 CPU、4GB 内存(推荐 8GB),避免集群资源不足。 - 在
Settings > Kubernetes中,不要勾选 "Enable Kubernetes"(避免和 Kind/Minikube 冲突)。
- 在
- 验证 Docker 正常运行:
bash
运行
docker --version # 输出 Docker 版本,如 Docker version 25.0.3 docker info # 无报错即正常
-
安装 kubectl 命令行工具
- Windows/macOS(推荐):通过 Docker Desktop 自动安装(Docker Desktop > Settings > Kubernetes > 勾选 "Install kubectl")。
- 手动安装(适用于所有系统):
bash
运行
# macOS brew install kubectl # Windows(PowerShell) winget install Kubernetes.kubectl # Linux curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/ - 验证:
kubectl version --client(输出客户端版本即正常)。
二、方案 1:Docker Desktop + Kind 搭建
Kind(Kubernetes IN Docker)是纯 Docker 容器化的 K8s 集群,轻量、启动快,适合开发 / 测试。
步骤 1:安装 Kind
- macOS:
bash
运行
brew install kind - Windows(PowerShell):
bash
运行
winget install Kind.Kind - Linux / 通用:
bash
运行
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind - 验证:
kind version(输出 Kind 版本即正常)。
步骤 2:创建 Kind 集群
-
基础集群(单节点,推荐新手):
bash
运行
# 创建默认集群(名称为 kind) kind create cluster- 说明:Kind 会自动拉取 K8s 节点镜像,启动一个单节点集群,耗时约 1-3 分钟(取决于网络)。
-
自定义集群(可选,多节点):创建
kind-config.yaml文件:yaml
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane # 控制节点 - role: worker # 工作节点1 - role: worker # 工作节点2执行创建:
bash
运行
kind create cluster --config kind-config.yaml --name my-cluster
步骤 3:验证集群
bash
运行
# 查看 Kind 集群列表
kind get clusters
# 查看集群节点(kubectl 会自动关联 Kind 集群)
kubectl get nodes
# 输出示例(STATUS 为 Ready 即正常):
# NAME STATUS ROLES AGE VERSION
# kind-control-plane Ready control-plane 10s v1.29.0
步骤 4:删除集群(可选)
bash
运行
# 删除默认集群
kind delete cluster
# 删除指定名称的集群
kind delete cluster --name my-cluster
三、方案 2:Docker Desktop + Minikube 搭建
Minikube 是经典的本地 K8s 工具,支持多种驱动(这里用 Docker 驱动),功能更全,适合模拟生产环境。
步骤 1:安装 Minikube
- macOS:
bash
运行
brew install minikube - Windows(PowerShell):
bash
运行
winget install Kubernetes.minikube - Linux / 通用:
bash
运行
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube - 验证:
minikube version(输出版本即正常)。
步骤 2:启动 Minikube 集群
bash
运行
# 用 Docker 驱动启动(核心,指定 K8s 版本可选)
minikube start --driver=docker --kubernetes-version=v1.29.0
# 说明:
# --driver=docker:强制使用 Docker 驱动(依赖 Docker Desktop)
# --kubernetes-version:指定 K8s 版本(可选,不指定则用默认)
# 首次启动会拉取 Minikube 镜像和 K8s 节点镜像,耗时稍长(约 3-5 分钟)
步骤 3:验证集群
bash
运行
# 查看 Minikube 状态
minikube status
# 输出示例:
# minikube
# type: Control Plane
# host: Running
# kubelet: Running
# apiserver: Running
# 查看节点(STATUS 为 Ready 即正常)
kubectl get nodes
# 输出示例:
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 20s v1.29.0
# 启动 Minikube 仪表盘(可视化界面)
minikube dashboard
步骤 4:常用 Minikube 操作
bash
运行
# 停止集群(保留数据)
minikube stop
# 重启集群
minikube start
# 删除集群(清理所有数据)
minikube delete
# 查看 Minikube 配置
minikube config view
四、常见问题解决
- Kind/Minikube 启动失败:Docker 未运行
- 解决:确保 Docker Desktop 已启动,且
docker ps能正常执行。
- 解决:确保 Docker Desktop 已启动,且
- 拉取镜像超时
- 解决:给 Docker Desktop 配置国内镜像源(如阿里云、网易云),或手动拉取镜像:
bash
运行
# Kind 手动拉取镜像(示例) docker pull kindest/node:v1.29.0 # Minikube 手动拉取镜像(示例) minikube start --image-mirror-country cn --driver=docker
- 解决:给 Docker Desktop 配置国内镜像源(如阿里云、网易云),或手动拉取镜像:
- kubectl 无法连接集群
- 解决:Kind/Minikube 会自动配置
~/.kube/config,执行以下命令重置上下文:bash
运行
# Kind 切换上下文 kubectl config use-context kind-kind # Minikube 切换上下文 kubectl config use-context minikube
- 解决:Kind/Minikube 会自动配置
总结
- Kind 特点:超轻量、启动快(1 分钟内)、基于 Docker 容器,适合快速测试 K8s 命令 / 配置,无额外虚拟机开销。
- Minikube 特点:功能更全(支持仪表盘、Ingress、Metrics 等插件),模拟生产环境更真实,启动稍慢但稳定性更高。
- 核心验证步骤:无论哪种方案,最终通过
kubectl get nodes看到节点 STATUS 为Ready,即集群搭建成功。
你可根据需求选择:快速测试选 Kind,模拟生产环境选 Minikube,两者均基于 Docker Desktop,无需额外安装虚拟机(如 VirtualBox)。
阿里云、腾讯云、华为云的轻量 K8s 集群
基于 Docker Desktop + Kind/Minikube 的本地 K8s 搭建思路,适配到阿里云、腾讯云、华为云的轻量 K8s 集群上,我会针对三大云厂商的轻量 K8s 产品(托管版 / 轻量版),提供适配性的搭建步骤,包括集群创建、kubectl 连接、核心操作适配,同时说明云厂商环境和本地环境的核心差异。
核心前提说明
云厂商的轻量 K8s 集群和本地 Kind/Minikube 有本质区别:
- 本地:基于 Docker 模拟的单 / 多节点集群,仅用于测试,无公网暴露能力;
- 云厂商:托管式 K8s 集群(如阿里云 ACK 轻量版、腾讯云 TKE 轻量版、华为云 CCE 轻量版),由云厂商维护控制平面,你只需管理工作节点,支持公网访问、弹性扩缩容、高可用,且无需手动部署 Docker / 容器运行时。
因此无需在云服务器上安装 Kind/Minikube,而是直接使用云厂商的托管 K8s 服务,以下是三大云厂商的标准化搭建步骤。
一、阿里云 ACK 轻量版集群搭建
阿里云轻量 K8s 集群(ACK Serverless 版 / 轻量版)是性价比最高的托管 K8s 方案,无需购买专用控制节点。
步骤 1:创建 ACK 轻量版集群
- 登录阿里云控制台:https://cs.console.aliyun.com/
- 进入「容器服务 K8s 版」→「集群」→「创建集群」;
- 选择「轻量版集群」(或 Serverless 版,更省成本):
- 地域:选择就近地域(如华东 2 上海);
- 集群版本:选择稳定版(如 v1.28);
- 节点配置:选择轻量应用服务器(2 核 4G 起步),设置节点数量(1 节点即可测试);
- 网络:使用默认 VPC / 交换机(自动创建),开启公网访问;
- 其他:关闭「节点池自动扩缩容」(测试环境无需),密码 / 密钥登录二选一。
- 点击「创建」,等待 5-10 分钟,集群状态变为「运行中」。
步骤 2:配置 kubectl 连接集群
- 在集群列表页,点击目标集群→「连接信息」→「KubeConfig 」;
- 复制 KubeConfig 内容,替换本地
~/.kube/config文件(或新建文件); - 验证连接:
bash
运行
# 查看集群节点(云厂商节点 STATUS 为 Ready 即正常) kubectl get nodes # 输出示例: # NAME STATUS ROLES AGE VERSION # cn-hangzhou.i-xxxx Ready <none> 5m v1.28.0
步骤 3:核心操作适配(和本地 Kind/Minikube 一致)
云厂商集群的 kubectl 命令和本地完全通用,例如:
bash
运行
# 部署 Nginx 测试(和本地命令无区别)
kubectl create deployment nginx --image=nginx:1.25
kubectl expose deployment nginx --port=80 --type=NodePort
# 查看 Service(NodePort 可通过云服务器公网 IP 访问)
kubectl get svc nginx
二、腾讯云 TKE 轻量版集群搭建
腾讯云 TKE 轻量版基于轻量应用服务器,成本低、部署快,适配个人 / 小型团队。
步骤 1:创建 TKE 轻量版集群
- 登录腾讯云控制台:https://console.cloud.tencent.com/tke
- 进入「集群」→「新建」→ 选择「轻量应用集群」;
- 配置参数:
- 集群名称:自定义(如 tke-light-cluster);
- 地域 / 可用区:就近选择(如广州);
- K8s 版本:选择 v1.26+ 稳定版;
- 节点配置:轻量应用服务器(2 核 4G,1 节点),设置登录密码 / 密钥;
- 网络:默认私有网络,开启「公网访问」。
- 点击「创建集群」,等待 3-8 分钟,集群状态变为「运行中」。
步骤 2:配置 kubectl 连接
- 集群列表页→目标集群→「基本信息」→「获取 KubeConfig」;
- 将 KubeConfig 内容写入本地
~/.kube/config; - 验证:
bash
运行
kubectl get nodes # 输出腾讯云轻量节点信息,STATUS 为 Ready 即成功
步骤 3:关键适配点
- 腾讯云 TKE 轻量版默认开启「容器网络插件」(CNI),无需手动配置;
- 暴露服务时,NodePort 范围为 30000-32767,需在轻量服务器的「防火墙」中放行对应端口。
三、华为云 CCE 轻量版集群搭建
华为云 CCE 轻量版(又称「CCE 边缘集群」/「轻量版」)适配轻量服务器,操作逻辑和阿里云 / 腾讯云一致。
步骤 1:创建 CCE 轻量版集群
- 登录华为云控制台:https://console.huaweicloud.com/cce/
- 进入「集群」→「创建集群」→ 选择「轻量版集群」;
- 配置参数:
- 集群名称:自定义;
- 地域 / 可用区:就近选择(如北京四);
- K8s 版本:v1.27+;
- 节点配置:轻量应用服务器(2 核 4G,1 节点),设置登录凭证;
- 网络:使用默认 VPC,开启「公网访问」。
- 点击「立即创建」,等待 5-10 分钟完成部署。
步骤 2:配置 kubectl 连接
- 集群详情页→「连接集群」→「KubeConfig」→ 复制配置内容;
- 覆盖本地
~/.kube/config; - 验证:
bash
运行
kubectl get pods --all-namespaces # 查看系统组件是否正常运行
四、云厂商集群 vs 本地 Kind/Minikube 核心适配点
表格
| 操作场景 | 本地 Kind/Minikube | 云厂商轻量 K8s 集群 |
|---|---|---|
| 集群创建 | kind create cluster/minikube start |
云控制台可视化创建(无需命令) |
| kubectl 连接 | 自动生成 ~/.kube/config |
从云控制台复制 KubeConfig 手动配置 |
| 网络访问 | 仅本地端口转发(port-forward) |
支持 NodePort/LoadBalancer 公网访问 |
| 资源限制 | 依赖本地 Docker 资源(CPU / 内存) | 依赖云服务器配置,可弹性扩容 |
核心 kubectl 命令 |
完全通用(get/apply/logs等) |
完全通用,无差异 |
云厂商集群的额外实用操作(适配本地习惯)
- 端口转发(和本地一致):
bash
运行
# 本地访问云集群的 Nginx 服务(无需暴露公网) kubectl port-forward svc/nginx 8080:80 - 部署本地 YAML 文件(和本地一致):
bash
运行
# 本地写好的 deployment.yaml 直接部署到云集群 kubectl apply -f deployment.yaml - 查看云集群日志(和本地一致):
bash
运行
kubectl logs -f <pod-name>
五、常见问题解决
- kubectl 连接云集群超时:
- 检查云服务器「安全组」:放行 6443 端口(K8s API 端口);
- 确认 KubeConfig 中的
server地址是公网 IP / 域名,且能 ping 通。
- NodePort 服务无法访问:
- 云服务器防火墙 / 安全组放行对应 NodePort 端口(如 30080);
- 访问地址:
云服务器公网 IP:NodePort(如 120.78.xxx.xxx:30080)。
- 镜像拉取失败:
- 云厂商集群默认可访问公网镜像源(如 Docker Hub),若拉取慢,可配置云厂商私有镜像仓库(如阿里云 ACr、腾讯云 TCR)。
总结
- 核心适配逻辑:云厂商轻量 K8s 集群无需安装 Kind/Minikube,直接通过控制台创建托管集群,
kubectl核心命令和本地完全通用; - 关键差异:集群创建由云控制台完成(替代本地
kind create/minikube start),连接集群需手动配置云厂商提供的 KubeConfig; - 操作一致性:部署应用、查看日志、端口转发等核心操作和本地 Kind/Minikube 无区别,只需注意云服务器安全组 / 端口放行。
你可根据成本和地域选择云厂商:阿里云 ACK 生态最完善,腾讯云 TKE 轻量版性价比高,华为云 CCE 适配国产化场景,三者操作逻辑基本一致,核心 kubectl 命令无需修改即可复用。
2)命令开箱:只背 20 条高频 kubectl 命令
不用全学,架构师只需要能排查、能发布、能观测:
学习法:每条命令只练 3 分钟,跑通就过。
20 条高频 kubectl 命令(附说明 + 示例)
一、集群 / 节点信息查看
-
查看集群信息
bash
运行
kubectl cluster-info说明:显示集群的控制平面、Kubernetes DNS 等核心组件的地址,快速确认集群是否正常运行。
-
查看节点列表
bash
运行
kubectl get nodes # 查看节点详细信息(含标签、污点、状态) kubectl get nodes -o wide # 查看节点描述(排查节点异常) kubectl describe node <节点名称>说明:核心命令,用于确认节点状态(Ready/NotReady)、角色、资源配置等。
二、核心资源查看(Pod/Deployment/Service 等)
-
查看所有命名空间的 Pod
bash
运行
kubectl get pods --all-namespaces # 简写:kubectl get pods -A # 查看指定命名空间的 Pod(最常用) kubectl get pods -n <命名空间> # 查看 Pod 详细信息(IP、节点、容器等) kubectl get pods -n <命名空间> -o wide说明:日常排查 Pod 状态(Running/CrashLoopBackOff 等)的首要命令。
-
查看 Deployment
bash
运行
# 查看指定命名空间的 Deployment kubectl get deploy -n <命名空间> # 查看 Deployment 详细描述(含副本数、镜像、更新策略) kubectl describe deploy <deployment名称> -n <命名空间>说明:管理无状态应用的核心命令,确认部署的副本数、镜像版本等。
-
查看 Service
bash
运行
kubectl get svc -n <命名空间> # 查看 Service 详细信息(含 ClusterIP、端口映射、关联 Pod) kubectl get svc -n <命名空间> -o wide说明:确认服务的访问方式(ClusterIP/NodePort/LoadBalancer)和端口配置。
-
查看所有资源类型
bash
运行
# 查看指定命名空间的所有资源 kubectl get all -n <命名空间>说明:快速概览命名空间内的 Pod、Deployment、Service、ConfigMap 等所有资源,适合快速排查。
-
查看 ConfigMap/Secret
bash
运行
# 查看 ConfigMap kubectl get cm -n <命名空间> # 查看 Secret(默认加密显示,-o yaml 可看明文) kubectl get secret <secret名称> -n <命名空间> -o yaml说明:管理配置和敏感信息(如密码、token)的核心命令。
三、资源管理(创建 / 删除 / 更新)
-
通过 YAML 文件创建资源
bash
运行
kubectl apply -f <yaml文件路径> # 示例:kubectl apply -f deployment.yaml说明:最推荐的资源创建方式(幂等,重复执行不会报错),优于
create。 -
删除资源
bash
运行
# 删除指定 Pod kubectl delete pod <pod名称> -n <命名空间> # 删除 YAML 文件定义的资源 kubectl delete -f <yaml文件路径> # 强制删除卡住的 Pod(慎用) kubectl delete pod <pod名称> -n <命名空间> --force --grace-period=0 -
更新 Deployment 镜像
bash
运行
kubectl set image deployment/<deployment名称> <容器名>=<新镜像>:<版本> -n <命名空间> # 示例:kubectl set image deployment/myapp app=nginx:1.25 -n default说明:无需修改 YAML 文件,快速更新镜像版本,会自动触发滚动更新。
-
扩缩容 Deployment 副本数
bash
运行
# 缩放到 3 个副本 kubectl scale deployment <deployment名称> --replicas=3 -n <命名空间>
四、调试 / 排障(核心高频)
-
查看 Pod 日志
bash
运行
# 查看 Pod 实时日志(最常用) kubectl logs -f <pod名称> -n <命名空间> # 查看指定容器的日志(Pod 多容器时) kubectl logs -f <pod名称> -c <容器名> -n <命名空间> # 查看最近的日志(如最近 100 行) kubectl logs <pod名称> -n <命名空间> --tail=100说明:排查 Pod 启动失败、运行异常的核心命令。
-
进入 Pod 容器执行命令
bash
运行
# 进入容器交互终端(类似 ssh) kubectl exec -it <pod名称> -n <命名空间> -- /bin/bash # 若没有 bash,用 sh kubectl exec -it <pod名称> -n <命名空间> -- /bin/sh # 直接执行单条命令(无需进入容器) kubectl exec <pod名称> -n <命名空间> -- ls /app -
查看 Pod 事件(排查启动失败)
bash
运行
kubectl describe pod <pod名称> -n <命名空间>说明:重点看
Events部分,会显示 Pod 调度失败、镜像拉取失败、权限不足等关键原因。 -
端口转发(本地访问 Pod/Service)
bash
运行
# 将本地 8080 端口转发到 Pod 的 80 端口 kubectl port-forward <pod名称> 8080:80 -n <命名空间> # 转发到 Service(更稳定,Service 会自动转发到 Pod) kubectl port-forward svc/<service名称> 8080:80 -n <命名空间>说明:本地调试集群内服务的常用方式,无需暴露公网地址。
五、其他高频命令
-
查看资源标签
bash
运行
# 查看 Pod 的标签 kubectl get pods -n <命名空间> --show-labels # 根据标签筛选 Pod(常用) kubectl get pods -n <命名空间> -l app=myapp说明:标签是 Kubernetes 资源分组的核心,常用于筛选、调度。
-
编辑资源(临时修改)
bash
运行
kubectl edit deployment <deployment名称> -n <命名空间>说明:直接编辑资源的 YAML 配置(临时修改,推荐优先改 YAML 文件后
apply)。 -
查看资源的 YAML 配置
bash
运行
kubectl get pod <pod名称> -n <命名空间> -o yaml # 仅查看关键字段(精简输出) kubectl get pod <pod名称> -n <命名空间> -o jsonpath='{.status.podIP}' -
查看资源使用情况(CPU / 内存)
bash
运行
# 查看节点资源使用 kubectl top nodes # 查看 Pod 资源使用 kubectl top pods -n <命名空间>说明:需集群部署 metrics-server 才能使用,排查资源不足的核心命令。
-
设置默认命名空间(简化命令)
bash
运行
# 设置默认命名空间为 default(后续命令无需加 -n default) kubectl config set-context --current --namespace=default # 查看当前上下文 kubectl config current-context
总结
- 核心查看类:
kubectl get pods/deploy/svc -A -o wide、kubectl describe是日常排查的基础,优先掌握。 - 调试排障类:
kubectl logs -f、kubectl exec -it、kubectl port-forward是解决 Pod 异常的核心命令。 - 资源管理类:
kubectl apply -f(创建)、kubectl set image(更新镜像)、kubectl scale(扩缩容)是运维高频操作,推荐优先用 YAML 文件管理资源。
这些命令覆盖了 90% 以上的日常 Kubernetes 操作场景,建议结合实际场景多练习,可通过 kubectl <命令> --help 查看更多参数。
3)资源开箱:只学 8 个核心对象(足够做架构)
按优先级:
- Pod
- Deployment
- Service
- Ingress
- ConfigMap / Secret
- StatefulSet(AI 训练常用)
- PV/PVC
- Job / CronJob(AI 任务调度)
学习法:每个资源只做 1 件事:写 YAML → 部署 → 看效果 → 改配置。
POD
一、第一步:编写 Pod YAML 配置文件
我们先从最简单的 Nginx 单容器 Pod 入手,这是新手最易上手的示例。
1. 创建 YAML 文件(nginx-pod.yaml)
yaml
# API 版本,K8s 1.9+ 推荐使用 v1
apiVersion: v1
# 资源类型,这里是 Pod
kind: Pod
# 元数据:Pod 名称、标签等
metadata:
# Pod 名称(必须唯一)
name: nginx-demo
# 标签(用于筛选、关联其他资源)
labels:
app: nginx
env: test
# 核心配置:Pod 规约(容器、资源、重启策略等)
spec:
# 容器列表(Pod 可包含多个容器)
containers:
# 第一个容器(单容器 Pod 仅需这一个)
- name: nginx-container
# 容器镜像(默认从 Docker Hub 拉取)
image: nginx:1.25-alpine
# 端口配置(声明容器监听的端口,仅用于展示,非强制映射)
ports:
- containerPort: 80
# 资源限制(可选,避免容器占用过多节点资源)
resources:
requests:
cpu: "100m" # 最小申请 CPU(100毫核 = 0.1核)
memory: "128Mi" # 最小申请内存
limits:
cpu: "200m" # 最大可用 CPU
memory: "256Mi" # 最大可用内存
# 重启策略(Always:总是重启;OnFailure:失败时重启;Never:永不重启)
restartPolicy: Always
2. 关键配置解释
apiVersion+kind:固定组合,标识要创建的 K8s 资源类型(Pod 对应v1+Pod)。metadata.name:Pod 的唯一标识,部署后不能修改。spec.containers:Pod 的核心,定义容器的镜像、端口、资源等。image:建议指定具体版本(如1.25-alpine),避免拉取 latest 镜像导致版本不一致。resources:新手建议配置,防止单个 Pod 占满节点资源。
二、第二步:部署 Pod 到 K8s 集群
部署前请确保:
- 已安装并配置好
kubectl命令行工具。 kubectl config get-contexts能看到可用的 K8s 集群(本地可使用 Minikube、Kind 或 Docker Desktop 内置的 K8s)。
1. 执行部署命令
bash
运行
# 应用 YAML 文件创建 Pod
kubectl apply -f nginx-pod.yaml
成功输出:pod/nginx-demo created
2. 验证部署是否提交
bash
运行
# 查看所有 Pod 的状态
kubectl get pods
初始状态可能是 Pending(拉取镜像),等待几秒后变为 Running 即部署成功。
三、第三步:查看 Pod 运行效果
部署成功后,通过一系列命令验证 Pod 的状态、日志、网络等,确认运行符合预期。
1. 基础状态查看
bash
运行
# 查看 Pod 详细信息(名称、状态、重启次数、所在节点)
kubectl get pod nginx-demo
# 查看 Pod 详细描述(包含事件、容器状态、IP 等)
kubectl describe pod nginx-demo
重点关注:
Status:Running表示正常运行。IP:Pod 的唯一内网 IP(如10.244.0.5)。Events:无Error或Warning即无异常。
2. 访问 Pod 内的 Nginx 服务
Pod 运行在 K8s 内网,有两种方式访问:
方式 1:端口转发(本地直接访问)
bash
运行
# 将本地 8080 端口转发到 Pod 的 80 端口
kubectl port-forward nginx-demo 8080:80
打开浏览器访问 http://localhost:8080,能看到 Nginx 默认页面即成功。
方式 2:进入 Pod 内部验证
bash
运行
# 进入 Pod 的容器内执行命令
kubectl exec -it nginx-demo -- /bin/sh
# 验证 Nginx 是否运行
ps aux | grep nginx
# 测试本地访问
curl http://localhost
# 退出容器
exit
3. 查看 Pod 日志
bash
运行
# 查看实时日志
kubectl logs nginx-demo -f
# 查看指定时间段的日志
kubectl logs nginx-demo --since=10m
四、第四步:修改配置并重新部署
实际开发中常需调整 Pod 配置(如镜像版本、资源限制、端口等),我们以「升级 Nginx 版本 + 调整资源限制」为例演示。
1. 修改 YAML 文件(nginx-pod.yaml)
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
labels:
app: nginx
env: test
spec:
containers:
- name: nginx-container
# 1. 升级镜像版本到 1.26-alpine
image: nginx:1.26-alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "150m" # 2. 提高最小 CPU 申请
memory: "128Mi"
limits:
cpu: "300m" # 3. 提高最大 CPU 限制
memory: "512Mi" # 4. 提高最大内存限制
restartPolicy: Always
2. 注意:Pod 是「不可变资源」
K8s 不支持直接修改已运行 Pod 的核心配置(如镜像、资源限制),必须先删除旧 Pod,再重新创建:
bash
运行
# 1. 删除旧 Pod
kubectl delete pod nginx-demo
# 2. 应用修改后的 YAML 重新部署
kubectl apply -f nginx-pod.yaml
3. 验证修改效果
bash
运行
# 查看 Pod 状态
kubectl get pod nginx-demo
# 查看容器镜像是否更新
kubectl describe pod nginx-demo | grep "Image:"
# 验证 Nginx 版本
kubectl exec -it nginx-demo -- nginx -v
输出 nginx version: nginx/1.26.0 即版本升级成功。
拓展:生产环境更优方案
新手阶段用「删除重建」没问题,但生产环境建议用 Deployment 管理 Pod(支持滚动更新、回滚),只需将 YAML 中的 kind 改为 Deployment,并增加 replicas(副本数)即可,示例:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2 # 运行 2 个 Pod 副本
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.26-alpine
ports:
- containerPort: 80
部署后修改配置可直接 kubectl apply -f xxx.yaml,Deployment 会自动滚动更新 Pod,无需手动删除。
总结
- 核心流程:编写 YAML(定义 Pod 规格)→
kubectl apply部署 →kubectl get/describe/logs验证 → 修改 YAML 后删除重建(或用 Deployment 滚动更新)。 - 关键特性:Pod 是 K8s 最小部署单元,不可直接修改核心配置,需重建;单容器 Pod 是最常用形式。
- 实用命令:
kubectl apply(部署)、kubectl get pods(查状态)、kubectl describe pod(查详情)、kubectl exec(进容器)、kubectl logs(看日志)。
这套流程覆盖了 Pod 从创建到修改的全生命周期,掌握后可以尝试修改更多配置(如添加环境变量、挂载存储卷),进一步加深理解。
Deploment
Deployment 是 K8s 中管理 Pod 最核心的控制器,解决了 Pod 「不可变」和「无自愈能力」的问题,我会延续「写 YAML → 部署 → 看效果 → 改配置」的流程,带你完整掌握 Deployment 的使用。
一、第一步:编写 Deployment YAML 配置文件
Deployment 本质是管理 Pod 的控制器,它会自动创建、维护指定数量的 Pod 副本,还支持滚动更新、回滚等核心能力。我们基于之前的 Nginx Pod 改造为 Deployment。
1. 创建 YAML 文件(nginx-deployment.yaml)
yaml
# API 版本:Deployment 属于 apps 组,1.9+ 推荐使用 apps/v1
apiVersion: apps/v1
# 资源类型:Deployment
kind: Deployment
# 元数据:Deployment 名称、标签
metadata:
name: nginx-deployment
labels:
app: nginx
type: deployment
# 核心配置:Deployment 规约
spec:
# 副本数:指定要运行的 Pod 数量(核心特性)
replicas: 2
# 标签选择器:匹配要管理的 Pod(必须和 Pod 模板中的 labels 一致)
selector:
matchLabels:
app: nginx
env: test
# 更新策略:默认 RollingUpdate(滚动更新),可选 Recreate(先删所有再重建)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滚动更新时最多可超出的 Pod 数(1 个或 25%)
maxUnavailable: 0 # 滚动更新时最多不可用的 Pod 数(0 表示始终保证可用)
# Pod 模板:定义要创建的 Pod 规格(和之前的 Pod YAML 几乎一致)
template:
metadata:
# Pod 的标签:必须被上面的 selector.matchLabels 匹配
labels:
app: nginx
env: test
spec:
containers:
- name: nginx-container
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: Always
2. 关键配置解释(对比 Pod 的核心差异)
表格
| 配置项 | 作用 |
|---|---|
replicas: 2 |
自动维护 2 个 Pod 副本,若某个 Pod 挂了,Deployment 会自动重建 |
selector.matchLabels |
关联 Deployment 和 Pod,必须和 template.metadata.labels 完全匹配 |
strategy |
滚动更新策略:保证更新过程中服务不中断(生产环境核心需求) |
template |
嵌套的 Pod 模板:Deployment 会根据这个模板创建 / 重建 Pod |
二、第二步:部署 Deployment 到 K8s 集群
部署前仍需确保 kubectl 已连接 K8s 集群(Minikube/Kind/Docker Desktop)。
1. 执行部署命令
bash
运行
# 应用 YAML 文件创建 Deployment
kubectl apply -f nginx-deployment.yaml
成功输出:deployment.apps/nginx-deployment created
2. 验证部署提交
bash
运行
# 查看 Deployment 状态
kubectl get deployments
# 简写:kubectl get deploy
输出示例(READY 为 2/2 表示所有 Pod 已就绪):
plaintext
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 10s
三、第三步:查看 Deployment 运行效果
Deployment 的核心价值是「管理 Pod」,所以除了看 Deployment 本身,重点要验证它对 Pod 的管控能力。
1. 查看 Deployment 详情
bash
运行
# 查看 Deployment 详细信息(包含事件、更新策略、Pod 模板等)
kubectl describe deployment nginx-deployment
重点关注:
Replicas:Desired(期望)2 → Current(当前)2 → Ready(就绪)2。Events:无 Error/Warning,且有SuccessfulCreate事件(表示成功创建 Pod)。
2. 查看 Deployment 管理的 Pod
bash
运行
# 查看所有 Pod(会看到 2 个以 nginx-deployment-xxx 命名的 Pod)
kubectl get pods -l app=nginx # 通过标签筛选 Deployment 管理的 Pod
输出示例(Pod 名称包含随机后缀,由 Deployment 自动生成):
plaintext
NAME READY STATUS RESTARTS AGE
nginx-deployment-7f987d6c74-2x89s 1/1 Running 0 30s
nginx-deployment-7f987d6c74-9k75b 1/1 Running 0 30s
3. 验证 Deployment 的「自愈能力」
这是 Deployment 对比原生 Pod 的核心优势:手动删除一个 Pod,Deployment 会自动重建。
bash
运行
# 手动删除其中一个 Pod(替换为你的 Pod 名称)
kubectl delete pod nginx-deployment-7f987d6c74-2x89s
# 立即查看 Pod 状态
kubectl get pods -l app=nginx
你会发现:被删除的 Pod 状态变为 Terminating,同时会立即出现一个新的 Pod(名称不同),最终仍保持 2 个运行中的 Pod 副本。
4. 访问 Pod 内的 Nginx 服务
和之前一样,用端口转发访问(任选一个 Pod 即可):
bash
运行
kubectl port-forward nginx-deployment-7f987d6c74-9k75b 8080:80
访问 http://localhost:8080 即可看到 Nginx 默认页面。
四、第四步:修改配置并重新部署
Deployment 最大的优势是支持无中断的滚动更新,无需手动删除 Pod,直接修改 YAML 后重新 apply 即可。我们以「升级 Nginx 版本 + 调整副本数」为例。
1. 修改 YAML 文件(nginx-deployment.yaml)
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
type: deployment
spec:
replicas: 3 # 1. 副本数从 2 增加到 3
selector:
matchLabels:
app: nginx
env: test
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: nginx
env: test
spec:
containers:
- name: nginx-container
image: nginx:1.26-alpine # 2. 镜像版本从 1.25 升级到 1.26
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: Always
2. 应用修改后的配置(滚动更新)
bash
运行
# 直接 apply,Deployment 会自动执行滚动更新
kubectl apply -f nginx-deployment.yaml
成功输出:deployment.apps/nginx-deployment configured
3. 查看更新过程
bash
运行
# 实时查看 Deployment 状态(watch 表示实时刷新)
kubectl get deploy nginx-deployment -w
# 查看 Pod 滚动更新过程
kubectl get pods -l app=nginx -w
你会看到:
- 先创建新的 Pod(使用 1.26 镜像)→ 新 Pod 就绪后,删除旧 Pod(1.25 镜像)→ 最终保留 3 个新 Pod。
- 整个过程中始终有至少 2 个 Pod 运行,服务不中断(因为
maxUnavailable: 0)。
4. 验证更新效果
bash
运行
# 查看 Deployment 副本数是否为 3
kubectl get deploy nginx-deployment
# 验证 Pod 镜像版本
kubectl exec -it $(kubectl get pod -l app=nginx -o jsonpath="{.items[0].metadata.name}") -- nginx -v
输出 nginx version: nginx/1.26.0 即版本升级成功,且 Pod 数量为 3。
拓展:Deployment 回滚(生产必备)
如果更新后发现问题,可快速回滚到上一个版本:
bash
运行
# 查看 Deployment 版本历史
kubectl rollout history deployment/nginx-deployment
# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
# 验证回滚结果(镜像回到 1.25-alpine,副本数回到 2)
kubectl describe deployment nginx-deployment | grep "Image:"
总结
- 核心定位:Deployment 是 K8s 管理 Pod 的首选控制器,解决了 Pod 「不可变」「无自愈」「更新易中断」的问题。
- 核心流程:写 Deployment YAML(包含 Pod 模板 + 副本数 + 更新策略)→
kubectl apply部署 → 验证 Pod 副本数和自愈能力 → 修改配置后kubectl apply实现滚动更新(支持回滚)。 - 关键优势:自动维护 Pod 副本数、滚动更新不中断服务、支持版本回滚,是生产环境部署应用的标准方式(而非直接创建 Pod)。
掌握这套流程后,你可以尝试修改更多配置(如更新策略、添加环境变量),或结合 Service 暴露 Deployment 管理的 Pod 服务,进一步贴近生产场景。
Service
Service 解决了 Deployment 管理的 Pod 「IP 动态变化」「无法统一访问」的问题,是 K8s 中暴露应用服务的标准方式。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,带你完整掌握 Service 的使用,且和之前的 Deployment 无缝衔接。
一、第一步:编写 Service YAML 配置文件
Service 本质是固定访问入口 + 负载均衡器,通过标签选择器关联 Deployment 管理的 Pod,无论 Pod 如何重建、IP 如何变化,Service 的访问地址始终不变。
我们基于之前的 nginx-deployment 创建对应的 Service(以最常用的 ClusterIP 类型为例,后续拓展其他类型)。
1. 创建 YAML 文件(nginx-service.yaml)
yaml
# API 版本:Service 属于核心组,使用 v1
apiVersion: v1
# 资源类型:Service
kind: Service
# 元数据:Service 名称、标签
metadata:
name: nginx-service
labels:
app: nginx
type: service
# 核心配置:Service 规约
spec:
# Service 类型(核心):
# - ClusterIP:仅集群内可访问(默认)
# - NodePort:集群内 + 节点端口访问
# - LoadBalancer:云厂商提供外部负载均衡器
# - ExternalName:映射到外部域名
type: ClusterIP
# 标签选择器:匹配要关联的 Pod(必须和 Deployment 的 Pod 模板 labels 一致)
selector:
app: nginx
env: test
# 端口映射:Service 端口 → Pod 容器端口
ports:
- name: http # 端口名称(可选,建议配置,便于区分)
protocol: TCP # 协议(TCP/UDP,默认 TCP)
port: 80 # Service 暴露的端口(集群内访问用这个端口)
targetPort: 80 # Pod 容器的端口(必须和容器监听的端口一致)
# sessionAffinity: ClientIP # 可选,会话亲和性(同一客户端始终访问同一个 Pod)
2. 关键配置解释(和 Deployment 关联的核心)
表格
| 配置项 | 作用 |
|---|---|
type: ClusterIP |
最基础的 Service 类型,分配一个集群内唯一的虚拟 IP(ClusterIP),仅集群内可访问 |
selector |
核心!通过标签匹配 Deployment 管理的 Pod,必须和 Pod 的 labels 完全匹配 |
ports.port |
Service 自身的端口(集群内访问 Service 时用这个端口) |
ports.targetPort |
映射到 Pod 容器的端口(必须和容器的 containerPort 一致) |
二、第二步:部署 Service 到 K8s 集群
部署前确保:
- 之前的
nginx-deployment已正常运行(有 3 个 Pod 副本)。 kubectl已连接 K8s 集群。
1. 执行部署命令
bash
运行
# 应用 YAML 文件创建 Service
kubectl apply -f nginx-service.yaml
成功输出:service/nginx-service created
2. 验证部署提交
bash
运行
# 查看 Service 状态
kubectl get services
# 简写:kubectl get svc
输出示例(重点看 CLUSTER-IP 和 PORT(S)):
plaintext
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1d
nginx-service ClusterIP 10.96.123.45 <none> 80/TCP 10s
三、第三步:查看 Service 运行效果
Service 的核心价值是「固定访问入口 + 负载均衡」,我们从集群内、集群外两个维度验证效果。
1. 查看 Service 详情
bash
运行
# 查看 Service 详细信息(包含关联的 Pod、ClusterIP 等)
kubectl describe service nginx-service
重点关注:
Selector:app=nginx,env=test(和 Deployment 的 Pod 标签匹配)。Endpoints:列出关联的所有 Pod 的 IP + 端口(如10.244.0.5:80,10.244.0.6:80,10.244.0.7:80),表示 Service 已成功关联 Pod。ClusterIP:Service 的虚拟 IP(如10.96.123.45),集群内可通过这个 IP+80 端口访问。
2. 验证集群内访问(核心)
Service 的 ClusterIP 仅集群内可访问,我们通过「临时 Pod」模拟集群内访问:
bash
运行
# 创建一个临时的 busybox Pod,用于测试访问
kubectl run test-pod --image=busybox:1.36 --rm -it -- /bin/sh
# 进入 Pod 后,执行以下命令访问 Service
wget -q -O - http://nginx-service:80 # 用 Service 名称访问(K8s 内置 DNS 解析)
# 或用 ClusterIP 访问
wget -q -O - http://10.96.123.45:80
输出 Nginx 默认页面的 HTML 内容,说明访问成功!且多次执行会发现请求被负载均衡到不同的 Pod(可通过 Pod 日志验证)。
3. 验证「IP 变化不影响访问」(Service 核心优势)
手动删除一个 Pod,Deployment 会重建新 Pod(IP 变化),但 Service 会自动更新 Endpoints,访问不受影响:
bash
运行
# 1. 删除一个 Pod(替换为你的 Pod 名称)
kubectl delete pod nginx-deployment-7f987d6c74-2x89s
# 2. 等待新 Pod 创建完成
kubectl get pods -l app=nginx
# 3. 再次用 test-pod 访问 Service
wget -q -O - http://nginx-service:80
依然能正常访问,说明 Service 自动感知了 Pod 的变化。
四、第四步:修改配置(切换 Service 类型)
实际场景中,常需要将 Service 从「仅集群内访问」改为「对外暴露」,我们以切换为 NodePort 类型为例(适合测试 / 小规模场景)。
1. 修改 YAML 文件(nginx-service.yaml)
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
type: service
spec:
type: NodePort # 1. 改为 NodePort 类型
selector:
app: nginx
env: test
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080 # 2. 指定节点端口(可选,范围 30000-32767)
2. 应用修改后的配置
bash
运行
# 直接 apply,Service 会自动更新类型
kubectl apply -f nginx-service.yaml
成功输出:service/nginx-service configured
3. 验证 NodePort 访问
bash
运行
# 查看 Service 状态,确认 NodePort 已分配
kubectl get svc nginx-service
输出示例(PORT(S) 列显示 80:30080/TCP):
plaintext
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.96.123.45 <none> 80:30080/TCP 5m
现在可以通过「节点 IP + 30080 端口」访问 Nginx:
- 如果是 Minikube:先执行
minikube ip获取节点 IP,然后访问http://<minikube-ip>:30080。 - 如果是 Docker Desktop:直接访问
http://localhost:30080。 - 如果是云服务器集群:访问
http://<节点公网IP>:30080。
拓展:生产环境常用 Service 类型
表格
| 类型 | 适用场景 | 访问方式 |
|---|---|---|
| ClusterIP | 集群内服务间通信(默认) | 集群内 Pod 访问 Service 名称 / IP |
| NodePort | 测试 / 小流量对外暴露 | 节点 IP + 固定端口 |
| LoadBalancer | 生产环境对外暴露(云厂商) | 云厂商分配的外部 IP |
| Ingress | 多服务统一入口(替代 LB) | 域名 + HTTP/HTTPS(需部署 Ingress Controller) |
总结
- 核心定位:Service 是 K8s 中应用服务的「固定访问入口」,解决了 Pod IP 动态变化、无法统一访问的问题,且内置负载均衡能力。
- 核心流程:写 Service YAML(指定类型 + 标签选择器 + 端口映射)→
kubectl apply部署 → 验证集群内 / 外访问 → 修改配置切换 Service 类型(如 ClusterIP → NodePort)。 - 关键关联:Service 通过
selector与 Deployment/Pod 关联,无需手动绑定,Pod 变化时 Service 自动更新 Endpoints,保证访问不中断。
至此,你已掌握 K8s 应用部署的核心三件套:Deployment(管理 Pod) + Service(暴露服务) + Pod(运行容器),这是 K8s 部署无状态应用的标准架构。接下来可以尝试结合 Ingress 实现域名访问,或部署有状态应用(StatefulSet),进一步完善 K8s 知识体系。
Ingress
Ingress 解决了 Service(尤其是 NodePort/LoadBalancer)「端口有限」「无域名 / 路径路由」「无 HTTPS 支持」的问题,是 K8s 中多服务统一入口的标准方案。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,带你完整掌握 Ingress,且和之前的 Deployment + Service 无缝衔接。
一、前置说明
Ingress 分为两部分:
- Ingress 资源:定义路由规则(域名、路径 → Service)。
- Ingress Controller:执行路由规则的组件(如 Nginx Ingress Controller),需先部署,否则 Ingress 资源仅为「空规则」。
我们先部署 Ingress Controller(以最常用的 Nginx Ingress 为例),再编写 Ingress 规则。
二、第一步:部署 Ingress Controller + 编写 Ingress YAML
1. 部署 Nginx Ingress Controller(环境适配)
不同环境部署命令不同,选择对应方式:
bash
运行
# 方式 1:Minikube(一键部署)
minikube addons enable ingress
# 方式 2:Docker Desktop/K8s 集群(官方推荐,适用于 1.19+)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.0/deploy/static/provider/cloud/deploy.yaml
# 验证 Controller 运行(等待 STATUS 为 Running)
kubectl get pods -n ingress-nginx
2. 编写 Ingress YAML 配置文件(nginx-ingress.yaml)
基于之前的 nginx-service 创建 Ingress 规则,实现「域名访问 → Service → Pod」的路由:
yaml
# API 版本:Ingress 属于 networking.k8s.io 组,1.19+ 推荐 v1
apiVersion: networking.k8s.io/v1
# 资源类型:Ingress
kind: Ingress
# 元数据:Ingress 名称、注解(核心!用于配置 Ingress Controller 特性)
metadata:
name: nginx-ingress
labels:
app: nginx
# 注解:针对 Nginx Ingress Controller 的配置(如默认后端、SSL、重定向等)
annotations:
# 指定使用 Nginx Ingress Controller(多 Controller 时必须)
kubernetes.io/ingress.class: "nginx"
# 可选:将 HTTP 重定向到 HTTPS(后续配置证书后启用)
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# 可选:设置客户端请求超时时间
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30s"
# 核心配置:Ingress 规则
spec:
# 规则列表(可配置多个域名)
rules:
# 第一个域名规则
- host: nginx.example.com # 访问域名(需配置本地 hosts 解析)
http:
paths:
# 路径规则 1:根路径 → nginx-service
- path: /
pathType: Prefix # 路径匹配类型:Prefix(前缀匹配)/ Exact(精确匹配)
backend:
service:
# 关联的 Service 名称
name: nginx-service
# 关联的 Service 端口
port:
number: 80
# 可选:添加第二个域名/路径规则(演示多服务路由)
# - host: app.example.com
# http:
# paths:
# - path: /app
# pathType: Prefix
# backend:
# service:
# name: app-service
# port:
# number: 8080
# 可选:配置 HTTPS 证书(需先创建 Secret 存储证书)
# tls:
# - hosts:
# - nginx.example.com
# secretName: nginx-tls-secret
3. 关键配置解释
表格
| 配置项 | 作用 |
|---|---|
annotations |
针对 Ingress Controller 的自定义配置,不同 Controller 注解不同(如 Nginx vs Traefik) |
rules.host |
访问域名(如 nginx.example.com),需在本地 hosts 或 DNS 解析到 Ingress Controller 的 IP |
paths.path |
域名下的路径(如 /),支持前缀 / 精确匹配 |
paths.backend |
路由目标:关联的 Service 名称 + 端口,Ingress 会将请求转发到该 Service |
pathType |
匹配规则:Prefix(前缀匹配,如 / 匹配所有路径)、Exact(精确匹配,如 / 仅匹配根路径) |
三、第二步:部署 Ingress 并配置域名解析
1. 部署 Ingress 资源
bash
运行
# 应用 YAML 文件创建 Ingress
kubectl apply -f nginx-ingress.yaml
成功输出:ingress.networking.k8s.io/nginx-ingress created
2. 配置本地域名解析(关键)
Ingress 的 host 是 nginx.example.com,需将该域名解析到 Ingress Controller 的 IP:
bash
运行
# 步骤 1:获取 Ingress Controller 的 IP
# Minikube 环境
minikube ip # 输出如 192.168.49.2
# Docker Desktop 环境
kubectl get svc ingress-nginx-controller -n ingress-nginx # 查看 EXTERNAL-IP(通常是 localhost/127.0.0.1)
# 云服务器集群
kubectl get svc ingress-nginx-controller -n ingress-nginx # 查看 EXTERNAL-IP(云厂商分配的公网 IP)
# 步骤 2:修改本地 hosts 文件(Windows: C:\Windows\System32\drivers\etc\hosts;Linux/Mac: /etc/hosts)
# 添加一行:Ingress Controller IP + 域名
# 示例:
192.168.49.2 nginx.example.com
四、第三步:查看 Ingress 运行效果
1. 查看 Ingress 状态
bash
运行
# 查看 Ingress 资源
kubectl get ingress
# 简写:kubectl get ing
输出示例(HOSTS 为配置的域名,ADDRESS 为 Ingress Controller IP):
plaintext
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress nginx nginx.example.com 192.168.49.2 80 10s
2. 验证域名访问(核心)
bash
运行
# 方式 1:curl 访问(直接验证路由)
curl http://nginx.example.com
# 方式 2:浏览器访问
# 打开 http://nginx.example.com,能看到 Nginx 默认页面即成功
此时请求流程:浏览器/客户端 → nginx.example.com → Ingress Controller → nginx-service → 负载均衡到 Pod。
3. 验证「多路径 / 多服务路由」(拓展)
如果添加了第二个路径规则(如 /app → app-service),可验证:
bash
运行
curl http://nginx.example.com/app
请求会被 Ingress 路由到 app-service 对应的 Pod,实现「一个域名 + 不同路径 → 不同服务」的核心能力。
五、第四步:修改配置(添加 HTTPS 支持)
生产环境中,Ingress 最常用的扩展是配置 HTTPS,我们以「自签名证书」为例演示(生产需用 Let's Encrypt 等合法证书)。
1. 生成自签名证书并创建 Secret
bash
运行
# 生成自签名证书(替换域名为 nginx.example.com)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=nginx.example.com/O=nginx-example"
# 创建 K8s Secret 存储证书(名称需和 Ingress 的 tls.secretName 一致)
kubectl create secret tls nginx-tls-secret --key tls.key --cert tls.crt
2. 修改 Ingress YAML(启用 HTTPS)
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
labels:
app: nginx
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-redirect: "true" # 强制 HTTP 重定向到 HTTPS
spec:
rules:
- host: nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
# 添加 TLS 配置
tls:
- hosts:
- nginx.example.com # 证书对应的域名
secretName: nginx-tls-secret # 存储证书的 Secret 名称
3. 应用修改并验证 HTTPS 访问
bash
运行
# 应用更新后的 Ingress 配置
kubectl apply -f nginx-ingress.yaml
# 验证 HTTPS 访问(-k 忽略自签名证书警告)
curl -k https://nginx.example.com
此时访问 http://nginx.example.com 会自动重定向到 https://nginx.example.com,实现 HTTPS 访问。
总结
- 核心定位:Ingress 是 K8s 多服务的「统一入口」,解决了 Service 无域名 / 路径路由、无 HTTPS 的问题,由「Ingress 资源(规则) + Ingress Controller(执行)」组成。
- 核心流程:部署 Ingress Controller → 编写 Ingress YAML(定义域名 / 路径 → Service 路由规则)→ 配置域名解析 → 验证域名访问 → 修改配置启用 HTTPS 等高级特性。
- 关键优势:支持域名 / 路径路由、HTTPS、请求重定向、负载均衡,是生产环境暴露多服务的标准方案(替代多个 NodePort/LoadBalancer Service)。
至此,你已掌握 K8s 无状态应用部署的完整架构:Pod(运行容器) → Deployment(管理 Pod) → Service(固定访问入口) → Ingress(统一域名入口)。这是 K8s 最核心、最常用的部署模式,后续可进一步学习 StatefulSet(有状态应用)、ConfigMap/Secret(配置管理)等进阶内容。
ConfigMap
ConfigMap 解决了「配置和容器镜像解耦」的问题,能将配置文件、环境变量等抽离出来,避免修改配置时重新构建镜像。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,结合之前的 Nginx Deployment 来讲解,让你直观理解 ConfigMap 的使用场景和价值。
一、第一步:编写 ConfigMap YAML 配置文件
ConfigMap 本质是K8s 中存储非敏感配置的键值对资源,支持两种存储形式:
- 键值对形式(适合零散配置,如环境变量);
- 文件形式(适合完整配置文件,如 Nginx 配置、应用配置文件)。
我们以「替换 Nginx 默认配置」为例,编写 ConfigMap YAML(覆盖 Nginx 的默认首页和基础配置)。
1. 创建 ConfigMap YAML 文件(nginx-configmap.yaml)
yaml
# API 版本:ConfigMap 属于核心组,使用 v1
apiVersion: v1
# 资源类型:ConfigMap
kind: ConfigMap
# 元数据:ConfigMap 名称、标签
metadata:
name: nginx-config
labels:
app: nginx
# 核心配置:配置数据(键值对/文件内容)
data:
# 形式 1:零散键值对(可作为环境变量注入 Pod)
nginx_port: "80"
nginx_worker_processes: "auto"
# 形式 2:完整配置文件(键为文件名,值为文件内容)
default.conf: |
server {
listen ${NGINX_PORT}; # 引用环境变量(需配合 envsubst)
server_name localhost;
# 修改默认首页
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# 新增健康检查接口
location /health {
access_log off;
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
}
# 自定义 Nginx 首页内容
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>ConfigMap Demo</title>
<meta charset="utf-8">
</head>
<body>
<h1>Hello from ConfigMap!</h1>
<p>This page is loaded from K8s ConfigMap.</p>
</body>
</html>
2. 关键配置解释
表格
| 配置项 | 作用 | |
|---|---|---|
data |
ConfigMap 的核心,存储所有配置数据,支持「键值对」和「多行文本(文件)」两种形式 | |
key: "value" |
零散键值对:适合作为环境变量注入 Pod,如 nginx_port: "80" |
|
| `filename: | ` | 多行文本:模拟配置文件,键为文件名(如 default.conf),值为文件内容 |
| ` | ` 符号 | 保留多行文本的格式(换行、缩进),确保配置文件语法正确 |
二、第二步:部署 ConfigMap + 修改 Deployment 挂载配置
ConfigMap 本身不运行,需通过「环境变量」或「挂载卷」的方式注入到 Pod 中,我们结合之前的 Nginx Deployment 来演示。
1. 部署 ConfigMap
bash
运行
# 应用 YAML 创建 ConfigMap
kubectl apply -f nginx-configmap.yaml
成功输出:configmap/nginx-config created
2. 验证 ConfigMap 部署
bash
运行
# 查看 ConfigMap 列表
kubectl get configmaps
# 简写:kubectl get cm
# 查看 ConfigMap 详情(验证配置内容)
kubectl describe cm nginx-config
3. 修改 Deployment YAML(挂载 ConfigMap 到 Pod)
修改之前的 nginx-deployment.yaml,添加「环境变量注入」和「配置文件挂载」:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
env: test
template:
metadata:
labels:
app: nginx
env: test
spec:
containers:
- name: nginx-container
image: nginx:1.26-alpine
ports:
- containerPort: 80
# 方式 1:从 ConfigMap 注入环境变量
env:
- name: NGINX_PORT # Pod 内的环境变量名
valueFrom:
configMapKeyRef:
name: nginx-config # 关联的 ConfigMap 名称
key: nginx_port # 要引用的 ConfigMap 键
# 方式 2:挂载 ConfigMap 为文件(覆盖 Nginx 配置和首页)
volumeMounts:
# 挂载自定义 Nginx 配置文件
- name: nginx-conf-volume
mountPath: /etc/nginx/conf.d/default.conf # 覆盖默认配置文件
subPath: default.conf # 指定 ConfigMap 中的键(文件名)
# 挂载自定义首页
- name: nginx-html-volume
mountPath: /usr/share/nginx/html/index.html # 覆盖默认首页
subPath: index.html
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
# 定义要挂载的卷(关联 ConfigMap)
volumes:
- name: nginx-conf-volume
configMap:
name: nginx-config # 关联的 ConfigMap 名称
items:
- key: default.conf # ConfigMap 中的键
path: default.conf # 卷内的文件名(和 subPath 对应)
- name: nginx-html-volume
configMap:
name: nginx-config
items:
- key: index.html
path: index.html
4. 重新部署 Deployment
bash
运行
# 应用修改后的 Deployment 配置(触发滚动更新)
kubectl apply -f nginx-deployment.yaml
三、第三步:查看 ConfigMap 运行效果
验证 ConfigMap 中的配置是否成功注入 Pod 并生效。
1. 验证环境变量注入
bash
运行
# 进入任意一个 Nginx Pod
kubectl exec -it $(kubectl get pod -l app=nginx -o jsonpath="{.items[0].metadata.name}") -- /bin/sh
# 查看环境变量
echo $NGINX_PORT
# 输出:80(和 ConfigMap 中的 nginx_port 一致)
# 退出 Pod
exit
2. 验证配置文件挂载(自定义首页)
通过之前的 Ingress/Service 访问 Nginx:
bash
运行
# 方式 1:通过 Service 访问
curl http://nginx-service
# 方式 2:通过 Ingress 域名访问
curl http://nginx.example.com
输出内容应为 ConfigMap 中定义的自定义首页:
html
预览
<!DOCTYPE html>
<html>
<head>
<title>ConfigMap Demo</title>
<meta charset="utf-8">
</head>
<body>
<h1>Hello from ConfigMap!</h1>
<p>This page is loaded from K8s ConfigMap.</p>
</body>
</html>
3. 验证健康检查接口(自定义 Nginx 配置)
bash
运行
curl http://nginx.example.com/health
# 输出:{"status":"ok"}
说明 ConfigMap 中的 default.conf 已成功覆盖 Nginx 默认配置。
四、第四步:修改 ConfigMap 并验证热更新
ConfigMap 支持「热更新」(部分场景无需重启 Pod),我们修改首页内容,验证配置生效。
1. 修改 ConfigMap YAML(更新 index.html 内容)
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx_port: "80"
nginx_worker_processes: "auto"
default.conf: |
# 保持不变
server {
listen ${NGINX_PORT};
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /health {
access_log off;
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
}
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>ConfigMap Updated</title>
<meta charset="utf-8">
</head>
<body>
<h1>ConfigMap Updated!</h1>
<p>This page is updated from ConfigMap (hot reload).</p>
</body>
</html>
2. 应用 ConfigMap 修改
bash
运行
kubectl apply -f nginx-configmap.yaml
3. 验证热更新效果
bash
运行
# 等待 10 秒(ConfigMap 同步到 Pod 有延迟)
sleep 10
# 再次访问首页
curl http://nginx.example.com
输出内容会变为修改后的新首页,无需重启 Pod(因为是通过「文件挂载」方式,Nginx 会自动读取新文件;若为环境变量注入,需重启 Pod 才生效)。
拓展:ConfigMap 热更新说明
表格
| 注入方式 | 热更新是否生效 | 生效方式 |
|---|---|---|
| 文件挂载 | 是 | ConfigMap 修改后,Pod 内文件自动更新(应用需支持读取最新文件) |
| 环境变量注入 | 否 | 需重启 Pod 或滚动更新 Deployment |
总结
- 核心定位:ConfigMap 是 K8s 管理「非敏感配置」的核心资源,实现「配置和镜像解耦」,避免修改配置时重建镜像。
- 核心流程:编写 ConfigMap YAML(存储键值对 / 配置文件)→ 部署 ConfigMap → 修改 Deployment 以「环境变量」或「文件挂载」方式注入 → 验证配置生效 → 修改 ConfigMap 实现热更新(文件挂载方式)。
- 关键注意:ConfigMap 不存储敏感信息(如密码、密钥),敏感信息需用 Secret 管理;文件挂载支持热更新,环境变量需重启 Pod 生效。
至此,你已掌握 K8s 配置管理的基础方案,接下来可学习 Secret(敏感配置)、Volume(存储)等进阶内容,进一步完善配置和存储管理体系。
Secret
Secret 解决了 ConfigMap 「不适合存储敏感信息」的问题,专门用来存放密码、密钥、证书、Token 等敏感数据,且会以加密形式存储(相比 ConfigMap 的明文存储更安全)。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,结合之前的 Nginx 示例讲解,让你清晰区分 Secret 和 ConfigMap 的使用场景。
一、第一步:编写 Secret YAML 配置文件
Secret 本质是K8s 中存储敏感键值对的资源,核心特性是:
- 数据会被 Base64 编码(注意:Base64 是编码而非加密,生产需开启 K8s 静态加密);
- 支持三种常用类型:
Opaque(通用键值对)、kubernetes.io/tls(TLS 证书)、kubernetes.io/dockerconfigjson(镜像仓库凭证)。
我们以「存储 Nginx 基础认证密码 + TLS 证书」为例,编写 Secret YAML。
1. 准备敏感数据(Base64 编码)
Secret 的 data 字段要求值为 Base64 编码字符串,先手动编码测试数据:
bash
运行
# 编码用户名(admin)
echo -n "admin" | base64 # 输出:YWRtaW4=
# 编码密码(123456)
echo -n "123456" | base64 # 输出:MTIzNDU2
2. 创建 Secret YAML 文件(nginx-secret.yaml)
yaml
# API 版本:Secret 属于核心组,使用 v1
apiVersion: v1
# 资源类型:Secret
kind: Secret
# 元数据:Secret 名称、标签
metadata:
name: nginx-secret
labels:
app: nginx
# Secret 类型:Opaque 为通用类型(默认)
type: Opaque
# 核心配置:敏感数据(Base64 编码的键值对)
data:
# 基础认证的用户名(Base64 编码:admin → YWRtaW4=)
auth_user: YWRtaW4=
# 基础认证的密码(Base64 编码:123456 → MTIzNDU2)
auth_pass: MTIzNDU2
# 可选:stringData(明文输入,K8s 会自动编码为 Base64,适合手动编写)
# stringData:
# auth_user: admin
# auth_pass: 123456
3. 关键配置解释
表格
| 配置项 | 作用 | |
|---|---|---|
type: Opaque |
通用 Secret 类型,适用于大部分键值对场景;若存储 TLS 证书,需用 kubernetes.io/tls |
|
data |
存储 Base64 编码的敏感数据(必须编码),生产推荐用这个字段 | |
stringData |
存储明文敏感数据(K8s 自动编码),适合测试 / 手动编写,优先级高于 data |
|
| 安全性提示 | Base64 编码可被反向解码(`echo"YWRtaW4=" | base64 -d`),生产需开启 K8s APIServer 的静态加密功能 |
二、第二步:部署 Secret + 修改 Deployment 挂载 / 注入
和 ConfigMap 类似,Secret 需通过「环境变量」或「文件挂载」注入 Pod,我们基于之前的 Nginx Deployment 改造,添加「基础认证」功能(使用 Secret 中的用户名密码)。
1. 部署 Secret
bash
运行
# 应用 YAML 创建 Secret
kubectl apply -f nginx-secret.yaml
成功输出:secret/nginx-secret created
2. 验证 Secret 部署
bash
运行
# 查看 Secret 列表
kubectl get secrets
# 简写:kubectl get secret
# 查看 Secret 详情(K8s 会隐藏 data 字段的具体值,保证安全)
kubectl describe secret nginx-secret
注意:
kubectl describe不会显示 Base64 编码的具体值,需用kubectl get secret nginx-secret -o yaml查看(仅测试环境使用)。
3. 修改 ConfigMap + Deployment(集成 Secret 实现基础认证)
步骤 1:更新 ConfigMap(添加 Nginx 基础认证配置)
修改 nginx-configmap.yaml,新增基础认证规则:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx_port: "80"
nginx_worker_processes: "auto"
default.conf: |
server {
listen ${NGINX_PORT};
server_name localhost;
# 启用基础认证
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /health {
access_log off;
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
}
index.html: |
<!DOCTYPE html>
<html>
<head>
<title>ConfigMap Demo</title>
<meta charset="utf-8">
</head>
<body>
<h1>Hello from ConfigMap!</h1>
<p>This page is loaded from K8s ConfigMap.</p>
</body>
</html>
步骤 2:更新 Deployment(挂载 Secret 并生成认证文件)
修改 nginx-deployment.yaml,添加 Secret 挂载 + 初始化脚本生成 .htpasswd 文件:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
env: test
template:
metadata:
labels:
app: nginx
env: test
spec:
initContainers:
# 初始化容器:生成 Nginx 基础认证文件(使用 Secret 中的用户名密码)
- name: create-htpasswd
image: nginx:1.26-alpine
command:
- /bin/sh
- -c
- |
# 从 Secret 挂载的文件中读取用户名和密码(Base64 解码)
USER=$(cat /etc/secret/auth_user | base64 -d)
PASS=$(cat /etc/secret/auth_pass | base64 -d)
# 生成 .htpasswd 文件(nginx 基础认证格式)
htpasswd -bc /etc/nginx/conf.d/.htpasswd $USER $PASS
# 挂载 Secret 到初始化容器
volumeMounts:
- name: nginx-secret-volume
mountPath: /etc/secret
- name: htpasswd-volume
mountPath: /etc/nginx/conf.d
containers:
- name: nginx-container
image: nginx:1.26-alpine
ports:
- containerPort: 80
env:
- name: NGINX_PORT
valueFrom:
configMapKeyRef:
name: nginx-config
key: nginx_port
# 挂载 ConfigMap(配置文件)、Secret(认证文件)
volumeMounts:
- name: nginx-conf-volume
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
- name: nginx-html-volume
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
- name: htpasswd-volume
mountPath: /etc/nginx/conf.d/.htpasswd
subPath: .htpasswd
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
# 定义卷(关联 ConfigMap/Secret/空目录)
volumes:
- name: nginx-conf-volume
configMap:
name: nginx-config
items:
- key: default.conf
path: default.conf
- name: nginx-html-volume
configMap:
name: nginx-config
items:
- key: index.html
path: index.html
- name: nginx-secret-volume
secret:
secretName: nginx-secret # 关联的 Secret 名称
- name: htpasswd-volume
emptyDir: {} # 临时目录,用于存储初始化生成的 .htpasswd 文件
步骤 3:重新部署 ConfigMap + Deployment
bash
运行
# 更新 ConfigMap
kubectl apply -f nginx-configmap.yaml
# 更新 Deployment(触发滚动更新)
kubectl apply -f nginx-deployment.yaml
三、第三步:查看 Secret 运行效果
验证 Secret 中的用户名密码是否生效,访问 Nginx 需输入认证信息。
1. 验证基础认证(核心)
bash
运行
# 方式 1:未输入认证信息访问(返回 401 未授权)
curl -v http://nginx.example.com
# 方式 2:输入 Secret 中的用户名密码访问(成功返回页面)
curl -u admin:123456 http://nginx.example.com
成功输出 ConfigMap 定义的首页内容,说明 Secret 中的敏感数据已成功注入 Pod 并生效。
2. 验证 Secret 挂载内容
bash
运行
# 进入 Pod 查看 Secret 挂载的文件
kubectl exec -it $(kubectl get pod -l app=nginx -o jsonpath="{.items[0].metadata.name}") -- /bin/sh
# 查看 Secret 挂载的编码文件(自动解码)
cat /etc/secret/auth_user # 输出:admin
cat /etc/secret/auth_pass # 输出:123456
# 查看生成的 .htpasswd 文件
cat /etc/nginx/conf.d/.htpasswd # 输出:admin:$apr1$...(加密后的密码)
# 退出 Pod
exit
注意:K8s 会自动将 Secret 的 Base64 编码数据解码后挂载到 Pod 中,无需手动解码。
四、第四步:修改 Secret 并验证更新
Secret 同样支持热更新(文件挂载方式),我们修改密码并验证认证效果。
1. 修改 Secret YAML(更新密码为 654321)
先编码新密码:
bash
运行
echo -n "654321" | base64 # 输出:NjU0MzIx
更新 nginx-secret.yaml:
yaml
apiVersion: v1
kind: Secret
metadata:
name: nginx-secret
type: Opaque
data:
auth_user: YWRtaW4=
auth_pass: NjU0MzIx # 新密码 654321 的 Base64 编码
2. 应用 Secret 修改
bash
运行
kubectl apply -f nginx-secret.yaml
3. 重建初始化容器(使新密码生效)
Secret 热更新后,需重启 Pod 让初始化容器重新生成 .htpasswd 文件:
bash
运行
# 滚动更新 Deployment(重启所有 Pod)
kubectl rollout restart deployment/nginx-deployment
4. 验证密码更新效果
bash
运行
# 旧密码访问(失败)
curl -u admin:123456 http://nginx.example.com # 返回 401
# 新密码访问(成功)
curl -u admin:654321 http://nginx.example.com # 返回首页内容
拓展:Secret 常用类型
表格
| 类型 | 适用场景 | 示例用途 |
|---|---|---|
Opaque |
通用键值对(默认) | 用户名密码、API Token |
kubernetes.io/tls |
TLS 证书 | HTTPS 证书(替代手动创建 Secret) |
kubernetes.io/dockerconfigjson |
镜像仓库凭证 | 拉取私有镜像的用户名密码 |
总结
- 核心定位:Secret 是 K8s 管理「敏感配置」的核心资源,专门存储密码、证书等敏感数据,相比 ConfigMap 更安全(Base64 编码 + 访问权限控制)。
- 核心流程:编写 Secret YAML(Base64 编码敏感数据)→ 部署 Secret → 修改 Deployment 以「环境变量」或「文件挂载」方式注入 → 验证敏感配置生效 → 修改 Secret 并重启 Pod 实现更新。
- 关键区别(vs ConfigMap):
- 用途:ConfigMap 存非敏感配置(如 Nginx 配置),Secret 存敏感数据(如密码);
- 存储:ConfigMap 明文,Secret Base64 编码;
- 权限:Secret 默认仅挂载到需要的 Pod,访问权限更严格。
至此,你已掌握 K8s 配置管理的完整方案:ConfigMap(非敏感配置) + Secret(敏感配置),结合之前的 Deployment/Service/Ingress,形成了 K8s 无状态应用部署的完整闭环。后续可学习 StatefulSet(有状态应用)、PersistentVolume(持久化存储)等进阶内容。
StatefulSet
StatefulSet 解决了 Deployment(无状态)「Pod 名称随机、无固定网络标识、存储不持久」的问题,专门用于部署数据库(MySQL/PostgreSQL)、中间件(Redis/Zookeeper)等有状态应用。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,以 Redis 主从集群为例,带你理解 StatefulSet 的核心特性和使用方式。
一、前置说明:StatefulSet vs Deployment
先明确核心差异,帮你理解 StatefulSet 的设计初衷:
表格
| 特性 | Deployment(无状态) | StatefulSet(有状态) |
|---|---|---|
| Pod 名称 | 随机后缀(如 xxx-7f987d6c74-2x89s) | 固定名称(如 redis-0、redis-1) |
| 网络标识 | 无固定 DNS 名称 | 固定 Headless Service 域名(redis-0.redis-svc.default.svc.cluster.local) |
| 存储 | 共享 Volume(删除则丢失) | 固定 PersistentVolumeClaim(PVC),每个 Pod 独享存储 |
| 部署 / 扩缩容顺序 | 无序 | 有序(0→1→2 部署,2→1→0 缩容) |
| 更新策略 | 滚动更新 | 有序更新(默认)/ 分区更新 |
二、第一步:编写 StatefulSet 相关 YAML
StatefulSet 依赖两个核心组件:
- Headless Service:为 StatefulSet 提供固定网络标识(无 ClusterIP,仅做 DNS 解析);
- StatefulSet 资源:定义有状态 Pod 的模板、存储、有序部署规则;
- PersistentVolumeClaim(PVC)模板:为每个 Pod 分配独享的持久化存储。
我们以 Redis 主从集群为例,编写完整 YAML(redis-statefulset.yaml):
yaml
# 1. 先创建 Headless Service(为 StatefulSet 提供固定 DNS)
apiVersion: v1
kind: Service
metadata:
name: redis-headless
labels:
app: redis
spec:
clusterIP: None # 关键:Headless Service 无 ClusterIP
selector:
app: redis
ports:
- name: redis
port: 6379
targetPort: 6379
---
# 2. 创建 StatefulSet(管理 Redis 有状态 Pod)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-statefulset
labels:
app: redis
spec:
serviceName: redis-headless # 关联上面的 Headless Service(核心!)
replicas: 2 # 2 个 Pod:redis-0(主)、redis-1(从)
selector:
matchLabels:
app: redis
# 存储模板:每个 Pod 独享一个 PVC
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: [ "ReadWriteOnce" ] # 单节点读写
resources:
requests:
storage: 1Gi # 每个 Pod 申请 1Gi 存储
# 存储类(根据集群环境调整,如 minikube 的 standard、云厂商的 cbs)
storageClassName: "standard"
# Pod 模板
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.2-alpine
ports:
- containerPort: 6379
# 挂载持久化存储(对应 volumeClaimTemplates)
volumeMounts:
- name: redis-data
mountPath: /data # Redis 数据存储目录
# 初始化 Redis 主从配置(通过环境变量区分主从)
env:
- name: REDIS_REPLICATION_MODE
valueFrom:
fieldRef:
fieldPath: metadata.name # 获取 Pod 名称(redis-0/redis-1)
command:
- /bin/sh
- -c
- |
# redis-0 作为主节点,redis-1 作为从节点
if [ "$REDIS_REPLICATION_MODE" = "redis-statefulset-0" ]; then
redis-server --appendonly yes # 主节点开启 AOF 持久化
else
redis-server --appendonly yes --replicaof redis-statefulset-0.redis-headless 6379 # 从节点关联主节点
fi
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
restartPolicy: Always
# 更新策略:有序更新(默认)
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0 # 从第 0 个 Pod 开始有序更新
关键配置解释
表格
| 配置项 | 作用 |
|---|---|
serviceName |
核心!关联 Headless Service,为每个 Pod 生成固定 DNS 域名(如 redis-statefulset-0.redis-headless) |
volumeClaimTemplates |
PVC 模板:每个 Pod 自动创建一个同名 PVC(redis-data-redis-statefulset-0),独享存储 |
replicas |
有序部署的 Pod 数量,名称为 {statefulset-name}-{序号}(从 0 开始) |
updateStrategy |
有序更新:默认从序号大的 Pod 开始更新,保证主节点最后更新(数据库场景关键) |
三、第二步:部署 StatefulSet 及依赖资源
部署前确保集群支持 PersistentVolume(PV):
- Minikube:默认支持
standard存储类,会自动创建 PV; - 云厂商集群:需提前创建存储类(如阿里云
alicloud-disk-efficiency); - 本地集群:需手动创建 PV 或部署存储插件。
1. 执行部署命令
bash
运行
# 应用 YAML 创建 Headless Service + StatefulSet
kubectl apply -f redis-statefulset.yaml
成功输出:
plaintext
service/redis-headless created
statefulset.apps/redis-statefulset created
2. 验证部署过程(有序性)
bash
运行
# 实时查看 Pod 创建过程(先创建 redis-statefulset-0,再创建 redis-statefulset-1)
kubectl get pods -l app=redis -w
输出示例(有序创建):
plaintext
NAME READY STATUS RESTARTS AGE
redis-statefulset-0 0/1 ContainerCreating 0 0s
redis-statefulset-0 1/1 Running 0 5s
redis-statefulset-1 0/1 ContainerCreating 0 5s
redis-statefulset-1 1/1 Running 0 10s
3. 验证 PVC 自动创建
bash
运行
# 查看 PVC(每个 Pod 对应一个 PVC)
kubectl get pvc
输出示例:
plaintext
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
redis-data-redis-statefulset-0 Bound pvc-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 1Gi RWO standard 15s
redis-data-redis-statefulset-1 Bound pvc-yyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy 1Gi RWO standard 10s
四、第三步:查看 StatefulSet 运行效果
重点验证「固定网络标识」「持久化存储」「主从复制」三大核心特性。
1. 验证固定 DNS 解析(Headless Service)
bash
运行
# 创建临时 Pod 测试 DNS 解析
kubectl run test-pod --image=busybox:1.36 --rm -it -- /bin/sh
# 解析 redis-statefulset-0 的固定域名
nslookup redis-statefulset-0.redis-headless
# 输出:Address: 10.244.0.10(redis-0 的 Pod IP)
# 解析 redis-statefulset-1 的固定域名
nslookup redis-statefulset-1.redis-headless
# 输出:Address: 10.244.0.11(redis-1 的 Pod IP)
# 退出临时 Pod
exit
关键:即使 Pod 重建(IP 变化),DNS 域名仍指向新 Pod 的 IP,保证网络标识不变。
2. 验证 Redis 主从复制
bash
运行
# 进入 redis-0(主节点)
kubectl exec -it redis-statefulset-0 -- redis-cli
# 设置测试数据
set test "hello statefulset"
get test # 输出:"hello statefulset"
# 退出主节点
exit
# 进入 redis-1(从节点)
kubectl exec -it redis-statefulset-1 -- redis-cli
# 读取主节点同步的数据(验证主从复制)
get test # 输出:"hello statefulset"
# 查看复制状态
info replication
# 输出中会显示 "role:slave"、"master_host:redis-statefulset-0.redis-headless"
# 退出从节点
exit
3. 验证持久化存储(核心)
bash
运行
# 1. 删除 redis-0 Pod(模拟故障)
kubectl delete pod redis-statefulset-0
# 2. 等待 StatefulSet 重建 redis-0
kubectl get pods -l app=redis
# 3. 进入重建后的 redis-0,验证数据未丢失
kubectl exec -it redis-statefulset-0 -- redis-cli
get test # 输出:"hello statefulset"(数据从 PVC 中恢复)
exit
关键:Deployment 删除 Pod 后数据丢失,StatefulSet 因独享 PVC,重建后数据仍存在。
五、第四步:修改配置(扩缩容 + 分区更新)
1. 扩缩容(有序)
bash
运行
# 扩容到 3 个 Pod(会创建 redis-statefulset-2,作为从节点)
kubectl scale statefulset redis-statefulset --replicas=3
# 验证扩容结果
kubectl get pods -l app=redis
# 输出:redis-statefulset-0、redis-statefulset-1、redis-statefulset-2
# 缩容到 2 个 Pod(先删除 redis-statefulset-2,再保留 0/1)
kubectl scale statefulset redis-statefulset --replicas=2
2. 分区更新(生产常用)
分区更新可指定「仅更新部分 Pod」,适合灰度发布:
yaml
# 修改 StatefulSet YAML 的 updateStrategy
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 1 # 仅更新序号 ≥1 的 Pod(即 redis-statefulset-1)
应用修改并验证:
bash
运行
# 应用配置
kubectl apply -f redis-statefulset.yaml
# 查看更新状态(仅 redis-statefulset-1 重启,redis-statefulset-0 不变)
kubectl rollout status statefulset/redis-statefulset
总结
- 核心定位:StatefulSet 是 K8s 管理「有状态应用」的核心控制器,解决了 Deployment 无固定标识、无独享存储、无序部署的问题,适用于数据库、中间件等有状态场景。
- 核心流程:创建 Headless Service(固定网络)→ 编写 StatefulSet YAML(含 PVC 模板、有序规则)→ 部署并验证有序创建 / 固定 DNS / 持久化存储 → 测试扩缩容 / 分区更新。
- 关键特性:固定 Pod 名称 + 固定 DNS 标识、每个 Pod 独享 PVC 存储、有序部署 / 扩缩容 / 更新,是部署有状态应用的标准方案。
至此,你已掌握 K8s 核心资源的完整体系:
- 无状态应用:Pod → Deployment → Service → Ingress;
- 配置管理:ConfigMap(非敏感) + Secret(敏感);
- 有状态应用:StatefulSet + Headless Service + PVC/PV。
后续可学习 Operator(自动化运维有状态应用)、Namespace(资源隔离)、ResourceQuota(资源限制)等进阶内容,进一步完善 K8s 知识体系。
PV/PVC
PV(PersistentVolume)和 PVC(PersistentVolumeClaim) 解决了「存储和应用解耦」的问题,是 K8s 实现持久化存储的标准方案 ——StatefulSet 中用到的 volumeClaimTemplates 本质就是自动创建 PVC,而 PVC 又会绑定集群中的 PV。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,带你理解 PV/PVC 的核心逻辑,以及和 StatefulSet 的联动关系。
一、前置说明:PV/PVC 核心逻辑
先理清 PV/PVC 的分工(类比「租房」更易理解):
表格
| 角色 | 类比 | 作用 |
|---|---|---|
| PV(持久卷) | 房东的房子 | 集群级别的存储资源(独立于 Pod 生命周期),由管理员创建,定义存储类型、大小、访问模式 |
| PVC(持久卷声明) | 租客的租房申请 | Pod 对存储的「申请单」,由开发 / 运维创建,声明需要的存储大小、访问模式,K8s 自动绑定匹配的 PV |
| StorageClass | 房屋中介 | 自动创建 PV(动态供给),无需管理员手动创建 PV,是生产环境首选(StatefulSet 示例中已用到) |
二、第一步:编写 PV/PVC YAML 配置文件
我们分「静态供给(手动创建 PV)」和「动态供给(StorageClass 自动创建 PV)」两种场景演示,覆盖新手最常用的两种方式。
场景 1:静态供给(手动创建 PV + PVC)
适合测试 / 小规模集群,需先创建 PV,再创建 PVC 绑定。
1. 创建 PV YAML(redis-pv.yaml)
yaml
# API 版本:PV 属于核心组,使用 v1
apiVersion: v1
kind: PersistentVolume
metadata:
name: redis-pv-0 # PV 名称(唯一)
labels:
app: redis
pv: redis-pv-0
spec:
capacity:
storage: 1Gi # PV 大小(需 ≥ PVC 申请的大小)
accessModes:
- ReadWriteOnce # 访问模式:单节点读写(RWO),其他模式:ROX(多节点只读)、RWX(多节点读写)
persistentVolumeReclaimPolicy: Retain # 回收策略:Retain(保留)/ Delete(删除)/ Recycle(回收,已废弃)
storageClassName: "standard" # 存储类名称(需和 PVC 一致)
# 存储后端(根据环境选择,这里以 Minikube 本地存储为例)
hostPath:
path: /data/redis-pv-0 # Minikube 节点上的本地路径(需提前创建)
type: DirectoryOrCreate # 路径不存在则自动创建
2. 创建 PVC YAML(redis-pvc.yaml)
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc-0 # PVC 名称
labels:
app: redis
spec:
accessModes:
- ReadWriteOnce # 必须和 PV 的访问模式匹配
resources:
requests:
storage: 1Gi # 申请的存储大小(必须 ≤ PV 的容量)
storageClassName: "standard" # 必须和 PV 的存储类名称匹配
# 可选:通过标签选择器绑定指定 PV
selector:
matchLabels:
pv: redis-pv-0
场景 2:动态供给(StorageClass + PVC)
生产环境首选,无需手动创建 PV,StorageClass 会自动创建匹配的 PV。
1. 创建 StorageClass YAML(redis-storageclass.yaml)
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: redis-sc # 存储类名称
provisioner: k8s.io/minikube-hostpath # 存储供给者(Minikube 专用,云厂商需替换:如阿里云 alicloud/disk)
reclaimPolicy: Delete # PV 回收策略(删除 PVC 时自动删除 PV)
volumeBindingMode: Immediate # 立即绑定 PVC 和 PV
2. 创建 PVC YAML(redis-pvc-dynamic.yaml)
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc-dynamic
labels:
app: redis
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: "redis-sc" # 关联上面的 StorageClass
三、第二步:部署 PV/PVC 并验证绑定
场景 1:静态供给部署流程
1. 准备 Minikube 本地路径(仅 hostPath 需执行)
bash
运行
# 进入 Minikube 节点并创建存储路径
minikube ssh
mkdir -p /data/redis-pv-0
exit
2. 部署 PV
bash
运行
kubectl apply -f redis-pv.yaml
成功输出:persistentvolume/redis-pv-0 created
3. 部署 PVC
bash
运行
kubectl apply -f redis-pvc.yaml
成功输出:persistentvolumeclaim/redis-pvc-0 created
4. 验证 PV/PVC 绑定
bash
运行
# 查看 PV 状态(STATUS 为 Bound 表示已绑定)
kubectl get pv redis-pv-0
# 查看 PVC 状态(STATUS 为 Bound 表示绑定成功)
kubectl get pvc redis-pvc-0
输出示例:
plaintext
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
redis-pv-0 1Gi RWO Retain Bound default/redis-pvc-0 standard 10s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
redis-pvc-0 Bound redis-pv-0 1Gi RWO standard 5s
场景 2:动态供给部署流程
1. 部署 StorageClass
bash
运行
kubectl apply -f redis-storageclass.yaml
成功输出:storageclass.storage.k8s.io/redis-sc created
2. 部署 PVC
bash
运行
kubectl apply -f redis-pvc-dynamic.yaml
成功输出:persistentvolumeclaim/redis-pvc-dynamic created
3. 验证自动创建 PV
bash
运行
# 查看 PVC(STATUS 为 Bound)
kubectl get pvc redis-pvc-dynamic
# 查看自动创建的 PV(名称为 pvc-xxxxxx,STATUS 为 Bound)
kubectl get pv
关键:动态供给下,无需手动创建 PV,K8s 会根据 StorageClass 自动创建匹配的 PV 并绑定到 PVC。
四、第三步:将 PVC 挂载到 Pod/StatefulSet 验证效果
我们将静态供给的 PVC 挂载到 Pod,验证持久化存储效果。
1. 创建测试 Pod YAML(redis-pod-pvc.yaml)
yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-pod-with-pvc
spec:
containers:
- name: redis
image: redis:7.2-alpine
ports:
- containerPort: 6379
# 挂载 PVC 到容器
volumeMounts:
- name: redis-storage
mountPath: /data # Redis 数据存储目录
# 关联 PVC
volumes:
- name: redis-storage
persistentVolumeClaim:
claimName: redis-pvc-0 # 绑定的 PVC 名称
restartPolicy: Always
2. 部署 Pod
bash
运行
kubectl apply -f redis-pod-pvc.yaml
3. 验证持久化存储
bash
运行
# 1. 进入 Pod 写入测试数据
kubectl exec -it redis-pod-with-pvc -- redis-cli
set test "hello pv/pvc"
get test # 输出:"hello pv/pvc"
exit
# 2. 删除 Pod(模拟故障)
kubectl delete pod redis-pod-with-pvc
# 3. 重新部署 Pod(使用同一个 PVC)
kubectl apply -f redis-pod-pvc.yaml
# 4. 进入新 Pod 验证数据未丢失
kubectl exec -it redis-pod-with-pvc -- redis-cli
get test # 输出:"hello pv/pvc"(数据从 PV 中恢复)
exit
核心:PV/PVC 独立于 Pod 生命周期,即使 Pod 被删除重建,只要 PVC 绑定的 PV 存在,数据就不会丢失 —— 这也是 StatefulSet 能实现数据持久化的核心原因。
五、第四步:修改 PV/PVC 配置(扩容 + 回收策略)
1. PVC 扩容(K8s 1.11+ 支持)
1. 修改 PVC YAML(将存储大小改为 2Gi)
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc-0
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi # 扩容到 2Gi
storageClassName: "standard"
selector:
matchLabels:
pv: redis-pv-0
2. 应用修改(需确保 PV 支持扩容,hostPath 仅测试用,云厂商存储如 EBS 支持)
bash
运行
kubectl apply -f redis-pvc.yaml
3. 验证扩容
bash
运行
kubectl get pvc redis-pvc-0
# 输出 CAPACITY 为 2Gi
2. 修改 PV 回收策略
1. 编辑 PV 配置
bash
运行
kubectl edit pv redis-pv-0
将 persistentVolumeReclaimPolicy: Retain 改为 persistentVolumeReclaimPolicy: Delete。
2. 验证修改
bash
运行
kubectl describe pv redis-pv-0 | grep "Reclaim Policy"
# 输出:Reclaim Policy: Delete
拓展:PV 回收策略说明
表格
| 策略 | 作用 | 适用场景 |
|---|---|---|
| Retain | 删除 PVC 后,PV 保留(状态变为 Released),需手动清理数据 / 删除 PV | 生产环境(防止误删数据) |
| Delete | 删除 PVC 后,PV 自动删除(底层存储也会删除,如云盘) | 测试环境 / 临时存储 |
| Recycle | 删除 PVC 后,PV 格式化并重置(已废弃,推荐用 Retain/Delete) | 老旧集群(不推荐) |
总结
- 核心定位:PV/PVC 是 K8s 实现持久化存储的核心方案,通过「存储资源(PV)」和「存储申请(PVC)」解耦,让应用无需关心底层存储细节。
- 核心流程:
- 静态供给:创建 PV → 创建 PVC 绑定 PV → 挂载 PVC 到 Pod/StatefulSet;
- 动态供给:创建 StorageClass → 创建 PVC → K8s 自动创建 PV 并绑定 → 挂载 PVC 到应用。
- 关键联动:StatefulSet 的
volumeClaimTemplates本质是为每个 Pod 自动创建 PVC,结合 StorageClass 动态供给 PV,实现「每个 Pod 独享持久化存储」,这是有状态应用(如数据库)的核心需求。
至此,你已掌握 K8s 存储管理的核心方案,结合之前的 StatefulSet/Deployment/Service/Ingress/ConfigMap/Secret,形成了 K8s 应用部署的完整技术栈。后续可学习 CSI(容器存储接口)、动态存储扩容、存储快照等进阶内容,进一步适配生产环境的复杂存储需求。
JOB/CRONJOB
Job 解决了 Deployment/StatefulSet 「长期运行」的问题,专门用于执行一次性任务(如数据备份、批量计算);CronJob 则基于 Job 实现定时 / 周期性任务(如定时备份、日志清理)。我依然按「写 YAML → 部署 → 看效果 → 改配置」的流程,带你理解这两个资源的核心用法和场景差异。
一、前置说明:Job/CronJob 核心定位
先明确 Job/CronJob 与之前控制器的差异:
表格
| 控制器 | 适用场景 | 核心特性 |
|---|---|---|
| Deployment | 长期运行的无状态服务 | 持续运行、自动重启、滚动更新 |
| StatefulSet | 长期运行的有状态服务 | 固定标识、独享存储、有序部署 |
| Job | 一次性任务(执行完即结束) | 执行完成后 Pod 状态为 Completed,可重试 |
| CronJob | 定时 / 周期性任务 | 基于 Cron 表达式触发 Job,支持并发策略 |
二、第一步:编写 Job/CronJob YAML 配置文件
场景 1:Job(一次性任务)
以「批量生成测试数据并写入文件」为例,编写 Job YAML(data-generate-job.yaml):
yaml
# API 版本:Job 属于 batch 组,1.21+ 推荐使用 batch/v1
apiVersion: batch/v1
# 资源类型:Job
kind: Job
metadata:
name: data-generate-job
labels:
app: data-job
spec:
# 并行执行的 Pod 数(默认 1,适合批量任务)
parallelism: 1
# 完成的 Pod 数(需 ≤ parallelism,默认 1)
completions: 1
# 失败重试次数(默认 6,超出则 Job 标记为 Failed)
backoffLimit: 3
# 任务超时时间(可选,超出则终止 Pod)
activeDeadlineSeconds: 300
# Pod 模板(和 Deployment 类似,但重启策略仅支持 Never/OnFailure)
template:
metadata:
labels:
app: data-job
spec:
containers:
- name: data-generator
image: alpine:3.19
# 执行一次性任务:生成 100 行测试数据写入文件
command:
- /bin/sh
- -c
- |
echo "Generating test data..."
for i in $(seq 1 100); do
echo "Test data line $i: $(date +%Y-%m-%d_%H:%M:%S)" >> /data/test-data.txt
sleep 0.1
done
echo "Data generation completed!"
cat /data/test-data.txt
# 挂载 PV/PVC 持久化生成的文件(可选,测试也可不用)
volumeMounts:
- name: data-volume
mountPath: /data
# Job 的重启策略仅支持 Never(永不重启)或 OnFailure(失败时重启)
restartPolicy: Never
# 定义卷(这里用 EmptyDir 测试,生产可替换为 PVC)
volumes:
- name: data-volume
emptyDir: {}
场景 2:CronJob(定时任务)
以「每天凌晨 2 点执行数据备份」为例,编写 CronJob YAML(backup-cronjob.yaml):
yaml
# API 版本:CronJob 属于 batch 组,1.21+ 推荐使用 batch/v1
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-cronjob
labels:
app: backup-cron
spec:
# Cron 表达式(分时日月周,和 Linux Crontab 一致)
# 示例:每天凌晨 2 点执行 → 0 2 * * *
schedule: "*/1 * * * *" # 测试用:每分钟执行一次
# 任务执行超时时间(超出则终止)
jobTimeoutSeconds: 300
# 并发策略:Allow(允许并发)/ Forbid(禁止)/ Replace(替换)
concurrencyPolicy: Forbid
# 错过执行的任务是否运行(默认 false,适合非关键任务)
startingDeadlineSeconds: 60
# 保留成功的 Job 历史记录数(默认 3)
successfulJobsHistoryLimit: 5
# 保留失败的 Job 历史记录数(默认 1)
failedJobsHistoryLimit: 3
# 暂停 CronJob(默认 false,设为 true 则停止触发任务)
suspend: false
# Job 模板(和上面的 Job 配置一致)
jobTemplate:
spec:
backoffLimit: 3
template:
spec:
containers:
- name: backup
image: alpine:3.19
command:
- /bin/sh
- -c
- |
echo "Starting backup at $(date)..."
# 模拟备份操作:压缩 /data 目录(这里用空操作测试)
tar -czf /backup/backup-$(date +%Y%m%d_%H%M%S).tar.gz /data || echo "Backup completed!"
ls -l /backup/
volumeMounts:
- name: backup-volume
mountPath: /backup
restartPolicy: Never
volumes:
- name: backup-volume
emptyDir: {}
关键配置解释
表格
| 配置项(Job) | 作用 |
|---|---|
parallelism |
并行执行的 Pod 数,适合拆分大任务为多个子任务并行处理 |
completions |
需完成的 Pod 数,全部完成后 Job 状态为 Completed |
backoffLimit |
失败重试次数,防止任务无限重试(如依赖的服务不可用) |
restartPolicy |
仅支持 Never/OnFailure(Job 是一次性任务,不支持 Always) |
表格
| 配置项(CronJob) | 作用 |
|---|---|
schedule |
Cron 表达式(* * * * *):分 (0-59) 时 (0-23) 日 (1-31) 月 (1-12) 周 (0-6) |
concurrencyPolicy |
并发策略:Forbid 禁止并发(避免重复执行备份),生产推荐 |
successfulJobsHistoryLimit |
保留成功 Job 记录数,便于排查历史任务执行情况 |
suspend |
暂停 CronJob,无需删除资源即可停止任务触发(运维常用) |
三、第二步:部署 Job/CronJob 并验证执行
场景 1:部署 Job(一次性任务)
1. 执行部署命令
bash
运行
kubectl apply -f data-generate-job.yaml
成功输出:job.batch/data-generate-job created
2. 查看 Job 状态
bash
运行
# 查看 Job 列表(COMPLETIONS 为 1/1 表示执行完成)
kubectl get jobs
# 查看 Job 详情(包含执行事件、Pod 信息)
kubectl describe job data-generate-job
输出示例:
plaintext
NAME COMPLETIONS DURATION AGE
data-generate-job 1/1 12s 20s
3. 查看 Job 对应的 Pod 及日志
bash
运行
# 查看 Job 创建的 Pod(名称格式:{job-name}-{随机后缀})
kubectl get pods -l app=data-job
# 查看 Pod 日志(验证任务执行结果)
kubectl logs <pod-name> # 替换为实际 Pod 名称
日志会输出「生成 100 行测试数据」的内容,确认任务执行成功。
场景 2:部署 CronJob(定时任务)
1. 执行部署命令
bash
运行
kubectl apply -f backup-cronjob.yaml
成功输出:cronjob.batch/backup-cronjob created
2. 查看 CronJob 状态
bash
运行
# 查看 CronJob 列表
kubectl get cronjobs
# 简写:kubectl get cj
输出示例:
plaintext
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
backup-cronjob */1 * * * * False 0 10s 30s
3. 验证定时触发 Job
bash
运行
# 等待 1 分钟,查看 CronJob 触发的 Job
kubectl get jobs -l app=backup-cron
# 查看触发的 Pod 及日志
kubectl get pods -l app=backup-cron
kubectl logs <backup-pod-name>
日志会输出「备份开始 / 完成」的内容,确认定时任务每 1 分钟执行一次。
四、第三步:修改配置并验证更新
场景 1:修改 Job(重新执行一次性任务)
Job 执行完成后无法直接修改配置重新执行,需先删除旧 Job,再部署新配置:
1. 修改 Job YAML(将生成数据行数改为 200)
yaml
command:
- /bin/sh
- -c
- |
echo "Generating test data..."
for i in $(seq 1 200); do # 改为 200 行
echo "Test data line $i: $(date +%Y-%m-%d_%H:%M:%S)" >> /data/test-data.txt
sleep 0.1
done
echo "Data generation completed!"
cat /data/test-data.txt
2. 删除旧 Job 并重新部署
bash
运行
# 删除旧 Job
kubectl delete job data-generate-job
# 部署新 Job
kubectl apply -f data-generate-job.yaml
3. 验证修改效果
bash
运行
kubectl logs <new-pod-name> | wc -l # 查看输出行数(约 200 行)
场景 2:修改 CronJob(调整执行频率)
1. 修改 CronJob YAML(将执行频率改为每 5 分钟一次)
yaml
schedule: "*/5 * * * *" # 每 5 分钟执行一次
2. 应用修改
bash
运行
kubectl apply -f backup-cronjob.yaml
3. 验证更新效果
bash
运行
# 查看 CronJob 配置(确认 schedule 已更新)
kubectl describe cronjob backup-cronjob | grep Schedule
# 等待 5 分钟,验证仅每 5 分钟触发一次 Job
kubectl get jobs -l app=backup-cron -w
拓展:CronJob 常用操作
bash
运行
# 手动触发一次 CronJob(无需等待定时时间)
kubectl create job --from=cronjob/backup-cronjob manual-backup-job
# 暂停 CronJob(停止触发新任务)
kubectl patch cronjob backup-cronjob -p '{"spec":{"suspend":true}}'
# 恢复 CronJob
kubectl patch cronjob backup-cronjob -p '{"spec":{"suspend":false}}'
# 删除 CronJob 及所有历史 Job/Pod
kubectl delete cronjob backup-cronjob
kubectl delete jobs --all -l app=backup-cron
总结
- 核心定位:
- Job 用于执行「一次性任务」(如数据备份、批量计算),执行完成后 Pod 终止,支持并行 / 重试配置;
- CronJob 基于 Job 实现「定时 / 周期性任务」(如定时备份、日志清理),通过 Cron 表达式触发,支持并发控制和历史记录管理。
- 核心流程:
- Job:编写 YAML(定义一次性任务)→ 部署 → 查看 Pod 日志验证执行结果 → 删除重建修改配置;
- CronJob:编写 YAML(定义 Cron 表达式 + Job 模板)→ 部署 → 验证定时触发 → 修改 schedule 调整执行频率。
- 关键注意:
- Job 重启策略仅支持 Never/OnFailure,执行完成后需删除重建才能重新执行;
- CronJob 的
concurrencyPolicy推荐设为 Forbid,避免任务并发执行导致数据冲突; - 生产环境中,Job/CronJob 建议挂载 PVC 持久化任务输出(如备份文件)。
至此,你已掌握 K8s 核心控制器的全量场景:
- 长期运行服务:Deployment(无状态)、StatefulSet(有状态);
- 一次性 / 定时任务:Job、CronJob;
- 服务暴露:Service、Ingress;
- 配置管理:ConfigMap、Secret;
- 存储管理:PV/PVC、StorageClass。
这些覆盖了 K8s 日常运维的 90% 场景,后续可学习 RBAC(权限控制)、Namespace(资源隔离)、HPA(自动扩缩容)等进阶内容,进一步适配生产环境的复杂需求。
进阶内容
一、第一梯队:基础进阶(必学,覆盖日常运维 80% 场景)
1. Namespace(命名空间)—— 资源隔离与环境划分
核心定位
K8s 中最基础的资源隔离机制,将集群内的资源(Pod/Deployment/Service 等)按「环境 / 团队 / 项目」划分,避免资源名称冲突、权限混乱,是多团队 / 多环境共用集群的必备能力。
学习重点
表格
| 知识点 | 核心内容 |
|---|---|
| 核心特性 | ① 每个 Namespace 内资源名称唯一,跨 Namespace 需通过「名称 + Namespace」访问;② Namespace 独立分配资源配额;③ 部分系统资源(Node/PV)不属于任何 Namespace。 |
| 常用操作 | ① 创建 / 删除 Namespace:kubectl create ns dev;② 指定 Namespace 部署资源:kubectl apply -f xxx.yaml -n dev;③ 切换默认 Namespace:kubectl config set-context --current --namespace=dev。 |
| 核心配置 | 编写资源 YAML 时通过 metadata.namespace 指定所属 Namespace(默认 default)。 |
| 典型场景 | ① 划分环境:dev(开发)、test(测试)、prod(生产);② 划分团队:team-a、team-b。 |
实操方向
- 练习:为之前的 Nginx Deployment/Service 分别部署到
dev和prodNamespace,验证跨 Namespace 访问(需用service-name.namespace.svc.cluster.local域名); - 进阶:为不同 Namespace 配置 ResourceQuota(资源配额),限制每个 Namespace 最多使用 2CPU/4Gi 内存。
2. RBAC(基于角色的访问控制)—— 权限精细化管理
核心定位
K8s 原生的权限控制体系,替代老旧的 ABAC 模式,通过「角色(Role)+ 角色绑定(RoleBinding)」实现「谁(User/ServiceAccount)能对哪些资源(Pod/Deployment)执行哪些操作(get/create/delete)」的精细化管控,是生产集群安全的核心。
学习重点
表格
| 知识点 | 核心内容 |
|---|---|
| 核心组件 | ① Subject(主体):User(普通用户)、Group(用户组)、ServiceAccount(Pod 访问 API 的账户);② Role/ClusterRole(角色):定义权限规则(如允许 get pods、create deployments);③ RoleBinding/ClusterRoleBinding(绑定):将 Subject 和 Role 关联。 |
| 作用域 | ① Role/RoleBinding:仅作用于单个 Namespace;② ClusterRole/ClusterRoleBinding:作用于整个集群(如管理所有 Namespace 的 Pod)。 |
| ServiceAccount 核心 | ① Pod 默认使用 default ServiceAccount;② 可为 Pod 指定自定义 ServiceAccount,控制 Pod 访问 K8s API 的权限;③ 避免使用 default ServiceAccount 赋予过高权限。 |
| 常用操作 | ① 创建 Role:kubectl create role pod-reader --verb=get,list --resource=pods -n dev;② 创建 RoleBinding:kubectl create rolebinding user1-pod-reader --role=pod-reader --user=user1 -n dev;③ 查看权限:kubectl auth can-i delete pods -n dev --as=user1。 |
实操方向
- 基础:创建一个仅允许「查看 dev Namespace 下 Pod」的 Role,绑定给测试用户,验证权限;
- 进阶:为 StatefulSet 的 Pod 创建自定义 ServiceAccount,仅允许其访问 K8s API 获取自身标签,禁止删除资源;
- 生产要点:避免给 ServiceAccount 赋予
cluster-admin超级权限,遵循「最小权限原则」。
3. HPA(Horizontal Pod Autoscaler)—— 自动扩缩容
核心定位
根据 Pod 的 CPU / 内存使用率、自定义指标(如 QPS)自动调整 Deployment/StatefulSet 的 Pod 副本数,实现「负载高时扩容、负载低时缩容」,提升资源利用率,是应对流量波动的核心能力。
学习重点
表格
| 知识点 | 核心内容 |
|---|---|
| 核心指标 | ① 基础指标:CPU 使用率(默认)、内存使用率;② 自定义指标:需部署 Metrics Server + 自定义监控(如 Prometheus),支持 QPS、请求数等;③ 指标来源:Metrics Server(基础指标)、Prometheus Adapter(自定义指标)。 |
| 配置规则 | ① 最小 / 最大副本数:minReplicas: 2、maxReplicas: 10;② 目标指标:targetCPUUtilizationPercentage: 80(CPU 使用率 80% 触发扩容);③ 扩缩容冷却时间:避免频繁扩缩(默认 3 分钟扩容冷却,5 分钟缩容冷却)。 |
| 常用操作 | ① 创建 HPA:kubectl autoscale deployment nginx-deployment --min=2 --max=10 --cpu-percent=80;② 查看 HPA 状态:kubectl get hpa;③ 手动触发扩缩容验证:kubectl run -it --rm load-generator --image=busybox -- /bin/sh -c "while true; do wget -q -O - http://nginx-service; done"。 |
| 限制条件 | ① 仅支持 Deployment/StatefulSet(不支持裸 Pod/Job);② 需提前部署 Metrics Server(集群默认未安装);③ 扩缩容依赖节点资源充足。 |
实操方向
- 基础:部署 Metrics Server,为 Nginx Deployment 创建 HPA(CPU 阈值 50%),用压测工具模拟流量,验证 Pod 自动扩容;
- 进阶:配置基于内存 + CPU 双指标的 HPA,或基于 Prometheus 自定义指标(如 Nginx QPS)的 HPA;
- 生产要点:设置合理的
minReplicas避免缩容到 0,配置 PodDisruptionBudget 保证扩缩容时服务可用性。
二、第二梯队:进阶扩展(生产环境必备,适配复杂场景)
4. ResourceQuota & LimitRange —— 资源管控
核心定位
- ResourceQuota:限制 Namespace 级别的总资源使用(如最多 10 个 Pod、总 CPU 不超过 4 核),防止单个团队 / 环境占用过多集群资源;
- LimitRange:限制 Pod/Container 级别的资源(如每个容器最小 / 最大 CPU 0.1-1 核),避免单个 Pod 占用过多资源。
学习重点
- ResourceQuota 配置:为 Namespace 设定
hard限制(如pods: 10、requests.cpu: 4); - LimitRange 配置:为容器设定默认资源限制(如默认 request CPU 0.1 核,limit CPU 0.5 核),避免用户未配置资源导致的资源竞争;
- 实操:为 dev Namespace 配置 ResourceQuota + LimitRange,验证超出限制时部署 Pod 会失败。
5. PodDisruptionBudget(PDB)—— 服务高可用保障
核心定位
限制「自愿中断」的 Pod 数量(如 HPA 缩容、节点维护、Deployment 更新),保证至少有 N 个 Pod 可用,避免服务中断。例如:配置 PDB 保证 Nginx 至少有 1 个 Pod 运行,即使缩容 / 更新也不会全部下线。
学习重点
- 核心配置:
minAvailable: 1(至少 1 个 Pod 可用)或maxUnavailable: 1(最多 1 个 Pod 不可用); - 适配场景:Deployment 滚动更新、HPA 缩容、节点驱逐;
- 实操:为 Nginx Deployment 创建 PDB,验证滚动更新时始终有 Pod 可用。
6. Taints & Tolerations —— 节点调度管控
核心定位
实现「节点污点(Taint)+ Pod 容忍(Toleration)」的调度规则,控制 Pod 只能调度到指定节点。例如:给 GPU 节点加污点,只有带对应容忍的 Pod 才能调度到该节点;给生产节点加污点,避免测试 Pod 调度到生产节点。
学习重点
- 污点类型:
NoSchedule(不调度新 Pod)、PreferNoSchedule(尽量不调度)、NoExecute(驱逐已有 Pod); - 核心操作:① 给节点加污点:
kubectl taint nodes node1 key=value:NoSchedule;② 给 Pod 加容忍:在spec.tolerations中配置对应 key/value/effect; - 实操:给 Minikube 节点加污点,仅让 Nginx Pod (带容忍)调度到该节点。
7. Node Affinity —— 节点亲和性
核心定位
更灵活的节点调度规则(替代老旧的 nodeSelector),支持「硬亲和性」(必须满足条件)和「软亲和性」(尽量满足),控制 Pod 调度到符合标签的节点。例如:将数据库 Pod 调度到「磁盘类型 = SSD」的节点,将测试 Pod 调度到「环境 = test」的节点。
学习重点
- 硬亲和性:
requiredDuringSchedulingIgnoredDuringExecution(调度时必须满足,否则 Pod Pending); - 软亲和性:
preferredDuringSchedulingIgnoredDuringExecution(调度时尽量满足,不满足也能调度); - 实操:为 StatefulSet 的 Redis Pod 配置硬亲和性,仅调度到带
disk=ssd标签的节点。
三、第三梯队:高级进阶(适配大规模 / 高可用集群)
8. Operator —— 有状态应用自动化运维
核心定位
基于 CRD(自定义资源)+ Controller 实现有状态应用(如 MySQL/Elasticsearch/Zookeeper)的自动化运维,替代手动管理 StatefulSet/PVC。例如:MySQL Operator 可自动实现主从切换、备份恢复、扩缩容,大幅降低运维成本。
学习重点
- 核心组件:CRD(自定义资源,如 MySQLCluster)+ Controller(监听 CRD 变化,自动创建 StatefulSet/PVC/Service);
- 常用 Operator:MySQL Operator、Elasticsearch Operator、Prometheus Operator;
- 实操:部署 Prometheus Operator,通过 CRD 快速创建 Prometheus/Grafana 实例。
9. Ingress-NGINX 高级配置 —— 生产级网关
核心定位
在基础 Ingress 路由的基础上,配置 HTTPS 证书自动续期(Let's Encrypt)、请求限流、跨域、重定向、灰度发布(Canary)等生产级特性,将 Ingress 作为集群统一网关。
学习重点
- HTTPS 自动续期:结合 cert-manager 实现 Let's Encrypt 证书自动申请 / 续期;
- 灰度发布:通过 Ingress 注解实现基于权重 / Header 的流量切分;
- 限流与防护:配置请求限流(
nginx.ingress.kubernetes.io/limit-rps)、跨域(CORS)、IP 黑白名单; - 实操:为 Nginx Ingress 配置 HTTPS 自动续期 + 基于权重的灰度发布。
10. Cluster Autoscaler —— 集群节点自动扩缩容
核心定位
当集群资源不足时自动扩容节点(如云厂商 ECS/EKS),资源充足时自动缩容节点,结合 HPA 实现「Pod 扩容 → 节点扩容」的全自动化,适配大规模弹性场景。
学习重点
- 适配环境:云厂商集群(AWS EKS、阿里云 ACK、腾讯云 TKE);
- 核心配置:关联云厂商节点池,配置扩缩容阈值(如节点资源使用率 80% 触发扩容);
- 实操:在阿里云 ACK 中部署 Cluster Autoscaler,验证 Pod 扩容时自动创建新节点。
11. 监控与日志 —— 集群可观测性
核心定位
生产集群必备的可观测性能力,包括「监控(Metrics)、日志(Logs)、链路追踪(Tracing)」,及时发现并定位问题。
学习重点
- 监控:Prometheus + Grafana 监控集群 / 应用指标(CPU / 内存 / QPS),配置告警(Alertmanager);
- 日志:EFK/ELK 栈(Elasticsearch + Fluentd/Fluent Bit + Kibana)收集 Pod 日志,实现日志检索;
- 链路追踪:Jaeger/Zipkin 追踪微服务调用链路;
- 实操:部署 Prometheus + Grafana 监控 K8s 集群,部署 Fluent Bit 收集 Pod 日志到 Elasticsearch。
总结
按「从易到难、从基础到生产」的学习顺序,推荐路径:
- 第一梯队(必学):Namespace → RBAC → HPA → ResourceQuota/LimitRange;
- 第二梯队(生产必备):PDB → Taints&Tolerations → Node Affinity;
- 第三梯队(大规模集群):Operator → Ingress 高级配置 → Cluster Autoscaler → 监控日志。
每学习一个知识点,建议结合你已掌握的 Nginx/Redis 示例实操(如为 Redis StatefulSet 配置 PDB、为 Nginx Ingress 配置 HTTPS 自动续期),将知识点落地到实际场景中,加深理解
4)云原生架构开箱:4 层体系,一次性串完
你只要记住这个架构图:
- 应用层:微服务 / AI 模型服务(TensorFlow、TorchServe、vLLM)
- 调度层:K8s 核心(Deployment、StatefulSet、Job)
- 流量层:Service + Ingress / Gateway API
- 运维层:监控、日志、存储、CI/CD
学习法:每层只学 1 个工具,跑通链路就算会。
云原生应用层:微服务 + AI 模型服务
一、云原生应用层:微服务(Microservices)
1. 基础认知
微服务是什么
- 把一个大应用拆成多个独立、小、自治的服务
- 每个服务:独立开发、独立部署、独立扩缩容
- 服务之间通过 HTTP/gRPC 通信
云原生微服务的核心目标
- 高可用、弹性、可观测、可自动恢复
- 完全跑在 K8s 上
微服务 ≠ 分布式微服务强调:业务边界 + 独立部署 + 独立团队
2. 核心配置(在 K8s 里必须有的一套)
(1)服务基础部署
- Deployment / StatefulSet
- Service(ClusterIP)
- Ingress / API Gateway
- ConfigMap + Secret
(2)微服务治理标配
- 服务发现
- 负载均衡
- 限流、熔断、降级
- 链路追踪
- 监控告警
- 日志统一收集
(3)常用技术栈(云原生事实标准)
- 通信:HTTP /gRPC
- 网关:Ingress-NGINX、APISIX、Kong
- 服务治理:Spring Cloud / Istio / Dapr
- 可观测:Prometheus + Grafana + Jaeger + ELK
3. 实操场景(你能立刻练的)
场景 1:最简单微服务部署
- 服务 A:用户服务(Deployment + Service)
- 服务 B:订单服务(Deployment + Service)
- 服务 A 调用 服务 B:
http://order-service.{namespace}.svc.cluster.local
场景 2:统一入口(网关)
- 外部访问:
api.xxx.com/user→ 用户服务api.xxx.com/order→ 订单服务
场景 3:服务治理
- 超时控制
- 重试
- 熔断(防止级联故障)
- 限流(保护后端)
场景 4:可观测
- 看每个服务的 QPS、延迟、错误率
- 看一次请求跨多少服务(链路追踪)
- 日志统一检索
4. 进阶扩展
- Service Mesh(服务网格):Istio / Linkerd无侵入式治理,不用改代码
- gRPC 云原生部署:HTTP/2、长连接、流式、强类型
- Serverless 微服务:Knative缩到 0、按调用收费、自动弹性
- 多环境、多集群微服务
- 灰度 / 金丝雀发布
- 混沌测试:主动杀服务、杀节点,验证健壮性
二、云原生应用层:AI 模型服务(AI Model Serving)
1. 基础认知
AI 模型服务 = 把训练好的模型变成 API
- 输入:文本 / 图片 / 特征
- 输出: embedding / 分类结果 / 生成文本 / 检测框
云原生 AI 服务特点
- GPU 资源调度
- 高并发、低延迟
- 自动扩缩容(HPA 非常关键)
- 多模型、多版本管理
和微服务的区别
- 更依赖硬件(GPU)
- 推理性能敏感
- 框架更专用(TensorRT、TorchServe、Triton、vLLM)
2. 核心配置
(1)部署底座
- Deployment / StatefulSet(推理服务)
- GPU 资源声明(nvidia.com/gpu: 1)
- Service + Ingress(提供 API)
(2)资源与调度
- 节点亲和性(只调度到 GPU 节点)
- 污点与容忍(Taint/Toleration)
- 资源限制:CPU / 内存 / 显存
(3)推理引擎(必须掌握)
- Triton Inference Server(多框架、生产级)
- vLLM(大模型 LLM 推理超快)
- TorchServe
- TensorFlow Serving
(4)弹性与高可用
- HPA(基于 GPU/CPU/QPS 自动扩缩)
- 多副本
- 健康检查
3. 实操场景
场景 1:基础模型服务部署
- 模型:ResNet / BERT / 小 LLaMA
- 容器化 → 部署到 K8s → 暴露 API
场景 2:GPU 调度
yaml
resources:
limits:
nvidia.com/gpu: 1
场景 3:大模型(LLM)API 服务
- vLLM + OpenAI 兼容接口
- 支持流式输出(streaming)
- 并发、批量处理
场景 4:多模型统一管理
- Triton 同时跑:PyTorch、TensorRT、ONNX
- 支持版本控制、A/B 测试
场景 5:弹性 AI 服务
- 低峰:1 副本
- 高峰:自动扩到 6 副本
- 用 HPA + GPU 节点自动扩缩(Cluster Autoscaler)
4. 进阶扩展
- 模型热更新:不重启容器更新模型
- 模型缓存:热点模型加速
- 多 GPU / 分布式推理
- 量化、TensorRT 加速
- 模型监控:延迟、吞吐量、准确率漂移
- AI Workflow:推理 + 预处理 + 后处理 流水线
- 多集群统一模型分发
三、微服务 & AI 模型服务 对比速览
表格
| 维度 | 微服务 | AI 模型服务 |
|---|---|---|
| 核心依赖 | CPU、网络 | CPU/GPU、显存、模型文件 |
| 扩缩容依据 | CPU、QPS、延迟 | GPU 利用率、并发、排队长度 |
| 通信方式 | HTTP/gRPC | HTTP/gRPC(流式更常见) |
| 关键组件 | 网关、注册中心、治理、链路追踪 | 推理引擎、GPU 调度、模型管理 |
| 典型中间件 | Spring Cloud、Istio、APISIX | Triton、vLLM、TorchServe |
调度层:K8s 核心
一、基础认知:什么是 K8s 调度层?
一句话:调度层 = 决定 “这个 Pod 应该跑在哪个 Node 节点上” 的整套系统。
核心作用
- 自动为 Pod 选择最优节点
- 保证集群资源合理利用
- 满足业务约束(GPU、地域、高可用、亲和性等)
- 保证服务稳定性、高可用、性能
调度层的核心组件
- kube-schedulerK8s 官方默认调度器,负责 “选节点”。
- Node工作节点,提供 CPU、内存、GPU、存储。
- Pod调度的最小单元。
- 调度策略 / 规则亲和性、污点、容忍、资源限制等。
二、核心认知:调度层到底做什么?
1. 过滤(Predicate)
先去掉不能运行这个 Pod 的节点:
- 资源不够(CPU / 内存不足)
- 端口冲突
- 节点有污点(Taint)
- 不满足亲和性
- 节点宕机 / 被封锁
2. 打分(Priority)
在剩下的节点里选最优:
- 资源利用率最均衡
- 就近(拓扑分布)
- 负载最低
- 亲和性最高
3. 绑定(Bind)
最终决定:Pod → Node
三、K8s 调度层核心能力(必须掌握)
我按使用频率从高到低给你列全:
1. 资源调度(最基础)
- CPU Request / Limit
- Memory Request / Limit
- GPU(nvidia.com/gpu)
作用:保证 Pod 不被 “饿死”,不占满节点。
2. 节点选择(NodeSelector)
最简单的调度:
yaml
nodeSelector:
disk: ssd
env: prod
3. 节点亲和性(Node Affinity)
- 硬亲和:必须调度到某类节点
- 软亲和:尽量调度到某类节点
更灵活,支持多条件、与或非。
4. 污点与容忍(Taints & Tolerations)
- Taint(污点):节点拒绝 Pod
- Toleration(容忍):Pod 我能接受这个污点
典型场景:
- GPU 节点
- 专属节点(数据库、大数据)
- 主节点隔离
5. Pod 亲和性 / 反亲和性
- 亲和:两个 Pod 尽量放一起(性能好)
- 反亲和:两个 Pod 尽量分开(高可用)
典型场景:
- 服务主副本不允许在同一节点
- 缓存和应用就近部署
6. 拓扑调度(Topology Spread Constraints)
按:
- 节点
- 机架
- 可用区(AZ)
- 地域均匀打散 Pod,保证高可用。
7. 优先级与抢占(Priority & Preemption)
- 重要业务 Pod 可以 “挤掉” 低优先级 Pod
- 保证核心服务先运行
四、标准调度流程(面试 / 架构都用得到)
- Pod 创建 → 进入 Pending
- API Server 通知 kube-scheduler
- 过滤:去掉不符合条件的节点
- 打分:对剩下节点排序
- 绑定:将 Pod 分配到得分最高节点
- kubelet 在节点上启动 Pod
五、调度层 核心配置模板(你直接能复制用)
1. 节点亲和性(硬限制 + 软限制)
yaml
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values: ["true"]
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: env
operator: In
values: ["prod"]
2. 污点容忍(调度到 GPU 节点)
yaml
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
3. Pod 反亲和性(高可用)
yaml
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ["my-service"]
topologyKey: kubernetes.io/hostname
4. 拓扑分布约束(跨节点打散)
yaml
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: my-app
六、调度层 典型实操场景
1. CPU 密集型服务
- 节点亲和:高 CPU 机型
- 资源 request/limit 严格
2. GPU 任务(AI 训练 / AI 推理)
- 污点 + 容忍
- GPU 资源声明
- 节点亲和:只调度到 GPU 节点
3. 微服务高可用
- Pod 反亲和
- 拓扑跨节点、跨可用区
4. 有状态服务(StatefulSet)
- 固定节点调度
- 本地存储 + 亲和性
5. 批处理任务(Job/CronJob)
- 低优先级
- 抢占式调度
- 空闲节点运行
七、调度层 进阶扩展(云原生架构师必备)
1. 自定义调度器
替换默认 kube-scheduler,适合超大规模集群。
2. 调度器插件(Scheduler Framework)
- 自定义过滤
- 自定义打分
- 公司级调度策略
3. 集群自动扩缩容(Cluster Autoscaler)
- Pod 调度不了 → 自动买新节点
- 节点空闲 → 自动释放
4. 调度性能优化
- 调度并发
- 缓存优化
- 批量调度
5. 多集群调度(Karmada / KubeFed)
- 跨区域、跨云、多集群统一调度
- 全球分布式架构
6. 弹性调度 + 混部
- 在线服务(微服务 / AI 推理)
- 离线任务(大数据 / 训练)
- 同一集群混跑,提高利用率
八、一句话总结调度层
K8s 调度层 = 集群的 “指挥中心”,负责把所有 Pod 放到最合适的节点,保证资源最优、高可用、业务稳定。
它是:
- 微服务部署的基础
- AI 模型服务(GPU)的核心
- 有状态服务的依赖
- 云原生架构的 “底盘”
流量层:Service + Ingress / Gateway API
一、基础认知:流量层到底干什么?
一句话:流量层 = 负责 “请求怎么进到容器里、怎么在服务之间转发” 的整套机制。
它解决 3 个问题:
- 外部用户 → 集群内服务怎么访问?
- 服务 A → 服务 B 怎么稳定调用?
- 流量怎么路由、灰度、限流、安全?
两层流量结构(最经典、最标准)
- 内部流量:Service集群内部服务互相访问
- 外部流量:Ingress / Gateway API外部域名 + 路由进入集群
二、核心 1:Service(内部流量核心)
1. 基础认知
Service 是 K8s 官方稳定的服务发现 + 负载均衡。
- Pod IP 会变,但 Service IP 不变
- 自动代理到后端 Pod
- 服务间调用用域名:
service-name.namespace.svc.cluster.local
2. 四种类型(必须掌握)
① ClusterIP(默认)
- 仅集群内部可访问
- 微服务之间调用
- 最常用
② NodePort
- 在每个节点开端口
- 外部可访问,但不生产级
③ LoadBalancer
- 云厂商自动创建 LB
- 外部直接访问
- 成本高,不适合大量服务
④ ExternalName
- 映射到外部域名
- 集群访问外部服务用
3. 工作原理
- kube-proxy 维护 iptables/ipvs 规则
- 访问 Service → 转发到任意健康 Pod
- 四层负载均衡(TCP/UDP)
4. 核心配置(极简模板)
yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
type: ClusterIP
selector:
app: user-service
ports:
- port: 80 # Service 端口
targetPort: 8080 # 容器端口
三、核心 2:Ingress(七层外部流量入口)
1. 基础认知
- 七层 HTTP/HTTPS 流量入口
- 基于域名 + 路径路由到不同 Service
- 统一入口:SSL、限流、重写、跨域
2. 核心能力
- 域名路由
- 多域名、多服务
- HTTPS 证书(Secret)
- path 路由 / 重写
- 黑白名单、限流
3. 组成
- Ingress 资源:你写的路由规则
- Ingress Controller:真正执行转发(如 nginx-ingress)
4. 标准模板
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- api.example.com
secretName: ssl-tls
rules:
- host: api.example.com
http:
paths:
- path: /user
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
- path: /ai
backend:
service:
name: ai-service
port:
number: 80
四、核心 3:Gateway API(下一代标准)
1. 基础认知
Gateway API = Ingress 的升级版
- 更灵活
- 更安全
- 更云原生
- 支持流量灰度、权重、HTTP/gRPC/TCP 统一管理
2. 三个核心对象
① Gateway
网关本身:监听端口、TLS
② HTTPRoute
路由规则:域名、path、header、权重
③ ReferenceGrant
权限控制(哪个命名空间能用网关)
3. 优势(为什么要学)
- 支持流量切分(金丝雀)
- 支持请求头改写
- 支持权重路由
- 支持gRPC、TCP
- 角色分离:运维管网关,开发管路由
4. 核心定位
未来云原生流量标准,正在逐步替代 Ingress
五、三者关系(最清晰总结)
plaintext
外部用户
↓
LB(云厂商)
↓
Ingress / Gateway API (七层路由)
↓
Service(四层负载均衡 + 服务发现)
↓
Pod
- Service:内部流量枢纽
- Ingress:外部 HTTP 入口
- Gateway API:下一代统一流量网关
六、典型实操场景(你能直接用)
1. 微服务统一入口
plaintext
api.example.com/user → user-service
api.example.com/order → order-service
api.example.com/ai → ai-service
2. HTTPS 统一证书
所有服务共用一个证书,通过 Ingress 配置。
3. AI 模型服务流式输出
- vLLM / Triton
- 流式响应
- 长连接保持
- 由 Ingress 或 Gateway 提供
4. 灰度发布(Gateway API 最强)
- 90% 流量 → v1
- 10% 流量 → v2
七、进阶扩展(架构师级别)
- TCP /gRPC 暴露
- 限流、熔断、重试
- 灰度 / 金丝雀 / A/B 测试
- WAF 防护
- 多集群网关
- API 管理:认证、授权、限流、计费
- Service Mesh + Gateway 集成(Istio)
八、最简单记忆口诀
- Service 管内部
- Ingress 管外部 HTTP
- Gateway API 是未来统一入口
运维层:监控、日志、存储、CI/CD
(云原生稳定运行的 “底盘”)
一、整体定位
运维层 = 让微服务 + AI 模型服务在 K8s 上稳定、自动化、可追溯地运行。
它负责 4 件事:
- 看得见(监控)
- 查得清(日志)
- 存得住(存储)
- 自动发(CI/CD)
二、1. 监控(Monitoring)
基础认知
- 实时看系统运行状态
- 出问题能告警、定位、复盘
核心组件(云原生事实标准)
- Prometheus:采集、存储指标
- Grafana:大盘展示
- AlertManager:告警(钉钉 / 企业微信 / 邮件)
- Metrics Server:给 HPA 提供数据
监控看什么
- 集群:节点 CPU、内存、磁盘、网络
- 容器:Pod CPU、内存、重启次数
- 业务:QPS、延迟、错误率
- AI:GPU 使用率、推理耗时、并发
核心价值
- 自动发现问题
- 自动弹性扩缩容(HPA)
- 容量规划
- 稳定性保障
三、2. 日志(Logging)
基础认知
- 记录程序运行轨迹
- 出问题追溯、排查、审计
标准架构:EFK / PLG
- EFK
- Elasticsearch:存日志
- Fluentd / Fluent Bit:收集日志
- Kibana:查询、展示
- PLG(轻量)
- Promtail + Loki + Grafana
日志收集方式
- 容器 stdout
- 宿主机文件
- 容器内挂载日志文件
核心价值
- 问题快速定位
- 行为审计
- 安全分析
- 业务统计
四、3. 存储(Storage)
基础认知
- 给容器提供持久化数据
- Pod 删了数据不丢
K8s 存储三件套
- PV:集群存储空间
- PVC:容器申请空间
- StorageClass:自动创建云盘 / 存储
存储使用场景
- 数据库:MySQL、PostgreSQL、Redis
- AI 模型:模型文件、权重、缓存
- 业务:上传文件、导出报表、日志归档
核心价值
- 有状态服务底座
- 数据不丢
- 动态扩容
五、4. CI/CD(持续集成 / 持续部署)
基础认知
- 代码提交 → 自动构建 → 自动部署
- 全流程自动化,不手工操作服务器
主流工具
- GitLab CI
- Jenkins
- GitHub Actions
- ArgoCD(GitOps 云原生主流)
标准流程
- 代码 push → Git
- 自动构建镜像
- 自动扫描安全漏洞
- 自动更新 K8s YAML
- 自动发布到测试 / 预发 / 生产
核心价值
- 发布效率提升 10~100 倍
- 降低人为失误
- 可回滚、可追溯
- 支持灰度、蓝绿
六、运维层整体架构图(极简可直接用)
plaintext
┌─────────────────────────────────────────────────────┐
│ 业务应用层 │
│ 微服务 / AI 模型服务 │
└───────────────────────┬─────────────────────────────┘
│
┌───────────────────────┼─────────────────────────────┐
│ ▼ │
│ 运维层(四大件) │
│ │
│ ┌─────────────┬────────────┬────────┬─────────┐ │
│ │ 监控 │ 日志 │ 存储 │ CI/CD │ │
│ │ Prometheus │ EFK/Loki │ PV/PVC │ GitLab │ │
│ │ Grafana │ Fluent Bit │ SC │ ArgoCD │ │
│ └─────────────┴────────────┴────────┴─────────┘ │
│ │
└───────────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ K8s 集群 │
└─────────────────────────────────────────────────────┘
七、一句话总结运维层
监控让你 “看得见”,日志让你 “查得清”,存储让你 “存得稳”,CI/CD 让你 “发得快”。
它们共同保证:微服务 + AI 模型服务在 K8s 上稳定、高效、自动化运行。
5)AI + K8S 开箱:直接学「AI 云原生落地三件套」
现在企业最缺的就是这个:
-
模型推理部署
-
K8s + TorchServe / Triton / vLLM
-
K8s + TorchServe / Triton /vLLM 到底是什么?
一句话总结:就是把训练好的 AI 模型,变成一个可以在线调用的 API 服务,并且跑在 K8s 上,实现自动扩缩容、高可用、GPU 调度。
1. 先拆成 2 部分看
① K8s 是什么角色?
AI 模型的 “运行平台 + 管理员”
- 负责把模型服务启动、重启、扩缩容
- 负责GPU 分配、节点调度、高可用
- 负责流量分发、负载均衡
- 负责监控、日志、自动恢复
你可以理解:K8s = 模型服务的云原生底座
② TorchServe / Triton /vLLM 是什么角色?
它们是 3 种不同的 “模型推理引擎”= 专门把模型变成 API 的工具。
就像:
- Web 服务用 Tomcat、Nginx
- AI 模型服务用 TorchServe、Triton、vLLM
2. 三个工具分别干什么?(超级清晰)
🔥 TorchServe
专门给 PyTorch 模型用的推理服务器
- 官方出品,简单、轻量
- 适合:小模型、常规模型、个人 / 小团队
- 提供 HTTP API:/predict/health
优点:
- 开箱即用
- PyTorch 生态完美支持
- 适合快速上线
缺点:
- 性能一般
- 不适合超大模型(LLM)
🔥 Triton Inference Server(英伟达出品)
企业级、多框架、高性能统一推理引擎
- 支持 PyTorch、TensorFlow、ONNX、TensorRT
- 支持 CPU/GPU
- 支持并发、批处理、动态调度
- 生产级工业标准
优点:
- 性能极强
- 多模型、多版本管理
- 支持流水线、模型编排
- 大厂标配:腾讯、阿里、字节、百度都用
适合:
- 公司级 AI 平台
- 多模型统一管理
- 高并发、低延迟场景
🔥 vLLM(最火的大模型推理引擎)
专门给 LLM 大模型(如 Llama、Qwen、GLM)做高速推理
- 主打一个:快、快、超快
- 用 PagedAttention 技术,比传统方式快 10~20 倍
- 支持流式输出(streaming)
- 兼容 OpenAI 接口
优点:
- LLM 大模型部署神器
- 显存利用率极高
- 支持高并发聊天、生成
适合:
- 对话机器人
- 文生文
- 私有化大模型 API
3. 放在一起:K8s + TorchServe / Triton /vLLM 是什么?
就是:
把 AI 模型→ 装进容器→ 用 TorchServe / Triton /vLLM 提供 API→ 跑在 K8s 上→ 实现:高可用、自动扩缩容、GPU 调度、灰度发布、监控告警
用生活类比(秒懂)
- K8s = 商场 / 机房
- TorchServe / Triton / vLLM = 售货机 / 服务台
- AI 模型 = 商品
- 用户请求 = 顾客
顾客 → 商场 → 售货机 → 拿到商品用户 → K8s → 推理引擎 → 拿到模型结果
4. 最实用的选型口诀(直接背)
- 小模型、PyTorch、简单部署 → TorchServe
- 企业多模型、高性能、统一管理 → Triton
- 大模型 LLM、对话、高并发 → vLLM
- 全都跑在 K8s 上 → 云原生 AI 服务
5. 架构长这样(极简图)
plaintext
用户请求
↓
Ingress / API 网关
↓
K8s Service(负载均衡)
↓
Pod 里跑着:
TorchServe 或 Triton 或 vLLM
↓
加载 AI 模型,返回结果
开箱即用的 K8s YAML 部署模板
两套开箱即用的 K8s YAML 部署模板—— 分别是 K8s + vLLM(大模型推理)、K8s + Triton(多模型统一推理),你只需要替换模型地址 / 参数,就能直接部署出生产级的 AI 模型服务。
说明
- 所有配置已做生产级优化(资源限制、健康检查、GPU 调度、弹性扩缩容);
- 基于
NVIDIA GPU环境(需集群已安装 NVIDIA 设备插件); - 部署前确保集群有 GPU 节点(标注
gpu: "true")。
一、K8s + vLLM 部署模板(大模型推理)
核心场景:LLM 大模型(如 Llama3、Qwen、GLM)提供 OpenAI 兼容 API,支持流式输出
yaml
# 1. Service(负载均衡 + 服务发现)
apiVersion: v1
kind: Service
metadata:
name: vllm-service
labels:
app: vllm
spec:
type: ClusterIP
selector:
app: vllm
ports:
- port: 8000
targetPort: 8000
name: http
---
# 2. Deployment(vLLM 推理服务)
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-deployment
labels:
app: vllm
spec:
replicas: 1
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
spec:
# 仅调度到 GPU 节点
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values: ["true"]
# 容忍 GPU 节点污点
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: vllm
# 官方 vLLM 镜像(已包含 CUDA)
image: vllm/vllm-openai:latest
ports:
- containerPort: 8000
# 启动命令:加载模型 + 开启 OpenAI 兼容 API
command:
- python
- -m
- vllm.entrypoints.openai.api_server
args:
- --model=Qwen/Qwen2-7B-Instruct # 替换为你的模型(本地/ HuggingFace)
- --port=8000
- --host=0.0.0.0
- --gpu-memory-utilization=0.9 # GPU 显存利用率(按需调整)
- --max-num-batched-tokens=4096 # 批处理最大 Token 数
- --enable-streaming # 开启流式输出
# 资源限制(按需调整)
resources:
limits:
nvidia.com/gpu: 1 # 1 张 GPU
cpu: "8"
memory: "32Gi"
requests:
cpu: "4"
memory: "16Gi"
# 健康检查(生产必备)
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60 # 模型加载慢,延长初始化时间
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 60
periodSeconds: 10
# 模型缓存(可选:挂载 PVC 存储模型,避免每次重启重新下载)
volumeMounts:
- name: model-cache
mountPath: /root/.cache/huggingface
# 持久化模型缓存
volumes:
- name: model-cache
persistentVolumeClaim:
claimName: vllm-model-pvc # 需提前创建 PVC
---
# 3. HPA(自动扩缩容,基于 GPU 利用率)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: vllm-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: vllm-deployment
minReplicas: 1
maxReplicas: 4 # 最大 4 个副本
metrics:
- type: Pods
pods:
metric:
name: nvidia_gpu_utilization # GPU 利用率指标(需 Prometheus + NVIDIA 监控)
target:
type: AverageValue
averageValue: 80 # GPU 利用率超 80% 扩容
behavior:
scaleUp:
stabilizationWindowSeconds: 60 # 扩容冷却 60s
scaleDown:
stabilizationWindowSeconds: 300 # 缩容冷却 5 分钟
---
# 4. Ingress(外部访问入口)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vllm-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive" # 长连接(流式输出)
spec:
tls:
- hosts:
- ai.example.com
secretName: ai-tls-secret # 需提前创建 SSL 证书 Secret
rules:
- host: ai.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: vllm-service
port:
number: 8000
关键配置说明
- 模型替换:把
--model=Qwen/Qwen2-7B-Instruct换成你的模型(支持本地路径 / HuggingFace 地址); - GPU 资源:根据模型大小调整
nvidia.com/gpu数量(如 70B 模型需 4 张 GPU); - 流式输出:
--enable-streaming开启后,支持 ChatGPT 风格的流式返回; - 模型缓存:挂载 PVC 后,模型只需下载一次,重启 Pod 无需重新下载。
测试访问
bash
运行
# 集群内访问
curl http://vllm-service:8000/v1/models
# 外部访问(通过 Ingress)
curl https://ai.example.com/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2-7B-Instruct",
"messages": [{"role": "user", "content": "介绍下 K8s + vLLM"}],
"stream": true
}'
二、K8s + Triton Inference Server 部署模板(多模型统一推理)
核心场景:同时部署 PyTorch/ONNX/TensorRT 模型,提供统一推理 API
yaml
# 1. ConfigMap(Triton 模型配置)
apiVersion: v1
kind: ConfigMap
metadata:
name: triton-model-config
data:
# 模型仓库配置(示例:同时部署 ResNet(图像分类) + BERT(文本分类))
model_repository: |
model_repository/
├── resnet50/
│ ├── 1/
│ │ └── model.onnx # 模型文件
│ └── config.pbtxt # 模型配置
└── bert/
├── 1/
│ └── model.pt
└── config.pbtxt
# ResNet 模型配置示例
resnet50_config.pbtxt: |
name: "resnet50"
platform: "onnxruntime_onnx"
max_batch_size: 32
input [
{
name: "input_0"
data_type: TYPE_FP32
dims: [3, 224, 224]
}
]
output [
{
name: "output_0"
data_type: TYPE_FP32
dims: [1000]
}
]
---
# 2. Service
apiVersion: v1
kind: Service
metadata:
name: triton-service
labels:
app: triton
spec:
type: ClusterIP
selector:
app: triton
ports:
- port: 8000
targetPort: 8000
name: http
- port: 8001
targetPort: 8001
name: grpc
- port: 8002
targetPort: 8002
name: metrics
---
# 3. Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: triton-deployment
labels:
app: triton
spec:
replicas: 1
selector:
matchLabels:
app: triton
template:
metadata:
labels:
app: triton
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values: ["true"]
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: triton
# NVIDIA 官方 Triton 镜像(带 CUDA)
image: nvcr.io/nvidia/tritonserver:24.01-py3
ports:
- containerPort: 8000 # HTTP
- containerPort: 8001 # gRPC
- containerPort: 8002 # Metrics
# 启动 Triton 服务器
command:
- tritonserver
args:
- --model-repository=/models # 模型仓库路径
- --http-port=8000
- --grpc-port=8001
- --metrics-port=8002
- --model-control-mode=poll # 自动加载模型
- --load-model=all # 加载所有模型
# 资源限制
resources:
limits:
nvidia.com/gpu: 1
cpu: "8"
memory: "32Gi"
requests:
cpu: "4"
memory: "16Gi"
# 健康检查
livenessProbe:
httpGet:
path: /v2/health/live
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /v2/health/ready
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
# 挂载模型文件(PVC 存储模型)
volumeMounts:
- name: triton-models
mountPath: /models
# 模型存储 PVC
volumes:
- name: triton-models
persistentVolumeClaim:
claimName: triton-model-pvc # 需提前创建 PVC,放入模型文件
---
# 4. Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: triton-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- triton.example.com
secretName: triton-tls-secret
rules:
- host: triton.example.com
http:
paths:
- path: /v2
pathType: Prefix
backend:
service:
name: triton-service
port:
number: 8000
关键配置说明
- 模型部署:把模型文件(ONNX/PyTorch/TensorRT)放到
triton-model-pvc对应的 PV 路径下,按 Triton 目录结构组织; - 多模型管理:支持同时部署多个模型,通过
config.pbtxt定义输入输出格式、批处理大小; - 协议支持:同时提供 HTTP/gRPC 接口,gRPC 适合低延迟、高并发场景;
- 监控指标:8002 端口暴露 Prometheus 指标,可监控推理延迟、吞吐量、GPU 使用率。
测试访问
bash
运行
# 查看已加载的模型
curl https://triton.example.com/v2/models
# 调用 ResNet 模型推理
curl -X POST https://triton.example.com/v2/models/resnet50/infer \
-H "Content-Type: application/json" \
-d '{
"inputs": [
{
"name": "input_0",
"shape": [1, 3, 224, 224],
"datatype": "FP32",
"data": [/* 图像数据 */]
}
]
}'
三、部署前置条件
- GPU 环境:K8s 集群已安装 NVIDIA 设备插件(
nvidia-device-plugin); - PVC 创建:提前创建用于存储模型的 PVC(参考之前 PV/PVC 教程);
- 监控配置:如需 HPA 基于 GPU 扩缩容,需部署 Prometheus + NVIDIA DCGM 监控;
- 镜像拉取:确保集群能拉取
vllm/vllm-openai和nvcr.io/nvidia/tritonserver镜像(私有仓库需配置 Secret)。
四、核心总结
- vLLM 模板:专为 LLM 大模型优化,支持流式输出、OpenAI 兼容 API,开箱即用;
- Triton 模板:企业级多模型统一推理,支持多框架、批处理、高并发,适合规模化部署;
- 生产优化:包含健康检查、资源限制、GPU 调度、自动扩缩容,直接用于生产环境;
- 灵活调整:只需替换模型地址 / 配置,即可适配不同模型(小模型 / 大模型、CV/NLP)。
你可以先部署单副本测试,验证模型推理正常后,再开启 HPA 实现自动扩缩容,逐步扩到生产规模。
-
AI 任务调度
- K8s Job + Volcano 批量调度
K8s Job + Volcano 批量调度到底是什么?
一句话总结
- K8s Job:跑一次性任务(数据处理、模型训练、数据清洗、离线计算)。
- Volcano:专门给 AI / 大数据 / 批量任务 做的增强版 K8s 调度器。
- 合起来:K8s + Volcano + Job = 云原生批量计算平台(AI 训练标配)
1. 先搞懂:原生 K8s Job 不够用在哪?
原生 Job 只能做简单任务,但AI 训练 / 分布式训练需要:
- GPU 排队、抢占
- 任务优先级(重要训练先跑)
- 分布式训练调度(TensorFlow/PyTorch PS/Worker 模式)
- 任务排队、批队列、资源池管理
- binpack 优化(尽量塞满 GPU,不浪费)
原生 kube-scheduler 搞不定 → 所以要用 Volcano。
2. Volcano 是什么?
Volcano = 云原生批量计算调度引擎(CNCF 毕业项目)专门为这些场景设计:
- AI 模型训练(PyTorch/TensorFlow/MindSpore)
- 大数据(Spark、Flink)
- 批量计算、离线任务
- 渲染、仿真、基因测序
它完全兼容 K8s Job,但强得多。
3. Volcano 核心能力(你必须知道的)
1)批量任务调度(Queue 队列)
任务太多排着等,有资源再跑。
2)GPU / 算力调度
- 按 GPU 数量分配
- 支持多卡、分布式训练
3)任务优先级 & 抢占
- 高优先级任务可以 “抢” 低优先级任务的资源
- 保证核心训练不排队
4)分布式训练调度(PS / Worker / Chief)
PyTorchDistributed、TensorFlow PS 架构直接支持。
5)Binpack 调度(塞满机器,省钱)
尽量把任务塞进同个节点,提高利用率。
6)多租户排队(团队隔离)
不同团队、不同项目有自己的队列和资源配额。
7)兼容原生 K8s Job
你原来的 Job YAML 几乎不用改。
4. K8s Job + Volcano 长什么样?
架构超级简单
plaintext
用户提交 Job
↓
Volcano 调度器(队列、优先级、GPU、资源池)
↓
分配到最合适的节点
↓
启动 Pod 执行任务(训练/数据处理)
5. 最直观对比:原生 Job vs Volcano
表格
| 特性 | 原生 K8s Job | Volcano + Job |
|---|---|---|
| 任务排队 | ❌ 不支持 | ✅ 支持 |
| 优先级 / 抢占 | ❌ 弱 | ✅ 强 |
| 分布式训练 | ❌ 难 | ✅ 原生支持 |
| GPU 调度 | ✅ 基础 | ✅ 企业级 |
| 多租户队列 | ❌ 无 | ✅ 有 |
| 批处理能力 | 简单 | 专业级 |
| 场景 | 简单一次性任务 | AI 训练、大数据、离线计算 |
6. 一句话定位(面试 / 架构都能背)
- K8s Job:定义跑什么任务
- Volcano:决定任务怎么排、谁先跑、跑在哪、用多少 GPU
Volcano 是 AI 训练平台的标配调度器。
7. 给你一段最经典的 Volcano Job YAML(可直接用)
yaml
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: pytorch-train-job
spec:
# 调度队列(Volcano 核心)
schedulerName: volcano
queue: default
# 任务优先级
priorityClassName: high-priority
# 最大重试次数
maxRetry: 3
# 分布式训练:PyTorch Worker
tasks:
- name: worker
replicas: 4 # 4 个 Worker 分布式训练
template:
spec:
containers:
- name: train
image: pytorch/pytorch:2.0-cuda11.7-cudnn8-runtime
command: ["python", "train.py"]
resources:
limits:
nvidia.com/gpu: 1 # 每个Worker 1张GPU
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: training-data
8. 最常见使用场景(你一定会遇到)
1)AI 模型训练(最主流)
PyTorch / TensorFlow 分布式训练
2)数据预处理 / 清洗
大量离线 Job,排队跑
3)大数据 Spark / Flink 任务
Volcano 比原生调度稳定很多
4)批量推理
跑一批图片、视频、语音推理任务
5)渲染、仿真、基因测序
高算力、批量、排队任务
9. 超级好记的总结
- K8s Job = 一次性任务
- Volcano = 批量任务调度增强器
- K8s Job + Volcano = 云原生 AI / 大数据 计算平台
开箱即用的 Volcano + PyTorch 分布式训练完整部署方案
开箱即用的 Volcano + PyTorch 分布式训练完整部署方案,包含「Volcano 安装 → 分布式训练 Job YAML → 任务提交 / 监控 → 结果验证」全流程,你只需替换训练脚本和数据地址,就能直接跑起分布式训练。
核心说明
- 基于 PyTorch Distributed Data Parallel (DDP) 分布式训练(最主流的多卡 / 多机训练方式);
- 适配 GPU 集群,支持 多 Worker + 多 GPU;
- 包含 Volcano 队列、优先级、资源配额等生产级配置。
一、前置准备:安装 Volcano
1. 快速安装(推荐)
bash
运行
# 安装最新版 Volcano(兼容 K8s 1.20+)
kubectl apply -f https://raw.githubusercontent.com/volcano-sh/volcano/master/installer/volcano-development.yaml
# 验证安装(看到以下组件 Running 即成功)
kubectl get pods -n volcano-system
# 预期输出:
# NAME READY STATUS RESTARTS AGE
# volcano-admission-7f987d9c7f-xxxx 1/1 Running 0 5m
# volcano-controllers-7896d876c6-xxxx 1/1 Running 0 5m
# volcano-scheduler-5f97867894-xxxx 1/1 Running 0 5m
2. 创建 Volcano 队列(任务排队 / 资源隔离)
yaml
# volcano-queue.yaml
apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
name: ai-training-queue
spec:
# 队列资源配额(限制该队列最多用 8 张 GPU、16核 CPU)
resourceQuota:
hard:
nvidia.com/gpu: 8
cpu: 16
memory: 64Gi
# 队列优先级(高优先级队列先调度)
priority: 100
bash
运行
kubectl apply -f volcano-queue.yaml
# 验证队列
kubectl get queue
# 预期输出:
# NAME CLUSTER PRIORITY STATE AGE
# ai-training-queue default 100 Open 10s
二、Volcano + PyTorch 分布式训练完整 YAML
1. 训练数据 PVC(持久化训练数据 / 模型)
yaml
# training-data-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pytorch-training-pvc
spec:
accessModes:
- ReadWriteMany # 多 Worker 共享读写
resources:
requests:
storage: 100Gi
storageClassName: nfs-storage # 替换为你的共享存储类(如 NFS/CEPH)
bash
运行
kubectl apply -f training-data-pvc.yaml
2. 分布式训练 Job(核心配置)
yaml
# pytorch-ddp-training-job.yaml
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: pytorch-ddp-training
labels:
app: pytorch-training
spec:
# 指定 Volcano 调度器(核心)
schedulerName: volcano
# 绑定训练队列
queue: ai-training-queue
# 任务优先级(队列内优先级)
priorityClassName: high-priority
# 最大重试次数(训练失败自动重试)
maxRetry: 3
# 任务完成策略:所有 Worker 完成才算结束
completionPolicy:
type: AllCompletions
# 分布式训练任务定义(Worker 节点)
tasks:
- name: ddp-worker
# 4 个 Worker 节点(每个节点 1 张 GPU,共 4 卡训练)
replicas: 4
# 任务模板
template:
spec:
# 仅调度到 GPU 节点
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values: ["true"]
# 容忍 GPU 节点污点
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
# 容器配置
containers:
- name: pytorch-trainer
# PyTorch 官方镜像(带 CUDA/分布式训练依赖)
image: pytorch/pytorch:2.2.0-cuda12.1-cudnn8-runtime
# 启动分布式训练脚本
command:
- /bin/bash
- -c
- |
# 设置分布式训练环境变量
export MASTER_ADDR=$(hostname -i)
export MASTER_PORT=29500
export WORLD_SIZE=4 # 总 Worker 数
# 获取当前 Worker 序号(Volcano 自动注入 VOLCANO_TASK_INDEX)
export RANK=${VOLCANO_TASK_INDEX}
export LOCAL_RANK=0
# 进入数据目录
cd /data
# 下载示例训练脚本(替换为你的脚本)
wget -O train_ddp.py https://raw.githubusercontent.com/pytorch/examples/main/distributed/ddp/train_ddp.py
# 启动分布式训练
python -m torch.distributed.launch \
--nproc_per_node=1 \
--nnodes=${WORLD_SIZE} \
--node_rank=${RANK} \
--master_addr=$(kubectl get pod pytorch-ddp-training-ddp-worker-0 -o jsonpath='{.status.podIP}') \
--master_port=29500 \
train_ddp.py \
--epochs=10 \
--batch-size=64
# 资源限制(每个 Worker 1 张 GPU、4 核 CPU、16Gi 内存)
resources:
limits:
nvidia.com/gpu: 1
cpu: 4
memory: 16Gi
requests:
cpu: 2
memory: 8Gi
# 挂载训练数据/模型目录
volumeMounts:
- name: training-data
mountPath: /data
# 健康检查(训练任务长时间运行,关闭存活检查,仅做就绪检查)
readinessProbe:
exec:
command: ["pgrep", "python"]
initialDelaySeconds: 60
periodSeconds: 30
# 重启策略:训练失败不重启(由 Volcano 重试整个 Job)
restartPolicy: Never
# 挂载 PVC
volumes:
- name: training-data
persistentVolumeClaim:
claimName: pytorch-training-pvc
关键配置说明
- 分布式核心:
WORLD_SIZE=4:总 Worker 数(对应replicas: 4);VOLCANO_TASK_INDEX:Volcano 自动为每个 Worker 注入的序号(0~3),作为分布式训练的RANK;torch.distributed.launch:PyTorch 分布式训练启动器,自动搭建通信集群。
- 资源调度:
- 绑定
ai-training-queue队列,受队列资源配额限制; - 仅调度到带
gpu: "true"标签的节点,保证 GPU 资源。
- 绑定
- 数据持久化:
- 挂载
ReadWriteMany类型的 PVC,所有 Worker 可共享训练数据,训练结果(模型文件)也会保存到 PVC 中。
- 挂载
三、提交并监控训练任务
1. 提交 Job
bash
运行
kubectl apply -f pytorch-ddp-training-job.yaml
# 查看 Job 状态
kubectl get vcjob pytorch-ddp-training
# 预期输出(PENDING → RUNNING → COMPLETED):
# NAME STATE MINIMUM PENDING RUNNING SUCCEEDED FAILED AGE
# pytorch-ddp-training RUNNING 4 0 4 0 0 2m
2. 查看训练 Pod
bash
运行
# 查看所有 Worker Pod
kubectl get pods -l app=pytorch-training
# 预期输出:
# NAME READY STATUS RESTARTS AGE
# pytorch-ddp-training-ddp-worker-0 1/1 Running 0 3m
# pytorch-ddp-training-ddp-worker-1 1/1 Running 0 3m
# pytorch-ddp-training-ddp-worker-2 1/1 Running 0 3m
# pytorch-ddp-training-ddp-worker-3 1/1 Running 0 3m
3. 查看训练日志(验证分布式训练)
bash
运行
# 查看任意 Worker 日志
kubectl logs -f pytorch-ddp-training-ddp-worker-0
# 关键日志(看到以下内容说明分布式训练成功):
# > Initializing distributed: GLOBAL_RANK: 0, MEMBER: 1/4
# > Initializing distributed: GLOBAL_RANK: 1, MEMBER: 2/4
# > Initializing distributed: GLOBAL_RANK: 2, MEMBER: 3/4
# > Initializing distributed: GLOBAL_RANK: 3, MEMBER: 4/4
# > Epoch 1/10, Loss: 2.302, Accuracy: 10.0%
# > Epoch 10/10, Loss: 0.123, Accuracy: 98.5%
# > Training completed! Model saved to /data/model.pth
4. 查看队列资源使用
bash
运行
kubectl describe queue ai-training-queue
# 查看 "Allocated Resources" 部分,确认 GPU/CPU 资源已分配:
# Allocated Resources:
# nvidia.com/gpu: 4
# cpu: 16
# memory: 64Gi
四、任务完成后验证结果
1. 检查 Job 状态
bash
运行
kubectl get vcjob pytorch-ddp-training
# 预期输出:
# NAME STATE MINIMUM PENDING RUNNING SUCCEEDED FAILED AGE
# pytorch-ddp-training Completed 4 0 0 4 0 30m
2. 查看训练结果(模型文件)
bash
运行
# 进入任意 Pod 查看模型文件
kubectl exec -it pytorch-ddp-training-ddp-worker-0 -- ls /data
# 预期输出:
# train_ddp.py model.pth training.log
3. 清理任务(可选)
bash
运行
# 删除训练 Job
kubectl delete vcjob pytorch-ddp-training
# 保留 PVC(模型文件),如需清理则执行:
# kubectl delete pvc pytorch-training-pvc
五、生产级优化建议
-
训练脚本定制:
-
替换示例
train_ddp.py为你的实际训练脚本(如图像分类、LLM 预训练); -
增加 checkpoint 保存逻辑,训练中断后可续跑。
-
-
资源调度优化:
-
为不同训练任务创建不同队列(如
llm-training-queue、cv-training-queue),实现团队 / 任务隔离; -
配置
priorityClassName,核心任务(如正式训练)设为高优先级,测试任务设为低优先级。
-
-
监控告警:
-
部署 Prometheus + Volcano 监控插件,监控队列资源使用率、任务运行时长、失败率;
-
配置 AlertManager 告警,当训练任务失败 / 资源不足时触发通知。
-
-
多机多卡扩展:
-
增加
replicas数量(如 8),并调整WORLD_SIZE为对应值,实现 8 卡分布式训练; -
如需多机训练,确保节点间网络互通(Calico/Flannel 网络插件支持)。
-
核心总结
- Volcano 核心价值:为 PyTorch 分布式训练提供队列调度、优先级、资源隔离、GPU 精准调度,解决原生 K8s Job 无法满足的批量 / 分布式训练需求;
- 部署流程:安装 Volcano → 创建队列 → 编写分布式训练 Job → 提交监控 → 验证结果;
- 关键配置:
schedulerName: volcano绑定 Volcano 调度器,VOLCANO_TASK_INDEX实现分布式训练节点序号分配,PVC 保证数据 / 模型持久化。
这套方案可直接用于生产环境,适配 CV/NLP/LLM 等各类 PyTorch 分布式训练场景。
-
GPU 虚拟化 / 共享
- nvidia-device-plugin、MIG、vGPU
nvidia-device-plugin + MIG + vGPU 到底是什么?
一句话总结
这三个都是 K8s 集群中 NVIDIA GPU 资源的管理 / 切分工具,核心解决:
- nvidia-device-plugin:让 K8s 能 “看见” GPU,是基础;
- MIG:物理 GPU 硬切分(适合算力密集型任务);
- vGPU:物理 GPU 软切分(适合多轻量任务共享)。
1. 先搞懂:为什么需要这些工具?
原生 K8s 不认识 GPU → 无法调度 / 分配 GPU 资源;一张物理 GPU 很贵(几万 / 张)→ 直接给一个任务用太浪费 → 需要切分成更小的单元共享。
2. 逐个拆解(从基础到进阶)
🔥 1)nvidia-device-plugin(GPU 管理基础)
核心定位
K8s 与 NVIDIA GPU 之间的 “翻译官”
- 让 K8s 知道:集群有多少张 GPU、每张 GPU 用了多少;
- 让 K8s 能:给 Pod 分配 GPU(
nvidia.com/gpu: 1); - 是所有 NVIDIA GPU 调度的前提,必须先装。
核心作用
表格
| 功能 | 说明 |
|---|---|
| 资源发现 | 自动识别节点上的 NVIDIA GPU 型号 / 数量 |
| 资源分配 | K8s 调度时,为 Pod 分配指定数量的 GPU |
| 资源隔离 | 保证 Pod 只能用分配的 GPU,不抢占其他 Pod 的 GPU |
| 状态上报 | 向 K8s API Server 上报 GPU 使用率 / 健康状态 |
安装(极简命令)
bash
运行
# 部署 nvidia-device-plugin(DaemonSet,每个 GPU 节点跑一个)
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.15.0/nvidia-device-plugin.yml
# 验证安装(节点标注出现 nvidia.com/gpu 数量)
kubectl describe node <gpu-node-name> | grep nvidia.com/gpu
# 预期输出:nvidia.com/gpu: 2(节点有 2 张 GPU)
使用示例(Pod 申请 GPU)
yaml
resources:
limits:
nvidia.com/gpu: 1 # 申请 1 张物理 GPU
🔥 2)MIG(Multi-Instance GPU)—— GPU 硬切分
核心定位
NVIDIA 高端 GPU 自带的 “硬件级切分功能”
-
把一张物理 GPU 切分成 多个独立的 MIG 实例(比如 A100 可切成 7 个实例);
-
每个 MIG 实例有独立的显存、算力、缓存,互相完全隔离;
-
只有 NVIDIA A100/A30/H100/H200 等高端 GPU 支持。
核心特点
表格
|
特性 |
说明 |
|---|---|
|
硬件隔离 |
切分后实例间无性能干扰,比软切分稳定 |
|
固定规格 |
每张 GPU 有固定的切分规格(如 A100 可切:1g.5gb / 2g.10gb / 3g.20gb) |
|
独立调度 |
K8s 可把每个 MIG 实例当作独立 GPU 分配( |
|
适合场景 |
AI 训练、高性能推理(需要稳定算力 / 显存) |
核心用法(K8s 中使用 MIG)
1)开启 MIG(节点上操作)
bash
运行
# 登录 GPU 节点,开启 MIG 模式
nvidia-smi -mig 1
# 创建 MIG 实例(A100 切 4 个 2g.10gb 实例)
nvidia-mig-manager create -f a100_4x2g10gb
2)K8s 中申请 MIG 实例
yaml
resources:
limits:
# 申请 1 个 2g.10gb 的 MIG 实例(不是整张 GPU)
nvidia.com/mig-2g.10gb: 1
优势 vs 劣势
表格
|
优势 |
劣势 |
|---|---|
|
性能无干扰 |
仅高端 GPU 支持 |
|
显存 / 算力隔离 |
切分规格固定,不够灵活 |
|
稳定性高 |
配置复杂 |
🔥 3)vGPU(Virtual GPU)—— GPU 软切分
核心定位
NVIDIA 虚拟化技术,软件级切分 GPU
-
把一张物理 GPU 切分成 多个 vGPU 虚拟机 / 容器;
-
基于软件层隔离,实例间共享 GPU 核心,可灵活分配显存 / 算力;
-
支持大部分 NVIDIA GPU(Tesla/P4/T4/A10/A16/A30 等)。
核心特点
表格
|
特性 |
说明 |
|---|---|
|
软件隔离 |
基于驱动层切分,实例间可能有轻微性能干扰 |
|
灵活规格 |
可自定义每个 vGPU 的显存(如 2GB/4GB/8GB)、算力占比 |
|
广泛兼容 |
支持中低端 GPU,成本更低 |
|
适合场景 |
轻量推理、多用户共享 GPU、开发测试 |
K8s 中使用 vGPU(基于 NVIDIA vGPU 驱动)
1)前置条件
-
节点安装 NVIDIA vGPU 驱动 + 许可证;
-
部署 vGPU 设备插件(替代原生 nvidia-device-plugin)。
2)申请 vGPU 资源
yaml
resources:
limits:
# 申请 1 个 vGPU,显存 4GB,算力 20%
nvidia.com/vgpu: 4GB-20%
优势 vs 劣势
表格
|
优势 |
劣势 |
|---|---|
|
成本低、兼容广 |
性能有轻微损耗 |
|
规格灵活 |
隔离性不如 MIG |
|
易配置 |
需要许可证(付费) |
3. 三者核心关系(一张表看懂)
表格
| 维度 | nvidia-device-plugin | MIG | vGPU |
|---|---|---|---|
| 定位 | GPU 基础管理插件 | GPU 硬件切分 | GPU 软件切分 |
| 隔离级别 | 物理 GPU 级 | 硬件实例级 | 软件虚拟级 |
| 灵活性 | 低(只能分配整张 GPU) | 中(固定规格) | 高(自定义规格) |
| 性能 | 无损耗 | 无损耗 | 轻微损耗 |
| 成本 | 免费 | 高(仅高端 GPU) | 中(需许可证) |
| 适合场景 | 所有 GPU 集群基础配置 | AI 训练 / 高性能推理 | 轻量推理 / 共享 GPU |
4. 典型使用场景(直接对号入座)
场景 1:AI 训练(A100/H100)
- 基础:安装
nvidia-device-plugin; - 切分:用 MIG 把 1 张 A100 切成 4 个实例,同时跑 4 个训练任务;
- 优势:硬件隔离,训练互不干扰。
场景 2:LLM 轻量推理(T4/A10)
- 基础:安装
nvidia-device-plugin; - 切分:用 vGPU 把 1 张 T4 切成 8 个 vGPU(每个 2GB 显存),同时提供 8 路推理;
- 优势:成本低,利用率高。
场景 3:开发测试环境
- 基础:安装
nvidia-device-plugin; - 切分:用 vGPU 给每个开发者分配 1 个 4GB vGPU;
- 优势:灵活共享,降低硬件成本。
5. 超级好记的总结
- nvidia-device-plugin:K8s 用 GPU 的 “基础门票”,必须装;
- MIG:高端 GPU 硬切分,稳但贵,适合训练;
- vGPU:中低端 GPU 软切分,灵但略损性能,适合推理 / 共享。
三者的核心目标都是:让 K8s 能精细化管理 GPU,提高 GPU 利用率,降低成本。
学习法:不啃论文,直接跑通「模型打包 → 上 K8s → 对外提供 API」。
6)架构师思维开箱:用 3 个问题代替死记硬背
任何技术,你只问三句:
- 它解决什么业务问题?
- 在 K8s 里放在哪一层?
- 出问题怎么排查?
能回答,你就是架构师思维,不是运维背命令。
7)实战开箱:做 1 个完整云原生 AI 项目(最提效)
建议你直接做这个:「基于 K8s 的 AI 模型推理服务平台」流程:
-
写一个简单模型(torch)
基于 PyTorch 框架的简单深度学习模型,我会为你提供一个结构清晰、注释完整的基础模型示例,适合新手理解和上手。
我将以图像分类这个最经典的任务为例,构建一个简单的全连接神经网络(MLP),这个模型结构简单,能帮你快速理解 PyTorch 构建模型的核心逻辑。
完整代码示例
python
运行
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# ====================== 1. 定义简单的神经网络模型 ======================
class SimpleMLP(nn.Module):
"""
简单的多层感知机(MLP)模型,用于图像分类(以MNIST手写数字为例)
输入:28x28的灰度图(展平后为784维向量)
输出:10类数字的概率分布
"""
def __init__(self, input_size=784, hidden_size=128, output_size=10):
super(SimpleMLP, self).__init__()
# 定义网络层
self.fc1 = nn.Linear(input_size, hidden_size) # 第一层全连接:输入层→隐藏层
self.relu = nn.ReLU() # 激活函数(引入非线性)
self.fc2 = nn.Linear(hidden_size, output_size) # 第二层全连接:隐藏层→输出层
def forward(self, x):
"""
前向传播(必须实现的核心方法)
:param x: 输入张量,形状为 [batch_size, input_size]
:return: 输出张量,形状为 [batch_size, output_size]
"""
# 展平输入(如果输入是[batch_size, 1, 28, 28],先转为[batch_size, 784])
x = x.view(x.size(0), -1)
# 逐层计算
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# ====================== 2. 初始化模型、损失函数、优化器 ======================
# 设置设备(优先使用GPU,没有则用CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 初始化模型并移到指定设备
model = SimpleMLP(input_size=784, hidden_size=128, output_size=10).to(device)
# 损失函数:分类任务用交叉熵损失(自动包含Softmax)
criterion = nn.CrossEntropyLoss()
# 优化器:随机梯度下降(SGD),也可以用Adam(更常用)
optimizer = optim.Adam(model.parameters(), lr=0.001)
# ====================== 3. 模拟训练过程(用随机数据) ======================
# 生成模拟数据:100个样本,每个样本是1通道28x28的图像,标签是0-9的数字
batch_size = 10
x_train = torch.randn(100, 1, 28, 28).to(device) # 输入数据
y_train = torch.randint(0, 10, (100,)).to(device) # 标签
# 构建数据加载器(批量加载数据)
train_dataset = TensorDataset(x_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# 训练5个epoch
num_epochs = 5
model.train() # 切换到训练模式
for epoch in range(num_epochs):
running_loss = 0.0
for batch_idx, (data, targets) in enumerate(train_loader):
# 1. 前向传播
outputs = model(data)
loss = criterion(outputs, targets)
# 2. 反向传播+优化
optimizer.zero_grad() # 清空梯度(必须!)
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新参数
# 统计损失
running_loss += loss.item()
# 打印每个epoch的平均损失
epoch_loss = running_loss / len(train_loader)
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}')
print("训练完成!")
# ====================== 4. 模拟推理过程 ======================
model.eval() # 切换到评估模式(禁用Dropout/BatchNorm等)
with torch.no_grad(): # 禁用梯度计算(节省内存、加快速度)
# 取一个测试样本
test_sample = torch.randn(1, 1, 28, 28).to(device)
output = model(test_sample)
# 取概率最大的类别作为预测结果
pred_label = torch.argmax(output, dim=1).item()
print(f"\n测试样本的预测标签:{pred_label}")
# 保存模型
torch.save(model.state_dict(), "simple_mlp_model.pth")
print("模型已保存为 simple_mlp_model.pth")
代码关键部分解释
-
模型定义(SimpleMLP 类):
-
必须继承
nn.Module,这是 PyTorch 所有模型的基类。 -
__init__方法:定义网络层(如全连接层nn.Linear、激活函数nn.ReLU)。 -
forward方法:定义前向传播逻辑(数据如何通过各层),不能手动调用 forward,直接用model(x)即可。
-
-
训练核心三步:
-
前向传播:输入数据→计算输出→计算损失。
-
清空梯度:
optimizer.zero_grad()(否则梯度会累加,导致错误)。 -
反向传播 + 更新参数:
loss.backward()+optimizer.step()。
-
-
模式切换:
-
model.train():训练模式(启用 Dropout、BatchNorm 的训练行为)。 -
model.eval():评估模式(禁用 Dropout、固定 BatchNorm 参数)。 -
torch.no_grad():推理时禁用梯度计算,避免不必要的内存消耗。
-
总结
-
PyTorch 构建模型的核心是继承
nn.Module,实现__init__(定义层)和forward(定义前向传播)。 -
训练流程固定为:前向传播算损失 → 清空梯度 → 反向传播算梯度 → 优化器更新参数。
-
推理时需切换到
eval()模式,并使用torch.no_grad()禁用梯度计算,提升效率。
这个模型是最基础的版本,你可以在此基础上扩展(比如增加隐藏层、添加 Dropout 防止过拟合、换成卷积层处理图像等),核心逻辑完全通用。
-
打包 Docker
你想要把上一个基于 PyTorch 的简单模型打包成 Docker 镜像,这样可以在任何支持 Docker 的环境中运行,避免环境配置的麻烦。我会为你提供完整的 Dockerfile 编写、镜像构建和容器运行的步骤,全程保持简洁易懂。
前置条件
- 你的电脑已安装 Docker(Windows/Mac 需安装 Docker Desktop,Linux 需安装 Docker Engine)
- 已准备好上一步的模型代码文件(命名为
simple_model.py)
步骤 1:编写 Dockerfile
Dockerfile 是构建 Docker 镜像的 "配方",我们基于官方的 PyTorch 镜像来构建,避免手动安装复杂依赖。
在代码同目录下创建名为Dockerfile的文件(无后缀),内容如下:
dockerfile
# 基础镜像:使用官方的PyTorch镜像(包含Python、PyTorch、CUDA等)
# 选择轻量的CPU版本(如果需要GPU,替换为 pytorch/pytorch:2.2.0-cuda12.1-cudnn8-runtime)
FROM pytorch/pytorch:2.2.0-cpu
# 设置工作目录(容器内的目录)
WORKDIR /app
# 复制本地的模型代码到容器的工作目录
COPY simple_model.py /app/
# 可选:安装额外依赖(如果代码需要)
# RUN pip install --no-cache-dir numpy pandas
# 设置容器启动时默认执行的命令
CMD ["python", "simple_model.py"]
步骤 2:编写.dockerignore(可选但推荐)
创建.dockerignore文件,排除不需要复制到镜像的文件,减小镜像体积:
plaintext
# 排除Python缓存文件
__pycache__/
*.pyc
*.pyo
*.pyd
# 排除Docker相关文件
Dockerfile
.dockerignore
# 排除模型权重文件(如果后续保存了,可按需排除)
*.pth
# 排除其他无关文件
.git
.gitignore
venv/
.env
步骤 3:构建 Docker 镜像
打开终端 / 命令行,进入代码和 Dockerfile 所在目录,执行以下命令:
bash
运行
# 构建镜像,-t 指定镜像名称(如simple-torch-model),. 表示Dockerfile在当前目录
docker build -t simple-torch-model .
命令解释:
-
-t simple-torch-model:给镜像打标签,方便后续引用 -
.:指定构建上下文为当前目录(即 Dockerfile 中 COPY 的文件从当前目录读取)
构建完成后,执行docker images可看到刚构建的镜像。
步骤 4:运行 Docker 容器
镜像构建完成后,执行以下命令启动容器运行模型:
bash
运行
# 运行容器,--rm 表示容器运行结束后自动删除(节省空间)
docker run --rm simple-torch-model
如果需要 GPU 支持(需主机有 NVIDIA 显卡且安装了 NVIDIA Container Toolkit):
bash
运行
# 启用GPU的运行命令
docker run --rm --gpus all simple-torch-model
步骤 5:验证运行结果
容器启动后,会自动执行python simple_model.py,终端会输出模型训练的日志(如 Epoch 损失、预测结果),和本地运行效果一致,说明打包和运行成功。
额外实用操作
-
进入容器调试(如果运行出错,可进入容器排查):
bash
运行
# 以交互模式启动容器,/bin/bash 进入命令行
docker run -it --rm simple-torch-model /bin/bash
-
保存 / 加载镜像(用于迁移到其他机器):
bash
运行
# 保存镜像为tar文件
docker save -o simple-torch-model.tar simple-torch-model
# 加载tar文件为镜像
docker load -i simple-torch-model.tar
-
后台运行容器:
bash
运行
# -d 表示后台运行,-name 指定容器名称
docker run -d --name torch-model-container simple-torch-model
# 查看容器日志
docker logs torch-model-container
总结
- 打包 PyTorch 模型的核心是基于官方 PyTorch 镜像编写 Dockerfile,避免手动配置环境;
- 构建镜像用
docker build -t 名称 .,运行容器用docker run --rm 镜像名; - 如需 GPU 支持,需替换基础镜像为 CUDA 版本,并添加
--gpus all参数运行容器。
这个流程是通用的,你后续无论修改模型代码还是添加依赖,只需更新 Dockerfile 中的COPY或RUN pip install部分,重新构建镜像即可。
-
写 K8s YAML
Kubernetes (K8s) 集群中部署上述 PyTorch 模型的 YAML 配置文件,我会为你提供基础的 Deployment 配置(适合运行无状态的模型任务),并附带详细注释和使用说明,确保新手能快速理解和上手。
前置条件
-
K8s 集群已部署并可访问(如 minikube、k3s、云厂商 K8s 等)
-
kubectl工具已配置并能连接集群 -
你的 PyTorch 镜像已推送到集群可访问的镜像仓库(如 Docker Hub、Harbor 等)
完整 YAML 配置文件
创建名为 torch-model-deployment.yaml 的文件,内容如下(所有关键配置都有注释):
yaml
# 配置类型:Deployment(无状态应用部署)
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment 名称(自定义)
name: simple-torch-model
# 命名空间(可自定义,默认default)
namespace: default
# 标签(用于关联Service、Pod等)
labels:
app: torch-model
spec:
# 副本数(运行多少个Pod实例)
replicas: 1
# 标签选择器:匹配Pod的标签
selector:
matchLabels:
app: torch-model
# Pod 模板(定义Pod的具体配置)
template:
metadata:
labels:
app: torch-model
spec:
# 容器配置(核心)
containers:
- name: torch-model-container
# 镜像地址(替换为你自己的镜像仓库地址,如 docker.io/你的用户名/simple-torch-model:latest)
image: simple-torch-model:latest
# 镜像拉取策略:Always(总是拉取最新)、IfNotPresent(本地没有才拉取)、Never(只用本地)
imagePullPolicy: IfNotPresent
# 资源限制(可选,推荐配置,避免占用过多集群资源)
resources:
requests:
# 最小资源需求
cpu: "100m" # 100毫核(0.1核)
memory: "256Mi" # 256MB内存
limits:
# 最大资源限制
cpu: "500m" # 0.5核
memory: "512Mi" # 512MB内存
# 重启策略:Pod异常时的处理(Always/OnFailure/Never)
restartPolicy: OnFailure
# 可选:容器启动命令(覆盖镜像的CMD)
# command: ["python", "simple_model.py"]
# 可选:环境变量(如需传递参数)
# env:
# - name: LEARNING_RATE
# value: "0.001"
---
# 可选:Service配置(如果模型需要对外提供服务,如API)
# 这里仅演示ClusterIP类型(集群内访问),如需外部访问可改用NodePort/LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: torch-model-service
namespace: default
spec:
# 选择器:匹配Deployment的Pod标签
selector:
app: torch-model
# Service类型
type: ClusterIP
# 端口映射(容器端口→Service端口)
ports:
- port: 80 # Service对外暴露的端口
targetPort: 8080 # 容器内应用监听的端口(需模型代码启动Web服务才需要)
protocol: TCP
关键配置解释
-
Deployment 核心字段:
-
replicas: 运行的 Pod 数量,新手先设为 1,避免资源浪费; -
image: 必须替换为你推送到镜像仓库的实际镜像地址(如docker.io/yourname/simple-torch-model:v1); -
resources: 限制 Pod 的 CPU / 内存使用,防止单个 Pod 占用集群全部资源; -
restartPolicy: OnFailure: 仅当模型运行失败时重启 Pod(适合一次性训练任务),如果是常驻服务可改为Always。
-
-
镜像仓库说明:本地构建的镜像(
simple-torch-model:latest)仅在本机可见,K8s 集群(尤其是多节点集群)无法直接访问,需推送到公共 / 私有镜像仓库:bash
运行
# 1. 给镜像打标签(替换为你的仓库地址) docker tag simple-torch-model:latest docker.io/你的用户名/simple-torch-model:latest # 2. 登录Docker Hub docker login # 3. 推送镜像 docker push docker.io/你的用户名/simple-torch-model:latest推送完成后,将 YAML 中的
image字段替换为上述标签。
部署和验证命令
bash
运行
# 1. 部署到K8s集群
kubectl apply -f torch-model-deployment.yaml
# 2. 查看Deployment状态
kubectl get deployments
# 3. 查看Pod状态(确认Running/Completed)
kubectl get pods
# 4. 查看Pod日志(验证模型是否正常运行)
kubectl logs <Pod名称> # 替换为实际Pod名,如 simple-torch-model-7f987d6b89-xxxx
# 5. 如需删除部署
kubectl delete -f torch-model-deployment.yaml
针对 GPU 集群的额外配置(可选)
如果你的 K8s 集群有 GPU 节点,需在 Pod 模板中添加 GPU 资源请求,修改resources部分:
yaml
resources:
requests:
cpu: "100m"
memory: "512Mi"
nvidia.com/gpu: 1 # 请求1块GPU
limits:
cpu: "1000m"
memory: "1Gi"
nvidia.com/gpu: 1 # 限制最多使用1块GPU
总结
-
K8s 部署 PyTorch 模型的核心是
Deployment配置,通过template定义 Pod 的容器、资源、镜像等; -
必须确保镜像推送到集群可访问的仓库,否则 Pod 会因拉取镜像失败而报错;
-
关键配置项:
image(镜像地址)、replicas(副本数)、resources(资源限制)、restartPolicy(重启策略); -
部署后通过
kubectl get pods和kubectl logs验证运行状态。
这份配置是基础版,适合一次性的模型训练任务;如果是需要对外提供推理服务的模型,还可以结合Service(NodePort/LoadBalancer)和Ingress实现外部访问,核心配置逻辑一致。
-
部署 Service + Ingress
在 K8s 中为 PyTorch 模型部署Service(服务暴露)和Ingress(外部访问入口),让模型能通过域名 / IP 对外提供推理服务。我会基于之前的 Deployment 配置,补充完整的 Service+Ingress YAML,并说明关键配置和验证步骤,同时适配新手的理解难度。
前置说明
- 本次示例会先改造模型代码,让它以Web 服务(Flask)形式运行(否则 Ingress/Service 无意义);
- 需确保 K8s 集群已安装 Ingress 控制器(如 NGINX Ingress Controller,后面会给出安装命令);
- 核心逻辑:Ingress → Service → Pod(运行模型 Web 服务)。
步骤 1:改造模型代码为 Web 服务
将之前的simple_model.py修改为带 Flask 接口的推理服务,这样才能通过 HTTP 访问:
python
运行
import torch
import torch.nn as nn
from flask import Flask, request, jsonify
# ====================== 1. 定义模型(复用之前的SimpleMLP) ======================
class SimpleMLP(nn.Module):
def __init__(self, input_size=784, hidden_size=128, output_size=10):
super(SimpleMLP, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, output_size)
def forward(self, x):
x = x.view(x.size(0), -1)
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# ====================== 2. 初始化模型(模拟加载训练好的权重) ======================
device = torch.device("cpu")
model = SimpleMLP().to(device)
model.eval() # 推理模式
# ====================== 3. 启动Flask Web服务 ======================
app = Flask(__name__)
@app.route('/predict', methods=['POST'])
def predict():
"""
推理接口:接收JSON格式的图像数据,返回预测结果
请求示例:{"data": [0.1, 0.2, ..., 0.784]}(784维向量)
"""
try:
# 解析请求数据
data = request.get_json()['data']
# 转换为Tensor并推理
input_tensor = torch.tensor(data, dtype=torch.float32).unsqueeze(0).to(device)
with torch.no_grad():
output = model(input_tensor)
pred_label = torch.argmax(output, dim=1).item()
# 返回结果
return jsonify({
"code": 200,
"pred_label": pred_label,
"msg": "推理成功"
})
except Exception as e:
return jsonify({
"code": 500,
"msg": f"推理失败:{str(e)}"
})
if __name__ == '__main__':
# 监听0.0.0.0(容器内必须监听所有地址),端口8080
app.run(host='0.0.0.0', port=8080, debug=False)
步骤 2:更新 Dockerfile(安装 Flask 依赖)
dockerfile
FROM pytorch/pytorch:2.2.0-cpu
WORKDIR /app
COPY simple_model.py /app/
# 新增:安装Flask
RUN pip install --no-cache-dir flask
CMD ["python", "simple_model.py"]
步骤 3:重新构建并推送镜像
bash
运行
# 重新构建镜像
docker build -t your-username/simple-torch-model:v2 .
# 推送镜像(替换为你的仓库地址)
docker push your-username/simple-torch-model:v2
步骤 4:完整的 Service + Ingress YAML 配置
创建torch-model-full.yaml,包含 Deployment、Service、Ingress:
yaml
# 1. Deployment(运行模型Web服务的Pod)
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-torch-model
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: torch-model
template:
metadata:
labels:
app: torch-model
spec:
containers:
- name: torch-model-container
# 替换为你推送的镜像地址
image: your-username/simple-torch-model:v2
imagePullPolicy: IfNotPresent
# 资源限制
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
# 端口映射:容器内Flask运行在8080端口
ports:
- containerPort: 8080
restartPolicy: Always
---
# 2. Service(ClusterIP类型,暴露Pod的8080端口)
apiVersion: v1
kind: Service
metadata:
name: torch-model-service
namespace: default
spec:
selector:
app: torch-model # 匹配Deployment的Pod标签
type: ClusterIP # 仅集群内访问,由Ingress转发请求
ports:
- port: 80 # Service的端口(Ingress会指向这个端口)
targetPort: 8080 # 容器内的端口(Flask监听的8080)
protocol: TCP
---
# 3. Ingress(外部访问入口,通过域名/IP转发到Service)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: torch-model-ingress
namespace: default
# 注解:指定Ingress控制器(NGINX)的配置
annotations:
# 核心注解:指定使用NGINX Ingress控制器
kubernetes.io/ingress.class: "nginx"
# 可选:设置请求超时
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
spec:
# 规则:域名/路径映射到Service
rules:
- host: torch-model.local # 自定义域名(需本地hosts解析)
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: torch-model-service # 关联上面的Service
port:
number: 80 # Service的端口
# 可选:如果需要HTTPS,添加tls配置(需证书)
# tls:
# - hosts:
# - torch-model.local
# secretName: torch-model-tls-secret
步骤 5:安装 Ingress 控制器(关键!)
如果集群中没有 Ingress 控制器,Ingress 规则不会生效,先安装 NGINX Ingress:
bash
运行
# 适用于K8s 1.24+的NGINX Ingress安装命令(官方推荐)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml
# 验证Ingress控制器是否运行
kubectl get pods -n ingress-nginx
# 看到 "ingress-nginx-controller-xxxx" 状态为Running即可
步骤 6:配置本地域名解析(可选)
为了用torch-model.local访问,需修改本地hosts文件:
- Windows:
C:\Windows\System32\drivers\etc\hosts - Linux/Mac:
/etc/hosts
添加一行:
plaintext
# 替换为你的K8s节点IP(如minikube的IP用minikube ip查看)
192.168.49.2 torch-model.local
步骤 7:部署并验证
1. 部署所有资源
bash
运行
kubectl apply -f torch-model-full.yaml
2. 检查资源状态
bash
运行
# 检查Deployment
kubectl get deployments simple-torch-model
# 检查Service
kubectl get svc torch-model-service
# 检查Ingress
kubectl get ingress torch-model-ingress
# 检查Pod
kubectl get pods -l app=torch-model
3. 测试访问
方式 1:本地 curl 测试
bash
运行
# 发送POST请求到推理接口
curl -X POST http://torch-model.local/predict \
-H "Content-Type: application/json" \
-d '{"data": [0.1]*784}' # 模拟784维的图像数据
方式 2:浏览器 / Postman 测试
访问 http://torch-model.local/predict(POST 方法),请求体:
json
{"data": [0.1, 0.2, 0.3, ..., 0.784]} // 784个数值,可重复填充
预期返回结果:
json
{"code":200,"pred_label":5,"msg":"推理成功"}
关键配置说明
-
Service 的核心作用:
-
ClusterIP类型:仅集群内可见,避免直接暴露 Pod; -
selector:通过标签app: torch-model关联 Pod; -
targetPort:必须和容器内 Flask 监听的端口(8080)一致。
-
-
Ingress 的核心作用:
-
rules:将外部请求(域名 + 路径)转发到指定 Service; -
annotations:指定使用 NGINX 控制器,是 Ingress 生效的关键; -
host:自定义域名,也可留空用 IP 直接访问(如http://<节点IP>/predict)。
-
-
常见问题排查:
- Ingress 状态为
Pending:未安装 Ingress 控制器; - 访问域名超时:检查 hosts 解析、Ingress 规则、Pod 是否正常运行;
- Pod 日志报错:用
kubectl logs <Pod名>查看,大概率是镜像拉取失败或依赖缺失。
- Ingress 状态为
总结
- 对外提供推理服务需先将模型封装为 Web 服务(如 Flask),监听
0.0.0.0:8080; - Service 通过
ClusterIP暴露 Pod 的端口,Ingress 作为外部入口转发请求到 Service; - 核心配置要点:
- Service 的
selector匹配 Pod 标签,targetPort匹配容器端口; - Ingress 的
rules关联 Service,需提前安装 Ingress 控制器; - 镜像必须推送到集群可访问的仓库,否则 Pod 启动失败。
- Service 的
如果需要对外暴露公网访问,可将 Ingress 的host改为公网域名,或使用LoadBalancer类型的 Service(云厂商 K8s 支持)。
-
加监控(Prometheus/Grafana)
为 K8s 中运行的 PyTorch 模型服务添加Prometheus + Grafana 监控,实现对 Pod 资源(CPU / 内存)、模型推理接口指标(QPS / 延迟 / 错误率)的可视化监控。我会分步骤完成配置:先添加指标暴露、再部署 Prometheus/Grafana、最后配置监控面板,全程保持新手友好。
核心思路
- 暴露指标:修改模型代码,用
prometheus_client暴露自定义指标(推理 QPS / 延迟)+ K8s 自带的 Node/Pod 资源指标; - 部署监控组件:用 Prometheus 采集指标,Grafana 可视化;
- 配置监控面板:导入预制面板,实现一键查看所有指标。
步骤 1:改造模型代码,暴露监控指标
更新simple_model.py,添加 Prometheus 指标暴露(Flask 接口指标 + 系统指标):
python
运行
import time
import torch
import torch.nn as nn
from flask import Flask, request, jsonify
# 新增:Prometheus监控依赖
from prometheus_client import Counter, Histogram, Gauge, generate_latest, REGISTRY
from prometheus_client.exposition import make_wsgi_app
from werkzeug.middleware.dispatcher import DispatcherMiddleware
# ====================== 1. 定义Prometheus指标 ======================
# 自定义指标:推理请求总数
PREDICTION_REQUESTS = Counter(
'torch_model_prediction_requests_total',
'Total number of prediction requests',
['method', 'endpoint']
)
# 自定义指标:推理请求延迟(秒)
PREDICTION_LATENCY = Histogram(
'torch_model_prediction_latency_seconds',
'Latency of prediction requests in seconds',
['endpoint']
)
# 自定义指标:推理错误数
PREDICTION_ERRORS = Counter(
'torch_model_prediction_errors_total',
'Total number of prediction errors',
['endpoint', 'error_type']
)
# 系统指标:模型加载状态(1=加载完成,0=未加载)
MODEL_STATUS = Gauge(
'torch_model_loaded_status',
'Status of model loading (1=loaded, 0=not loaded)'
)
# ====================== 2. 定义模型(复用之前的SimpleMLP) ======================
class SimpleMLP(nn.Module):
def __init__(self, input_size=784, hidden_size=128, output_size=10):
super(SimpleMLP, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, output_size)
def forward(self, x):
x = x.view(x.size(0), -1)
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# ====================== 3. 初始化模型 ======================
device = torch.device("cpu")
model = SimpleMLP().to(device)
model.eval()
MODEL_STATUS.set(1) # 标记模型加载完成
# ====================== 4. 启动Flask Web服务 ======================
app = Flask(__name__)
# 新增:将Prometheus的/metrics端点集成到Flask应用
app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {
'/metrics': make_wsgi_app(REGISTRY)
})
@app.route('/predict', methods=['POST'])
def predict():
"""推理接口:带Prometheus指标监控"""
# 记录请求总数
PREDICTION_REQUESTS.labels(method='POST', endpoint='/predict').inc()
# 记录请求延迟
start_time = time.time()
try:
data = request.get_json()['data']
input_tensor = torch.tensor(data, dtype=torch.float32).unsqueeze(0).to(device)
with torch.no_grad():
output = model(input_tensor)
pred_label = torch.argmax(output, dim=1).item()
# 记录延迟
PREDICTION_LATENCY.labels(endpoint='/predict').observe(time.time() - start_time)
return jsonify({
"code": 200,
"pred_label": pred_label,
"msg": "推理成功"
})
except Exception as e:
# 记录错误数
PREDICTION_ERRORS.labels(endpoint='/predict', error_type=type(e).__name__).inc()
# 记录延迟(即使出错)
PREDICTION_LATENCY.labels(endpoint='/predict').observe(time.time() - start_time)
return jsonify({
"code": 500,
"msg": f"推理失败:{str(e)}"
})
if __name__ == '__main__':
# 监听0.0.0.0,端口8080
app.run(host='0.0.0.0', port=8080, debug=False)
步骤 2:更新 Dockerfile(安装 Prometheus 依赖)
dockerfile
FROM pytorch/pytorch:2.2.0-cpu
WORKDIR /app
COPY simple_model.py /app/
# 安装Flask + Prometheus客户端
RUN pip install --no-cache-dir flask prometheus-client
CMD ["python", "simple_model.py"]
步骤 3:重新构建并推送镜像
bash
运行
docker build -t your-username/simple-torch-model:v3 .
docker push your-username/simple-torch-model:v3
步骤 4:更新 Deployment,添加监控端口注解
修改torch-model-full.yaml中的 Deployment 部分,添加Prometheus 采集注解(让 Prometheus 自动发现并采集指标):
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-torch-model
namespace: default
# 新增:Prometheus注解(关键!)
annotations:
prometheus.io/scrape: "true" # 开启采集
prometheus.io/path: "/metrics" # 指标路径
prometheus.io/port: "8080" # 指标端口
spec:
replicas: 1
selector:
matchLabels:
app: torch-model
template:
metadata:
labels:
app: torch-model
# 可选:Pod级别注解(和上面二选一即可)
# annotations:
# prometheus.io/scrape: "true"
# prometheus.io/path: "/metrics"
# prometheus.io/port: "8080"
spec:
containers:
- name: torch-model-container
image: your-username/simple-torch-model:v3 # 改为v3镜像
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
ports:
- containerPort: 8080
restartPolicy: Always
---
# Service和Ingress部分保持不变(略)
步骤 5:部署 Prometheus + Grafana(用 Helm 快速部署)
前置:安装 Helm(K8s 包管理工具)
bash
运行
# Linux/Mac
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Windows(需PowerShell)
choco install kubernetes-helm
1. 添加 Prometheus 社区仓库
bash
运行
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
2. 部署 Prometheus(包含 Node Exporter、kube-state-metrics)
bash
运行
# 创建监控命名空间
kubectl create namespace monitoring
# 部署Prometheus
helm install prometheus prometheus-community/prometheus \
--namespace monitoring \
--set server.service.type=NodePort # 暴露NodePort方便访问(新手友好)
3. 部署 Grafana
bash
运行
# 部署Grafana
helm install grafana prometheus-community/grafana \
--namespace monitoring \
--set service.type=NodePort # 暴露NodePort
4. 查看部署状态
bash
运行
# 查看监控组件Pod
kubectl get pods -n monitoring
# 查看Prometheus和Grafana的NodePort端口
kubectl get svc -n monitoring
# 找到:
# prometheus-server NodePort <IP> 80:30090/TCP → Prometheus端口是30090
# grafana NodePort <IP> 80:32000/TCP → Grafana端口是32000
步骤 6:配置 Prometheus 采集模型指标
1. 访问 Prometheus UI
plaintext
http://<K8s节点IP>:<Prometheus NodePort> # 如 http://192.168.49.2:30090
- 点击「Status」→「Targets」,能看到
default/simple-torch-model的采集目标(状态 UP),说明指标采集成功。 - 可在「Graph」中查询指标,如
torch_model_prediction_requests_total,验证指标是否正常。
2. 配置 Grafana 数据源
- 访问 Grafana UI:
http://<K8s节点IP>:<Grafana NodePort>(如http://192.168.49.2:32000); - 获取 Grafana 初始密码:
bash
运行
kubectl get secret -n monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode - 登录(用户名
admin,密码为上述结果); - 点击「Configuration」→「Data sources」→「Add data source」→选择「Prometheus」;
- 填写 Prometheus 地址:
http://prometheus-server.monitoring.svc.cluster.local:80(K8s 内部 Service 地址); - 点击「Save & test」,提示「Data source is working」即配置成功。
步骤 7:导入 Grafana 监控面板
1. 导入预制面板(推荐)
- 模型接口监控:导入面板 ID
15778(通用 HTTP 服务监控,适配自定义指标); - K8s Pod 资源监控:导入面板 ID
8588(Pod CPU / 内存 / 网络监控)。
导入步骤:
- Grafana 左侧点击「Dashboards」→「+ Import」;
- 输入面板 ID(如 15778)→「Load」;
- 选择已配置的 Prometheus 数据源→「Import」。
2. 自定义模型监控面板(可选)
可手动添加以下指标到面板:
- 推理请求总数:
sum(torch_model_prediction_requests_total) - 推理 QPS:
rate(torch_model_prediction_requests_total[1m]) - 推理平均延迟:
avg(torch_model_prediction_latency_seconds_avg) - 推理错误率:
sum(torch_model_prediction_errors_total) / sum(torch_model_prediction_requests_total) - 模型加载状态:
torch_model_loaded_status - Pod CPU 使用率:
sum(rate(container_cpu_usage_seconds_total{pod=~"simple-torch-model.*"}[1m])) / sum(kube_pod_container_resource_limits_cpu_cores{pod=~"simple-torch-model.*"}) * 100 - Pod 内存使用率:
sum(container_memory_usage_bytes{pod=~"simple-torch-model.*"}) / sum(kube_pod_container_resource_limits_memory_bytes{pod=~"simple-torch-model.*"}) * 100
步骤 8:验证监控效果
- 发送测试请求,触发指标变化:
bash
运行
for i in {1..10}; do curl -X POST http://torch-model.local/predict \ -H "Content-Type: application/json" \ -d '{"data": [0.1]*784}' sleep 1 done - 在 Grafana 面板中,能看到请求数、QPS、延迟等指标实时变化,Pod CPU / 内存也会显示对应波动。
关键配置说明
-
自定义指标设计:
Counter:累计型指标(请求数、错误数),适合统计总数;Histogram:分布型指标(延迟),可计算平均值、分位数;Gauge:瞬时值指标(模型状态),适合监控开关 / 状态。
-
Prometheus 采集注解:
prometheus.io/scrape: "true":开启自动采集;prometheus.io/path:指标暴露路径(默认/metrics);prometheus.io/port:指标端口(需和容器端口一致)。
-
Grafana 数据源:使用 K8s 内部 Service 地址(
prometheus-server.monitoring.svc.cluster.local),避免依赖 NodePort,更稳定。
总结
- 监控核心是暴露指标(代码中添加
prometheus_client)+ 采集指标(Prometheus)+ 可视化指标(Grafana); - 关键步骤:
- 模型代码添加自定义指标,暴露
/metrics端点; - Deployment 添加 Prometheus 注解,实现自动采集;
- 用 Helm 快速部署 Prometheus/Grafana,配置数据源和面板;
- 模型代码添加自定义指标,暴露
- 核心监控维度:接口指标(QPS / 延迟 / 错误率)+ 资源指标(CPU / 内存)+ 业务指标(模型状态)。
如果需要告警(如延迟过高、错误率超标),可在 Prometheus 中配置 AlertManager,Grafana 中添加告警规则,核心逻辑和上述配置兼容。
-
做自动扩缩容 HPA
为 K8s 中的 PyTorch 模型服务配置Horizontal Pod Autoscaler (HPA) 实现自动扩缩容,根据 CPU / 内存使用率或自定义的 Prometheus 指标(如推理 QPS)动态调整 Pod 副本数。我会提供完整的 HPA 配置(基础 CPU / 内存扩缩容 + 自定义指标扩缩容),并说明关键配置和验证步骤。
核心思路
- 基础 HPA:基于 CPU / 内存使用率自动扩缩容(K8s 原生支持);
- 高级 HPA:基于 Prometheus 自定义指标(推理 QPS)扩缩容(需安装 Prometheus Adapter);
- 核心逻辑:HPA 监控指标→达到阈值→自动调整 Deployment 的
replicas数。
前置条件
- 已完成前序步骤(Deployment/Service/Ingress/ 监控部署);
- K8s 集群版本≥1.23(HPA v2 稳定版);
- 已部署 Metrics Server(HPA 依赖,用于采集 Pod 资源指标)。
先安装 Metrics Server(如未安装)
bash
运行
# 安装Metrics Server(适配国内环境,跳过TLS验证)
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/metrics-server/v0.7.0/deploy/components.yaml
# 修改Metrics Server部署,添加--kubelet-insecure-tls(避免证书错误)
kubectl edit deployment metrics-server -n kube-system
# 在spec.template.spec.containers.args中添加:
# - --kubelet-insecure-tls
# 验证Metrics Server运行
kubectl get pods -n kube-system | grep metrics-server
kubectl top pods # 能看到Pod CPU/内存使用,说明安装成功
步骤 1:基础 HPA(基于 CPU / 内存)
创建torch-model-hpa.yaml,配置基于 CPU 使用率的自动扩缩容:
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: simple-torch-model-hpa
namespace: default
spec:
# 关联要扩缩容的Deployment
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: simple-torch-model
# 副本数范围:最小1个,最大5个
minReplicas: 1
maxReplicas: 5
# 扩缩容策略(可选,控制扩缩速度)
behavior:
scaleUp:
stabilizationWindowSeconds: 30 # 扩容前稳定观察30秒(避免抖动)
policies:
- type: Percent
value: 100 # 每次扩容100%(即翻倍)
periodSeconds: 60 # 60秒内最多扩容1次
scaleDown:
stabilizationWindowSeconds: 60 # 缩容前稳定观察60秒
policies:
- type: Percent
value: 50 # 每次缩容50%
periodSeconds: 120 # 120秒内最多缩容1次
# 指标配置(CPU使用率阈值)
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization # 基于使用率(而非绝对数值)
averageUtilization: 50 # 平均CPU使用率超过50%触发扩容
# 可选:添加内存指标
# - type: Resource
# resource:
# name: memory
# target:
# type: Utilization
# averageUtilization: 80
部署基础 HPA
bash
运行
kubectl apply -f torch-model-hpa.yaml
# 查看HPA状态
kubectl get hpa simple-torch-model-hpa
# 输出示例:
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# simple-torch-model-hpa Deployment/simple-torch-model 0%/50% 1 5 1 10s
步骤 2:高级 HPA(基于 Prometheus 自定义指标)
如果想基于推理 QPS(而非 CPU)扩缩容,需安装Prometheus Adapter(将 Prometheus 指标转换为 K8s 自定义指标)。
1. 安装 Prometheus Adapter
bash
运行
# 添加仓库并更新
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 部署Prometheus Adapter到monitoring命名空间
helm install prometheus-adapter prometheus-community/prometheus-adapter \
--namespace monitoring \
--set prometheus.url=http://prometheus-server.monitoring.svc.cluster.local \
--set prometheus.port=80
2. 配置 Prometheus Adapter 识别自定义指标
创建adapter-config.yaml,定义 QPS 指标转换规则:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-adapter-config
namespace: monitoring
data:
config.yaml: |
rules:
- seriesQuery: 'torch_model_prediction_requests_total{endpoint=~"/predict",namespace!=""}'
resources:
overrides:
namespace: {resource: "namespace"}
pod: {resource: "pod"}
name:
matches: "^(.*)_total"
as: "${1}_qps"
metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
---
# 更新Prometheus Adapter使用自定义配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus-adapter
namespace: monitoring
spec:
template:
spec:
containers:
- name: prometheus-adapter
args:
- --metrics-relist-interval=1m
- --config=/etc/adapter/config.yaml
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
volumeMounts:
- name: config-volume
mountPath: /etc/adapter
volumes:
- name: config-volume
configMap:
name: prometheus-adapter-config
3. 应用配置并验证
bash
运行
# 应用配置
kubectl apply -f adapter-config.yaml
# 重启Prometheus Adapter使配置生效
kubectl rollout restart deployment prometheus-adapter -n monitoring
# 验证自定义指标是否被识别
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/torch_model_prediction_requests_qps" | jq .
# 能看到指标数值,说明配置成功
4. 创建基于 QPS 的 HPA
更新torch-model-hpa.yaml,替换为自定义指标配置:
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: simple-torch-model-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: simple-torch-model
minReplicas: 1
maxReplicas: 5
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 100
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 50
periodSeconds: 120
# 基于Prometheus自定义指标(QPS)
metrics:
- type: Pods
pods:
metric:
name: torch_model_prediction_requests_qps # 自定义QPS指标
target:
type: AverageValue
averageValue: 10 # 平均每个Pod QPS超过10触发扩容
# 可选:保留CPU作为兜底指标
# - type: Resource
# resource:
# name: cpu
# target:
# type: Utilization
# averageUtilization: 80
5. 部署并验证自定义指标 HPA
bash
运行
kubectl apply -f torch-model-hpa.yaml
# 查看HPA状态(TARGETS列会显示QPS数值)
kubectl get hpa simple-torch-model-hpa
# 输出示例:
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# simple-torch-model-hpa Deployment/simple-torch-model 0/10 1 5 1 20s
步骤 3:测试自动扩缩容
1. 模拟高 QPS 压力(触发扩容)
bash
运行
# 循环发送请求,模拟QPS>10
while true; do
curl -X POST http://torch-model.local/predict \
-H "Content-Type: application/json" \
-d '{"data": [0.1]*784}' > /dev/null 2>&1
sleep 0.05 # 每秒20个请求,超过阈值10
done
2. 观察 HPA 和 Pod 变化
bash
运行
# 实时查看HPA状态
watch kubectl get hpa simple-torch-model-hpa
# 实时查看Pod数量
watch kubectl get pods -l app=torch-model
- 约 30 秒后,HPA 的 TARGETS 会显示 QPS 超过 10,REPLICAS 会从 1→2→4(按 100% 扩容策略);
- 停止压力测试后,约 60 秒 HPA 会触发缩容,Pod 数逐步减少到 1。
关键配置说明
-
HPA 核心参数:
minReplicas/maxReplicas:控制 Pod 数量范围,避免无限扩容 / 缩容;behavior:stabilizationWindowSeconds避免短时间指标波动导致的 “抖动扩缩容”;metrics:Resource:基于 CPU / 内存(原生支持,简单易配);Pods:基于自定义 Pod 指标(需 Prometheus Adapter)。
-
Prometheus Adapter 关键:
seriesQuery:匹配 Prometheus 中的原始指标(torch_model_prediction_requests_total);metricsQuery:计算 QPS(rate(指标[2m])),按 Pod / 命名空间分组;- 需确保指标标签包含
namespace/pod,否则无法关联到 K8s 资源。
-
扩缩容策略调优:
- 扩容策略:
scaleUp的periodSeconds不宜过小(避免频繁扩容); - 缩容策略:
scaleDown的stabilizationWindowSeconds建议比扩容大(避免缩容过快导致服务不可用)。
- 扩容策略:
总结
- 基础 HPA 基于 CPU / 内存使用率,配置简单(仅需 Metrics Server),适合通用场景;
- 高级 HPA 基于 Prometheus 自定义指标(如 QPS),需安装 Prometheus Adapter,更贴合业务场景;
- 核心配置要点:
- 基础 HPA:
scaleTargetRef关联 Deployment,metrics设置 CPU / 内存阈值; - 自定义指标 HPA:通过 Prometheus Adapter 将 Prometheus 指标转换为 K8s 自定义指标,HPA 引用该指标;
behavior配置可避免扩缩容抖动,提升稳定性。
- 基础 HPA:
如果需要更精细的控制(如基于延迟扩缩容),只需修改 Prometheus Adapter 的指标规则,将 QPS 替换为延迟指标(torch_model_prediction_latency_seconds)即可,核心配置逻辑一致。
做完这个,你就能面:云原生 / 云原生 AI/K8s 架构师。
更多推荐



所有评论(0)