【infra之路】模块三:Kubernetes (上) — 概念、集群搭建、Pod 与 Deployment

AI Infra 学习路线 · 阶段一 · 模块三(上半部分)

目标:理解声明式 → 搭本地集群 → 掌握 Pod/Deployment/自愈/扩缩容

环境:Windows + WSL2 (Ubuntu 24.04) + Docker Desktop + minikube v1.38.1 + NVIDIA RTX 5060 Ti (8G)

下半部分(GPU 接入 + PyTorch 训练 = 阶段一毕业项目)见后续笔记


0. 核心心智模型:声明式 (最重要)

  • 命令式 (Docker 时代):你下一条条指令------"跑这个容器""停那个""删掉它"。机器只管执行,出状况(容器崩了)它不管。
  • 声明式 (Kubernetes) :你描述「想要的最终状态」------"我要 3 个这样的容器一直运行着"。K8s 自己负责让现实变成那样,并持续维持:容器挂了自动拉起,机器宕了把任务挪走。

类比:命令式 = 手动开关每盏灯;声明式 = 设定"这房间要一直保持明亮",系统自己换坏掉的灯泡。

一句话:你描述想要什么,K8s 负责实现并持续维持。后面每个对象都是在帮你"描述想要什么"。

为什么 AI Infra 必须用它:成百上千个容器(训练任务、推理服务)跑在几十上百台机器上,手动 docker run 不可能。你只需声明"这个推理服务要 10 个副本、每个 1 张 GPU",K8s 负责调度到哪台机器、哪张卡、挂了怎么重启。它是「集群的操作系统」。


1. 核心概念

对象 作用
Pod 最小调度单位。装一个(或几个紧密关联的)容器。K8s 管 Pod 而非直接管容器。可粗略理解为"K8s 世界里的一个容器"。
Deployment 管理一组相同的 Pod。声明"我要 N 个副本",它负责维持:挂一个补一个,升级时滚动替换。
Service 给一组 Pod 提供稳定访问入口。Pod 会重建、IP 会变,Service 给它们固定的名字和地址。
Namespace 把资源分组隔离,像文件夹。不同项目/团队放不同 namespace。
kubectl 和 K8s 对话的命令行工具。所有操作通过它:get/apply/describe/logs/exec。

集群组件(K8s 的"大脑",排查问题会反复见到):

  • apiserver:所有操作的唯一入口,kubectl 命令都发给它。
  • kubelet:节点上负责真正把容器跑起来的代理。
  • control-plane:控制平面,负责调度决策。真实集群里和工作节点分开;minikube 单节点身兼两职。

2. 安装 minikube + kubectl

bash 复制代码
# kubectl (阿里云源,把版本号写进去)
curl -LO https://kubernetes.oss-cn-hangzhou.aliyuncs.com/kubernetes-release/release/v1.32.0/bin/linux/amd64/kubectl
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client

# minikube (阿里云源,带明确版本号,不要用 latest 路径)
curl -LO https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.38.1/minikube-linux-amd64
# 下完先验证文件!!!
ls -lh minikube-linux-amd64   # 应是 ~100MB,不是几百字节
file minikube-linux-amd64     # 应是 ELF 64-bit executable,不是 XML/HTML
sudo install minikube-linux-amd64 /usr/local/bin/minikube
minikube version

好习惯 :下载任何二进制后,先 ls -lh 看大小、file 看类型,确认无误再装。


3. 启动集群(Docker 驱动)

bash 复制代码
# 选了 Docker 驱动:最省心,复用现有 Docker Desktop,GPU 也走得通
# 确保 Docker Desktop 正在运行(minikube 用 Docker 驱动靠它)
minikube start --driver=docker --base-image="gcr.io/k8s-minikube/kicbase:v0.0.50"

成功标志:Done! kubectl is now configured to use "minikube" cluster

验证集群:

bash 复制代码
kubectl get nodes      # 节点 minikube,STATUS=Ready
kubectl cluster-info   # control plane 信息
minikube status        # host/kubelet/apiserver 都 Running

4. 第一个 Pod(声明式实操)

first-pod.yaml(YAML 对缩进敏感:用空格,每级 2 个,不要 Tab):

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: my-first-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: IfNotPresent   # 本地有就用本地,不强制远程拉
    ports:
    - containerPort: 80
bash 复制代码
kubectl apply -f first-pod.yaml    # 提交声明
kubectl get pods                   # 看状态
kubectl get pods -w                # 实时盯状态变化,Ctrl+C 退出
kubectl describe pod my-first-pod  # 详情,重点看底部 Events(排查第一去处)
kubectl logs my-first-pod          # 容器日志
kubectl exec -it my-first-pod -- bash   # 钻进容器(类比 docker exec)

关键实验:裸 Pod 删了不会自愈

bash 复制代码
kubectl delete pod my-first-pod
kubectl get pods          # No resources found ------ 没人管它,删了就没了

裸 Pod(直接 kind: Pod)没有管理者。要自愈,需要更高层对象 = Deployment。


5. Deployment(自愈 + 扩缩容)

first-deployment.yaml:

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3                  # 关键:声明要 3 个副本一直在
  selector:
    matchLabels:
      app: nginx               # 管理哪些 Pod(靠标签匹配)
  template:                    # 每个 Pod 的模板
    metadata:
      labels:
        app: nginx             # 给 Pod 打标签(和上面 selector 对应)
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
bash 复制代码
kubectl apply -f first-deployment.yaml
kubectl get pods            # 3 个 Pod: nginx-deployment-xxxx-yyyy
kubectl get deployment      # READY 3/3
kubectl get pods -o wide    # 含每个 Pod 的 IP、所在节点

关键实验:Deployment 管的 Pod 删了会自愈

bash 复制代码
kubectl delete pod <某个pod名>
kubectl get pods            # 总数仍是 3!被删的消失,立刻冒出一个 AGE=几秒 的新 Pod 补位

对比裸 Pod:同样删 Pod,裸 Pod 直接没了,Deployment 立刻补回。差别 = 有没有管理者持续维持声明的状态。

声明式扩缩容(改声明,不用删了重建):

bash 复制代码
kubectl scale deployment nginx-deployment --replicas=5   # 声明要 5 个 → 立刻变 5
kubectl scale deployment nginx-deployment --replicas=2   # 声明要 2 个 → 多的被回收

清理:

bash 复制代码
kubectl delete deployment nginx-deployment   # 删 deployment,它管的 pod 一起清理

6. 踩坑记录(国内环境 minikube 必遇)

坑 1:阿里云 latest 路径下到错误页

curl .../minikube/releases/latest/... 只下到 412 字节,file 显示是 XML。

  • 原因:latest 路径在阿里云源不可靠,返回了错误提示页。
  • 解决:用带明确版本号的路径 .../releases/v1.38.1/...。下完务必 ls -lh + file 验证。

坑 2:minikube start 拉 kicbase 极慢 (40 B/s)

日志:cannot pull kicbase image from any docker registry, and is trying to download ... from github release page via HTTP,速度 40 B/s。

  • 原因:kicbase(1.28G 基础镜像)从镜像仓库拉失败,回退到 GitHub HTTP 下载,GitHub 在国内极慢。
  • 解决:换网 + 下面的手动拉镜像办法。

坑 3:kicbase 镜像 sha256 指纹对不上 (not found)

日志:failed to resolve reference ... @sha256:eb4fec...: not found

  • 原因:minikube 1.38.1 写死要找指纹 eb4fec...,但阿里云那份 kicbase 实际指纹是 39500e5a...,按指纹精确匹配失败。

  • 解决(手动拉 + 绕过指纹):

    bash 复制代码
    minikube delete
    docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kicbase:v0.0.50  # 按标签拉,不带@sha256
    docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kicbase:v0.0.50 gcr.io/k8s-minikube/kicbase:v0.0.50
    minikube start --driver=docker --base-image="gcr.io/k8s-minikube/kicbase:v0.0.50"  # 用本地镜像,跳过指纹

坑 4:Pod 卡在 ImagePullBackOff / ErrImagePull

kubectl describe pod 的 Events:Failed to pull image "nginx:latest" ... registry-1.docker.io ... EOF

  • 原因:minikube 集群是独立环境,有自己的镜像存储,不走宿主机 Docker 配的加速源,默认直连 Docker Hub 拉失败。

  • 关键概念:ImagePullBackOff = 拉不到镜像后 K8s 退避等待(越等越久再试);ErrImagePull = 拉取失败。这是 K8s 最高频错误之一。

  • 解决(本地拉 + load 进集群):

    bash 复制代码
    docker pull nginx:latest                # 用本地 Docker(已配加速源)拉
    minikube image load nginx:latest        # 把镜像塞进 minikube 集群(桥梁!)
    minikube image ls | grep nginx          # 确认集群里有了
    # YAML 里加 imagePullPolicy: IfNotPresent,告诉 K8s 用本地的别去远程拉
  • 备选:用阿里云的 Docker Hub 镜像副本,路径形如 registry.cn-hangzhou.aliyuncs.com/library/nginx:1.21(library 命名空间 = Docker Hub 官方镜像)。


7. 关键认知沉淀

  1. 命令式 vs 声明式是 K8s 的世界观,比记任何 yaml 字段都重要。
  2. minikube 集群 ≠ 宿主机 Docker :两个独立的镜像环境,minikube image load 是桥梁。以后自己构建的训练/推理镜像也要这样塞进集群。
  3. 自愈的本质:你声明期望状态,K8s 持续让现实 = 声明。扩缩容、崩溃重启、故障转移都是这一个原理的放大。
  4. 排 Pod 问题第一步 :kubectl describe pod <name> 看 Events。

已掌握能力清单

  • 理解命令式 vs 声明式
  • 安装 kubectl + minikube,国内环境绕过 kicbase 下载/指纹坑
  • 启动并验证本地集群
  • 写 Pod YAML,apply/get/describe/logs/exec
  • 理解并复现 ImagePullBackOff,用 image load + imagePullPolicy 解决
  • 写 Deployment YAML,理解 replicas/selector/template/labels
  • 亲手验证自愈(删 Pod 自动补回)
  • 声明式扩缩容 kubectl scale

相关推荐
IT策士1 小时前
第 23篇 k8s之Pod:多容器 Pod 与设计模式(Sidecar 等)
设计模式·容器·kubernetes
专业白嫖怪9 小时前
什么是docker
运维·docker·容器
Plastic garden14 小时前
Docker(1)
运维·docker·容器
gs8014015 小时前
网络隐形杀手:从 Could not connect to SMTP host 报错深度剖析 Docker MTU 黑洞理论与实战
网络·docker·容器
程序猿阿伟16 小时前
《一套完整方法论:搞定图形应用的Docker镜像优化》
数据库·docker·容器
java_logo17 小时前
2026 Docker 国内镜像加速配置教程
运维·docker·容器·docker镜像·docker镜像源·docker镜像加速·docker镜像国内库
IT策士17 小时前
Docker从0到1再到 Kubernetes 实战:第15篇Compose 中的服务依赖、健康检查与启动顺序
docker·容器·kubernetes
Waay18 小时前
K8s Deployment 滚动更新与回滚深度详解(含踩坑实录+生产选型原理)
云原生·容器·kubernetes
顾默@18 小时前
双系统Ubuntu18.04升级22.04,安装docker进行openclaw安装
运维·docker·容器