Kubernetes 从入门到实践

50 阅读30分钟

Kubernetes 从入门到实践

目录


1. Kubernetes 基础

1.1 Kubernetes 架构

Kubernetes(K8s)采用 Master-Worker 架构,将集群分为控制平面和数据平面。

Master 节点(控制平面)

Master 节点也是一台服务器(物理机或虚拟机),但它不运行业务容器,而是专门负责集群的管理和调度决策。可以理解为"指挥中心"——它决定哪个 Pod 跑在哪台 Worker 上、监控集群健康状态、处理所有 API 请求。生产环境通常部署 3 个 Master 实现高可用。

核心组件:

组件职责
kube-apiserver集群的统一入口,所有操作都通过 REST API 与它交互
kube-scheduler监听未调度的 Pod,根据资源需求、亲和性等策略将 Pod 分配到合适的 Worker 节点
kube-controller-manager运行各种控制器(Deployment、ReplicaSet、Node 控制器等),确保集群实际状态与期望状态一致
etcd分布式键值存储,保存集群所有配置数据和状态信息,是集群的"数据库"

请求链路kubectlkube-apiserver → 写入 etcdkube-scheduler 调度 → kubelet 执行

Worker 节点(数据平面)

Worker 节点可以理解为一台服务器(物理机或虚拟机)。每个 Worker 节点就是集群中的一台机器,上面运行着实际的应用容器。一个集群通常由多个 Worker 节点组成,K8s 负责将 Pod 调度到这些"服务器"上运行。

一个 Worker 上可以运行多个 Pod。 Pod 是 K8s 最小的调度单位,每个 Pod 里包含一个或多个容器(通常是一个)。可以简单理解为:

  • Pod ≈ Docker Container 的包装层:大多数情况下 1 个 Pod = 1 个容器,但 Pod 提供了共享网络和存储的能力,允许多个紧密耦合的容器在同一个 Pod 内协作(如 sidecar 模式)。
  • Pod 有自己的 IP 地址,Pod 内的容器共享该 IP 和端口空间。

核心组件:

组件职责
kubelet每个 Worker 节点上的代理,负责管理 Pod 生命周期,向 apiserver 汇报节点状态
kube-proxy每个节点上的网络代理。当外部请求访问 Service 时,kube-proxy 负责将流量合理转发到后端的某个 Pod 上(负载均衡)。它通过维护 iptables/ipvs 规则实现这一点
Container Runtime容器运行时(如 containerd、CRI-O),负责拉取镜像、启动/停止容器

类比:Worker 节点 = 一台服务器,Pod = 服务器上运行的一个进程/应用,kube-proxy = 这台服务器上的"负载均衡器/路由器"

架构图

graph TB
    subgraph Master["Master Node(控制平面)"]
        API[kube-apiserver]
        SCH[kube-scheduler]
        CM[kube-controller-manager]
        ETCD[(etcd)]
        API --- SCH
        API --- CM
        API --- ETCD
    end

    subgraph Worker1["Worker Node 1"]
        K1[kubelet]
        KP1[kube-proxy]
        CR1[Container Runtime]
        P1A[Pod A]
        P1B[Pod B]
        K1 --- CR1
        CR1 --- P1A
        CR1 --- P1B
    end

    subgraph Worker2["Worker Node 2"]
        K2[kubelet]
        KP2[kube-proxy]
        CR2[Container Runtime]
        P2A[Pod C]
        P2B[Pod D]
        K2 --- CR2
        CR2 --- P2A
        CR2 --- P2B
    end

    subgraph Worker3["Worker Node N"]
        K3[kubelet]
        KP3[kube-proxy]
        CR3[Container Runtime]
        P3A[Pod E]
        P3B[Pod F]
        K3 --- CR3
        CR3 --- P3A
        CR3 --- P3B
    end

    API -->|调度指令| K1
    API -->|调度指令| K2
    API -->|调度指令| K3
    KP1 -.->|网络规则| P1A
    KP1 -.->|网络规则| P1B
    KP2 -.->|网络规则| P2A
    KP2 -.->|网络规则| P2B
    KP3 -.->|网络规则| P3A
    KP3 -.->|网络规则| P3B

1.2 集群搭建

常见搭建方式对比

方式适用场景特点
KindCI/CD、本地测试用 Docker 容器模拟 K8s 节点,启动快
kubeadm生产/准生产环境官方工具,支持多节点集群搭建
云服务生产环境EKS(AWS)、AKS(Azure)、GKE(Google)、ACK(阿里云),免运维

Kind 用 Docker 容器模拟节点(所有节点跑在一台机器上),真实环境中每个 Worker 是独立的物理机/虚拟机。

对比项Kind(本地模拟)生产环境(真实集群)
节点本质一个 Docker 容器 = 一个节点一台物理机/云虚拟机 = 一个节点
运行位置全部跑在你一台电脑上每台机器独立运行
搭建工具kind create clusterkubeadm、云服务(EKS/AKS/GKE/ACK)
用途学习、开发、测试生产部署

生产环境搭建(kubeadm)

假设有 3 台服务器:Master(192.168.1.10)、Worker1(192.168.1.11)、Worker2(192.168.1.12)。

① 每台机器安装基础组件

# 每台服务器都需要安装:Docker(或 containerd)、kubelet、kubeadm、kubectl
# 以 Ubuntu 为例
apt-get update && apt-get install -y kubelet kubeadm kubectl docker.io

② Master 上初始化集群

# 在 Master(192.168.1.10)上执行
kubeadm init --apiserver-advertise-address=192.168.1.10 --pod-network-cidr=10.244.0.0/16

# 初始化成功后会输出一条 join 命令,类似:
# kubeadm join 192.168.1.10:6443 --token abcdef.1234567890 \
#     --discovery-token-ca-cert-hash sha256:xxxxxxxx

# 配置 kubectl
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config

③ Worker 物理机加入集群

# 在 Worker1(192.168.1.11)上执行 Master 输出的 join 命令
kubeadm join 192.168.1.10:6443 --token abcdef.1234567890 \
    --discovery-token-ca-cert-hash sha256:xxxxxxxx

# 在 Worker2(192.168.1.12)上同样执行
kubeadm join 192.168.1.10:6443 --token abcdef.1234567890 \
    --discovery-token-ca-cert-hash sha256:xxxxxxxx

④ 回到 Master 查看节点

kubectl get nodes
# NAME       STATUS   ROLES           AGE
# master     Ready    control-plane   10m   ← 192.168.1.10
# worker1    Ready    <none>          5m    ← 192.168.1.11(独立物理机)
# worker2    Ready    <none>          5m    ← 192.168.1.12(独立物理机)

云服务托管集群

云平台(阿里云 ACK、AWS EKS、Azure AKS 等)方式更简单:

  1. 在云控制台创建集群,选择 ECS/EC2 实例作为 Worker 节点
  2. 云平台自动完成 Master 搭建和 Worker 加入
  3. 下载 kubeconfig 文件,本地 kubectl 即可操作

Master 节点由云平台托管(免运维),你只需管理 Worker 节点和上面的应用。

在 WSL 环境搭建(Kind)

--name vs control-plane 的区别

  • --name my-cluster集群的名字,给整个集群起个名,方便管理多个集群时区分
  • control-plane节点的角色,表示这个节点充当 Master(管理节点)

集群名是标识,节点角色决定职责,两者不是一个层级的概念。

# 安装 Kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
sudo install kind /usr/local/bin/kind
rm kind

# 创建集群(--name 是集群名称,默认只创建 1 个 control-plane 节点)
kind create cluster --name my-cluster

# 查看集群名列表
kind get clusters
# 输出:my-cluster

# 查看节点及角色
kubectl get nodes
# NAME                       STATUS   ROLES           AGE
# my-cluster-control-plane   Ready    control-plane   5m   ← Master 节点
# (默认不带配置文件只有 1 个 Master,无 Worker)

# 创建多节点集群(使用配置文件)
# cluster = 整个集群(Master + Worker 的集合)
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane    # Master 节点(管理调度)
- role: worker           # Worker 节点 1(跑业务 Pod)
- role: worker           # Worker 节点 2(跑业务 Pod)
EOF

# 查看多节点集群的节点
kubectl get nodes
# NAME                       STATUS   ROLES           AGE
# my-cluster-control-plane   Ready    control-plane   5m   ← Master
# my-cluster-worker          Ready    <none>          5m   ← Worker 1
# my-cluster-worker2         Ready    <none>          5m   ← Worker 2

# 删除集群
kind delete cluster --name my-cluster

Kind 在 WSL2 中常见问题

创建集群时报错 could not find a log line that matches "Reached target .*Multi-User System.*|detected cgroup v1",通常是 cgroup 配置不兼容导致。

解决方法:在 Windows 下创建/编辑 C:\Users\<你的用户名>\.wslconfig

[wsl2]
memory=4GB
processors=2
kernelCommandLine=systemd.unified_cgroup_hierarchy=1

然后在 Windows PowerShell 中重启 WSL:

wsl --shutdown

重新进入 WSL 后再创建集群即可。


1.3 kubectl 命令

安装和配置

kubeconfig 文件默认位于 ~/.kube/config,包含集群地址、认证信息和上下文。

命令说明
kubectl config view查看 kubectl 配置
kubectl config current-context查看当前上下文(当前连接的集群)
kubectl config use-context <context-name>切换上下文
kubectl config get-contexts查看所有上下文
kubectl config set-context --current --namespace=<ns>设置默认命名空间

常用命令

资源查看
命令说明
kubectl get namespaces查看所有命名空间
kubectl get nodes查看节点
kubectl get nodes -o wide查看节点详细信息(IP、OS 等)
kubectl get pods查看当前命名空间的 Pod
kubectl get pods -n <namespace>查看指定命名空间的 Pod
kubectl get pods -A查看所有命名空间的 Pod
kubectl get pods -o wide显示 Pod 详细信息(节点、IP)
kubectl get pods -w实时监听 Pod 变化
kubectl get svc查看 Service
kubectl get deploy查看 Deployment
kubectl get configmap查看 ConfigMap
kubectl get ingress查看 Ingress
kubectl get all -n <namespace>查看指定命名空间所有资源
kubectl describe pod <pod-name>查看 Pod 详情
kubectl describe node <node-name>查看 Node 详情
kubectl describe svc <service-name>查看 Service 详情
资源创建与管理
命令说明
kubectl apply -f deployment.yaml通过 YAML 创建/更新资源
kubectl apply -f ./manifests/应用目录下所有 YAML
kubectl delete -f deployment.yaml删除 YAML 中定义的资源
kubectl delete pod <pod-name>删除指定 Pod
kubectl delete deploy <deploy-name>删除指定 Deployment
kubectl create deployment nginx --image=nginx:latest快速创建 Deployment(不推荐生产使用)
kubectl expose deployment nginx --port=80 --type=NodePort暴露 Deployment 为 Service
扩缩容
命令说明
kubectl scale deployment <name> --replicas=3手动扩缩容
kubectl get hpa查看 HPA(自动扩缩容)

查看日志

命令说明
kubectl logs <pod-name>查看 Pod 日志
kubectl logs -f <pod-name>实时跟踪日志(类似 tail -f
kubectl logs --tail=100 <pod-name>查看最近 100 行
kubectl logs --since=1h <pod-name>查看最近 1 小时的日志
kubectl logs <pod-name> -c <container-name>多容器 Pod 指定容器查看日志
kubectl logs <pod-name> --previous查看上一个已终止容器的日志(排查 CrashLoopBackOff)

进入容器

命令说明
kubectl exec -it <pod-name> -- /bin/bash进入容器的 bash
kubectl exec -it <pod-name> -- /bin/sh进入容器的 sh(无 bash 时使用)
kubectl exec -it <pod-name> -c <container-name> -- /bin/bash多容器 Pod 指定容器进入
kubectl exec <pod-name> -- cat /etc/nginx/nginx.conf执行单条命令(不进入交互模式)
kubectl exec <pod-name> -- env查看环境变量
kubectl exec <pod-name> -- ls /app查看目录
kubectl cp <pod-name>:/path/file ./local-file从容器复制文件到本地
kubectl cp ./local-file <pod-name>:/path/file从本地复制文件到容器

常用排障命令速查

Pod 异常排查流程

步骤命令说明
1kubectl get pods查看 Pod 状态
2kubectl describe pod <pod-name>查看事件和详情
3kubectl logs <pod-name>查看日志
4kubectl logs <pod-name> --previous查看上次崩溃日志
5kubectl exec -it <pod-name> -- /bin/sh进入容器排查

其他排障命令

命令说明
kubectl top nodes查看节点资源使用(需 metrics-server)
kubectl top pods查看 Pod 资源使用(需 metrics-server)
kubectl port-forward pod/<pod-name> 8080:80端口转发 Pod(本地调试)
kubectl port-forward svc/<svc-name> 8080:80端口转发 Service(本地调试)

2. 核心对象

2.1 Pod

2.1.1 Pod 概念和作用

Pod 是 Kubernetes 中最小的可部署单元。一个 Pod 封装了一个或多个容器(通常是一个),它们共享:

  • 网络:同一个 Pod 内的容器共享 IP 地址和端口空间,可通过 localhost 互相通信
  • 存储:可以挂载相同的 Volume,实现数据共享
  • 生命周期:Pod 内的容器一起启动、一起销毁

为什么不直接用容器? Pod 提供了容器之上的抽象层,支持多容器协作(sidecar 模式)、共享网络/存储、统一调度等能力。

2.1.2 Pod 创建和管理

通过 YAML 创建 Pod
# nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod           # Pod 名称
  labels:
    app: nginx               # 标签,用于 Service 选择
spec:
  containers:
  - name: nginx              # 容器名称
    image: nginx:1.25        # 镜像
    ports:
    - containerPort: 80      # 容器暴露的端口
操作命令
创建 Podkubectl apply -f nginx-pod.yaml
查看 Podkubectl get pods
查看详情kubectl describe pod nginx-pod
删除 Podkubectl delete pod nginx-pod
删除(通过文件)kubectl delete -f nginx-pod.yaml

⚠️ 生产环境中不要直接创建 Pod,应使用 Deployment 来管理,这样才有副本管理、滚动更新等能力。

2.1.3 Pod 生命周期

Pod 从创建到销毁经历以下阶段:

阶段说明
PendingPod 已被创建,但容器还未启动(可能在拉取镜像或等待调度)
RunningPod 已绑定到节点,所有容器已启动
Succeeded所有容器正常执行完毕并退出(常见于 Job)
Failed至少一个容器以非零状态退出
Unknown无法获取 Pod 状态(通常是与节点通信失败)

常见异常状态

状态原因排查方式
CrashLoopBackOff容器反复崩溃重启kubectl logs <pod> --previous
ImagePullBackOff镜像拉取失败检查镜像名、tag、仓库权限
Pending无可用节点或资源不足kubectl describe pod <pod> 查看 Events
OOMKilled内存超出限制调整 resources.limits.memory

2.1.4 多容器 Pod

一个 Pod 可以包含多个容器,常见模式:

模式说明示例
Sidecar辅助容器增强主容器功能日志收集器、代理
Ambassador代理容器处理外部通信数据库连接代理
Adapter转换容器输出格式日志格式转换
# 多容器 Pod 示例(Sidecar 模式)
apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: app                    # 主容器:业务应用
    image: my-app:1.0
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/app
  - name: log-collector          # Sidecar:日志收集
    image: fluentd:latest
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/app
  volumes:
  - name: shared-logs            # 共享 Volume(见下方说明)
    emptyDir: {}

Volume 说明

  • shared-logs → Volume 的名称(自己定义的,用来在容器中引用)
  • emptyDir → Volume 的类型(决定数据存在哪里、生命周期多长)

emptyDir 类型会在 Worker 节点的磁盘上创建一个临时目录,不是在 Pod 内部

特性说明
存储位置Worker 节点的文件系统上(如 /var/lib/kubelet/pods/<pod-id>/volumes/
生命周期与 Pod 相同,Pod 删除时目录也会被清除
容器重启Pod 内容器重启时数据不会丢失(因为 Volume 在节点上,不在容器内)
用途同一 Pod 内多个容器之间共享数据(如上例中主容器写日志,Sidecar 读日志)

其他 Volume 类型对比:

类型存储位置生命周期
emptyDirWorker 节点磁盘随 Pod 销毁
hostPathWorker 节点指定路径独立于 Pod,节点存在就在。⚠️ Pod 调度到其他节点时无法访问原数据
persistentVolumeClaim外部存储(云盘、NFS 等)独立于 Pod 和节点

2.1.5 Init 容器

Init 容器在主容器启动之前运行,用于初始化工作。特点:

  • 按顺序逐个执行,前一个成功后才启动下一个
  • 全部成功后,主容器才会启动
  • 失败则 Pod 重启(遵循 restartPolicy)

常见用途:等待依赖服务就绪、初始化配置文件、数据库迁移

apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
  - name: wait-for-db           # 等待数据库就绪
    image: busybox:1.36
    command: ['sh', '-c', 'until nc -z mysql-service 3306; do echo waiting for db; sleep 2; done']
  - name: init-config           # 初始化配置
    image: busybox:1.36
    command: ['sh', '-c', 'cp /config-template/* /app/config/']
    volumeMounts:
    - name: config
      mountPath: /app/config
  containers:
  - name: app                   # 主容器(Init 全部成功后才启动)
    image: my-app:1.0
    volumeMounts:
    - name: config
      mountPath: /app/config
  volumes:
  - name: config
    emptyDir: {}

2.2 Deployment

2.2.1 概念和作用

Deployment 是管理 Pod 的高层控制器,提供:

  • 副本管理:确保指定数量的 Pod 始终运行
  • 滚动更新:无停机更新应用版本
  • 回滚:一键回退到之前的版本
  • 自愈:Pod 崩溃后自动重建

层级关系:Deployment → ReplicaSet → Pod。Deployment 管理 ReplicaSet,ReplicaSet 管理 Pod。

运行位置:Deployment 本身是一份"期望状态"声明,存储在 Master 的 etcd 中,由 kube-controller-manager 管理。真正跑在 Worker 上的是 Deployment 创建出来的 Pod

例如:Deployment 告诉 Master:"我要 3 个 nginx Pod",Master 的 Scheduler 负责把这 3 个 Pod 分配到不同的 Worker 上运行。

ReplicaSet(副本集)

ReplicaSet 代表一组 Pod 副本。它会创建指定数量的相同 Pod,并始终保持该数量不变——如果有 Pod 被删除或崩溃,ReplicaSet 会自动补建,确保可用性。

通常不直接使用 ReplicaSet,而是通过 Deployment 间接管理它。Deployment 每次更新镜像版本时,会创建一个新的 ReplicaSet(逐步扩容),同时缩容旧的 ReplicaSet,实现滚动更新。

# 查看 Deployment 创建的 ReplicaSet
kubectl get rs
# NAME                          DESIRED   CURRENT   READY   AGE
# nginx-deployment-569f95f5cb   3         3         3       10m
#                    ^^^^^^^^^^
#                    ReplicaSet 名 = Deployment 名 + Pod 模板 hash

# 查看 ReplicaSet 管理的 Pod
kubectl get pods -l app=nginx
# NAME                                READY   STATUS    AGE
# nginx-deployment-569f95f5cb-mrnm4   1/1     Running   10m   ← 由 ReplicaSet 创建
# nginx-deployment-569f95f5cb-n2j8s   1/1     Running   10m
# nginx-deployment-569f95f5cb-x8xl4   1/1     Running   10m

关系图:

Deployment(nginx-deployment)
  └── ReplicaSet(nginx-deployment-569f95f5cb)  ← 当前版本
        ├── Pod(nginx-deployment-569f95f5cb-mrnm4)
        ├── Pod(nginx-deployment-569f95f5cb-n2j8s)
        └── Pod(nginx-deployment-569f95f5cb-x8xl4)

更新镜像后,Deployment 会创建新 ReplicaSet,旧 ReplicaSet 保留(副本数缩为 0),方便回滚。

2.2.2 创建 Deployment

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3                    # 副本数
  selector:
    matchLabels:
      app: nginx                 # 选择器,匹配 Pod 标签
  template:                      # Pod 模板
    metadata:
      labels:
        app: nginx               # Pod 标签(必须与 selector 匹配)
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:              # 最低资源需求
            cpu: 100m
            memory: 128Mi
          limits:                # 资源上限
            cpu: 500m
            memory: 256Mi
操作命令
创建kubectl apply -f nginx-deployment.yaml
查看kubectl get deploy
查看详情kubectl describe deploy nginx-deployment
查看管理的 Podkubectl get pods -l app=nginxapp=nginx 对应 YAML 中 labels 定义的标签)
删除kubectl delete deploy nginx-deployment

2.2.3 滚动更新和回滚

滚动更新
# 方式1:修改 YAML 中的 image 后重新 apply
kubectl apply -f nginx-deployment.yaml

# 方式2:直接命令行更新镜像
# 格式:kubectl set image deployment/<deployment名称> <容器名称>=<新镜像>
# nginx-deployment → metadata.name,nginx → containers[].name(不是 label)
kubectl set image deployment/nginx-deployment nginx=nginx:1.26

# 查看更新进度
kubectl rollout status deployment/nginx-deployment

更新策略(在 YAML 中配置):

spec:
  strategy:
    type: RollingUpdate          # 滚动更新(默认)
    rollingUpdate:
      maxSurge: 1                # 更新时最多多出 1 个 Pod
      maxUnavailable: 0          # 更新时不允许不可用的 Pod
回滚
操作命令
查看更新历史kubectl rollout history deployment/nginx-deployment
回滚到上一个版本kubectl rollout undo deployment/nginx-deployment
回滚到指定版本kubectl rollout undo deployment/nginx-deployment --to-revision=2
暂停更新kubectl rollout pause deployment/nginx-deployment
恢复更新kubectl rollout resume deployment/nginx-deployment

2.2.4 副本数管理

副本数(replicas)即 Pod 的数量replicas: 3 表示 K8s 始终维持 3 个相同的 Pod 运行。扩缩容就是动态调整这个数字。

操作命令
手动扩缩容kubectl scale deployment nginx-deployment --replicas=5(将 Pod 数量调整为 5)
查看副本状态kubectl get deploy nginx-deployment

输出示例:

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           10m
                   ^^^
                   就绪/期望 副本数

2.3 Service

2.3.1 概念和作用

Service 为一组 Pod 提供稳定的网络访问入口。解决的问题:

  • Pod 的 IP 是动态分配的,Pod 重建后 IP 会变
  • 需要在多个 Pod 之间做负载均衡
  • 需要一个固定的域名/IP 供其他服务访问

类比:Pod 是后端服务器,Service 就是前面的负载均衡器,提供一个稳定的地址。

Deployment 与 Service 的关系

Deployment 和 Service 是独立对象,不是一对一绑定。它们通过 Label 关联:

关系说明
1 Deployment → 0 Service内部服务不需要被其他服务访问时
1 Deployment → 1 Service最常见,一个应用一个访问入口
1 Deployment → 多个 Service同一应用暴露不同端口/协议(如 HTTP + gRPC)
多个 Deployment → 1 Service少见,但 Service 只要 label 匹配就能指向多组 Pod

Deployment 创建 Pod 跑在已有的 Worker 上,不会新建 Worker。Pod 由 kube-scheduler 自动调度到合适的节点。

2.3.2 Service 类型

类型说明访问范围
ClusterIP默认类型,分配一个集群内部 IP仅集群内部访问
NodePort在每个节点上开放一个固定端口(30000-32767)集群外部可通过 节点IP:NodePort 访问
LoadBalancer在 NodePort 基础上,创建云厂商的外部负载均衡器外部访问(需云环境支持)
ClusterIP(默认)
# cluster-ip-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: ClusterIP               # 默认,可省略
  selector:
    app: nginx                   # 选择标签为 app=nginx 的 Pod
  ports:
  - port: 80                     # Service 端口
    targetPort: 80               # Pod 容器端口
NodePort
# node-port-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80                     # Service 端口(集群内访问)
    targetPort: 80               # Pod 容器端口
    nodePort: 30080              # 节点端口(外部访问),不指定则自动分配
LoadBalancer
# load-balancer-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-lb
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80

2.3.3 集群内访问 Service(服务发现)

完整示例:Deployment + Service
# nginx-app.yaml(一个文件中包含 Deployment 和 Service,用 --- 分隔)

# ===== Deployment:创建 3 个 nginx Pod =====
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment         # Deployment 名称
  namespace: dev                 # 自定义命名空间(需提前创建:kubectl create namespace dev)
spec:
  replicas: 3                    # 创建 3 个 Pod
  selector:
    matchLabels:
      app: nginx                 # ─┐ 选择器,匹配下方 Pod 的 labels
  template:                      #  │
    metadata:                    #  │
      labels:                    #  │
        app: nginx               # ─┘ Pod 标签(与 selector 和 Service 关联的纽带)
    spec:
      containers:
      - name: nginx              # 容器名称
        image: nginx:1.25
        ports:
        - containerPort: 80      # 容器监听 80 端口
---
# ===== Service:为上面的 Pod 提供统一访问入口 =====
apiVersion: v1
kind: Service
metadata:
  name: nginx-service            # Service 名称(集群内通过此名称访问)
  namespace: dev                 # 与 Deployment 同一命名空间
spec:
  type: ClusterIP                # 仅集群内部可访问
  selector:
    app: nginx                   # ← 通过此标签关联上面 Deployment 创建的 Pod
  ports:
  - port: 80                     # Service 暴露的端口
    targetPort: 80               # 转发到 Pod 的 80 端口
操作命令
创建命名空间kubectl create namespace dev
部署kubectl apply -f nginx-app.yaml
查看 Deploymentkubectl get deploy -n dev
查看关联的 Podkubectl get pods -l app=nginx -n dev
查看 Servicekubectl get svc nginx-service -n dev
查看 Service 背后的 Pod IPkubectl get endpoints nginx-service -n dev
集群内访问测试(同命名空间)kubectl run test -n dev --rm -it --image=busybox -- wget -qO- http://nginx-service
集群内访问测试(跨命名空间)kubectl run test --rm -it --image=busybox -- wget -qO- http://nginx-service.dev.svc.cluster.local

关联关系:Deployment 的 selector.matchLabels 和 Service 的 selector 都通过 app: nginx 这个标签找到同一组 Pod。

集群内的 Pod 可以通过以下方式访问 Service:

方式格式示例
同命名空间<service-name>curl http://nginx-service
跨命名空间<service-name>.<namespace>.svc.cluster.localcurl http://nginx-service.dev.svc.cluster.local

以上方 nginx-app.yaml 为例,各字段对应关系:

完整域名:nginx-service.dev.svc.cluster.local

  • nginx-service → Service 的 metadata.name
  • dev → Service 的 metadata.namespace
  • svc.cluster.local → K8s 固定后缀
  • svc.cluster.local → K8s 固定后缀

K8s 自带 DNS 服务(CoreDNS),自动为每个 Service 创建 DNS 记录。

2.3.4 Endpoints

Endpoints 是 Service 背后实际对应的 Pod IP 列表。Service 通过 selector 匹配 Pod,自动维护 Endpoints。

沿用上方 nginx-app.yaml 部署后,查看 Endpoints:

# 查看 nginx-service 的 Endpoints(nginx-service 即 YAML 中 metadata.name)
kubectl get endpoints nginx-service

# 输出示例:
# NAME            ENDPOINTS                                   AGE
# nginx-service   10.244.1.5:80,10.244.2.3:80,10.244.3.7:80  5m
#                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#                 三个 Pod 的实际 IP:端口

当 Pod 被创建/销毁时,Endpoints 会自动更新,流量只会转发到健康的 Pod。


2.4 Namespace

2.4.1 概念和作用

Namespace(命名空间)用于将集群资源划分为多个逻辑隔离的空间

常见用途

  • 按环境隔离:devstagingproduction
  • 按团队隔离:team-ateam-b
  • 按项目隔离:project-xproject-y

K8s 默认的 Namespace

Namespace说明
default未指定命名空间时的默认空间
kube-systemK8s 系统组件(apiserver、scheduler 等)
kube-public所有用户可读的公共资源
kube-node-lease节点心跳相关

沿用上方 nginx-app.yaml(已指定 namespace: dev)进行验证:

操作命令
查看所有命名空间kubectl get namespaces
创建命名空间kubectl create namespace dev
部署资源到 devkubectl apply -f nginx-app.yaml(YAML 中已指定 namespace: dev)
查看 dev 命名空间的 Podkubectl get pods -n dev
查看 dev 命名空间所有资源kubectl get all -n dev
设置默认命名空间(免 -n)kubectl config set-context --current --namespace=dev
删除命名空间(会删除其下所有资源)kubectl delete namespace dev

2.4.2 资源隔离

Namespace 提供的是逻辑隔离,不同命名空间的资源互不可见(同类型下名称可重复)。

如上方 nginx-app.yaml 所示,在 YAML 中通过 metadata.namespace: dev 指定资源归属的命名空间。

⚠️ 注意:

  • Namespace 是逻辑隔离,不是网络隔离。默认情况下,不同 Namespace 的 Pod 之间可以互相通信
  • 需要网络隔离时,需配合 NetworkPolicy 使用
  • Node 和 PersistentVolume 是集群级资源,不属于任何 Namespace

2.5 Label 和 Selector

Label(标签)

Label 是附加到 K8s 对象上的键值对,用于标识和分类资源。

metadata:
  labels:
    app: nginx               # 应用名
    env: production          # 环境
    tier: frontend           # 层级
    version: v1.0            # 版本
操作命令
给 Pod 添加标签kubectl label pod nginx-pod env=dev
修改已有标签kubectl label pod nginx-pod env=staging --overwrite
删除标签kubectl label pod nginx-pod env-
查看标签kubectl get pods --show-labels

Selector(选择器)

Selector 用于根据 Label 筛选资源。是 Service、Deployment 等关联 Pod 的核心机制。

命令行使用

操作命令
等值筛选kubectl get pods -l app=nginx
多条件筛选(AND)kubectl get pods -l app=nginx,env=dev
不等于kubectl get pods -l env!=production
集合筛选kubectl get pods -l 'env in (dev,staging)'

YAML 中使用(Deployment 通过 selector 关联 Pod):

# Deployment 的 selector 与 Pod 的 labels 必须匹配
spec:
  selector:
    matchLabels:
      app: nginx          # ─┐
  template:               #  │ 必须一致
    metadata:             #  │
      labels:             #  │
        app: nginx        # ─┘

Service 通过 selector 关联 Pod

# Service 选择所有带 app=nginx 标签的 Pod
spec:
  selector:
    app: nginx            # 匹配 Pod 的 labels
  ports:
  - port: 80

Label + Selector 是 K8s 的核心关联机制:Deployment 通过它管理 Pod,Service 通过它转发流量,NetworkPolicy 通过它控制网络策略。


3. 服务发现和负载均衡

3.1 Ingress

3.1.1 概念和作用

在第 2 章中,Service(NodePort/LoadBalancer)可以将流量从集群外部引入,但存在局限:

方式局限
NodePort端口范围有限(30000-32767),每个 Service 占一个端口,不支持域名
LoadBalancer每个 Service 创建一个云负载均衡器,成本高

Ingress 解决的问题:用一个统一入口管理所有外部访问,支持:

  • 域名路由api.example.com → Service A,web.example.com → Service B
  • 路径路由example.com/api → Service A,example.com/web → Service B
  • TLS/HTTPS:统一管理 SSL 证书
  • 负载均衡:一个入口分发到多个后端 Service

类比:Service 是每个应用的"后门",Ingress 是整个集群的"前台大门 + 路由器"。

3.1.2 Ingress Controller

Ingress 本身只是一份路由规则的定义(YAML),不会自动生效。需要部署 Ingress Controller 来实际执行这些规则。

Ingress Controller说明
Nginx Ingress Controller最常用,基于 Nginx 反向代理
Traefik轻量,自动发现服务,适合微服务
HAProxy高性能,企业级
云厂商AWS ALB、GCE、阿里云 SLB,与云服务深度集成

关系:Ingress(规则) + Ingress Controller(执行者) = 完整的外部访问方案。类似 Deployment(规则)需要 kubelet(执行者)来创建 Pod。

在 Kind 中安装 Nginx Ingress Controller

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

# 等待 Controller 就绪
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

3.1.3 Ingress 规则和配置

沿用上方 nginx-app.yaml(Deployment + Service 部署在 dev 命名空间),为其创建 Ingress:

# nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: dev                          # 与 Service 同一命名空间
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /    # URL 重写规则
spec:
  ingressClassName: nginx                 # 指定使用哪个 Ingress Controller
  rules:
  - host: app.example.com                # 域名(匹配请求的 Host 头)
    http:
      paths:
      - path: /                           # 路径匹配
        pathType: Prefix                  # Prefix=前缀匹配,Exact=精确匹配
        backend:
          service:
            name: nginx-service           # ← 转发到的 Service(metadata.name)
            port:
              number: 80                  # ← Service 的端口

nginx-ingress.yaml 是独立文件,与 nginx-app.yaml 分开执行即可。只要满足:

  1. Ingress Controller 已安装
  2. nginx-app.yaml 已部署(Deployment + Service 在 dev 命名空间运行中)
  3. Ingress 的 namespace 与 Service 相同,service.name 与 Service 的 metadata.name 一致
操作命令
创建 Ingresskubectl apply -f nginx-ingress.yaml
查看 Ingresskubectl get ingress -n dev
查看详情kubectl describe ingress nginx-ingress -n dev
删除 Ingresskubectl delete ingress nginx-ingress -n dev
本地访问 Ingress(Kind/WSL 环境)

Kind 没有云负载均衡器,Ingress Controller 的 EXTERNAL-IP 会一直显示 <pending>。通过以下步骤在本地访问:

步骤一:配置 hosts

在 WSL 中添加域名映射(Windows 的 hosts 对 WSL 内的 curl 无效):

echo "127.0.0.1 app.example.com" | sudo tee -a /etc/hosts

步骤二:端口转发

# 方式1:使用非特权端口(无需 sudo)
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 8080:80

# 方式2:使用 80 端口(需指定 kubeconfig,因为 sudo 下 root 的 kubeconfig 不同)
sudo kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 80:80 --kubeconfig=$HOME/.kube/config

步骤三:测试访问(新开一个终端)

# 方式1 对应
curl http://app.example.com:8080

# 方式2 对应
curl http://app.example.com

⚠️ port-forward 是前台进程,终端关闭则停止。生产环境不会用此方式,而是通过云负载均衡器或 NodePort 暴露。

3.1.4 域名路由和路径路由

域名路由(多个域名 → 不同 Service)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
  namespace: dev
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com               # 域名 A
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service            # → 转发到 api-service
            port:
              number: 8080
  - host: web.example.com               # 域名 B
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service            # → 转发到 web-service
            port:
              number: 80
路径路由(同一域名,不同路径 → 不同 Service)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-ingress
  namespace: dev
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - path: /api(/|$)(.*)             # example.com/api/* → api-service
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /web(/|$)(.*)             # example.com/web/* → web-service
        pathType: ImplementationSpecific
        backend:
          service:
            name: web-service
            port:
              number: 80
TLS/HTTPS 配置
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  namespace: dev
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls-secret           # 存储证书的 Secret 名称
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

证书通过 kubectl create secret tls app-tls-secret --cert=tls.crt --key=tls.key -n dev 创建。

访问流程总结

用户请求 → Ingress Controller(Nginx) → 根据域名/路径匹配 Ingress 规则 → 转发到 Service → kube-proxy 负载均衡 → Pod

3.2 网络

3.2.1 Kubernetes 网络模型

K8s 网络遵循三条基本原则:

原则说明
Pod 间通信所有 Pod 可以直接通过 IP 互相通信,无需 NAT
Pod 与 ServicePod 通过 Service 的 ClusterIP 或 DNS 名称访问其他服务
外部与集群通过 NodePort、LoadBalancer 或 Ingress 访问集群内服务

四种通信场景

场景实现方式
同一 Pod 内容器间通过 localhost(共享网络命名空间)
同一节点的 Pod 间通过虚拟网桥(如 cbr0/cni0)直接通信
跨节点的 Pod 间通过 CNI 插件建立的覆盖网络(Overlay Network)
外部访问 Pod通过 Service(NodePort/LoadBalancer)或 Ingress

3.2.2 CNI(Container Network Interface)

CNI 是 K8s 的网络插件规范,负责为 Pod 分配 IP、建立跨节点通信。K8s 本身不实现网络,由 CNI 插件完成。

CNI 插件特点适用场景
Flannel简单轻量,配置少学习、小型集群
Calico支持网络策略(NetworkPolicy),性能好生产环境,需要网络隔离
Cilium基于 eBPF,高性能,可观测性强大规模生产,安全要求高
Weave自动发现,加密通信多云环境

Kind 和 Minikube 默认自带 CNI 插件(kindnet / bridge),学习阶段无需额外安装。

CNI 工作流程

Pod 创建 → kubelet 调用 CNI 插件 → 分配 IP → 配置网络(veth pair、路由规则) → Pod 可通信

3.2.3 Service Mesh

Service Mesh(服务网格)是在 K8s 网络之上的应用层网络方案,用于管理微服务间的通信。

为什么需要 Service Mesh? K8s 的 Service + kube-proxy 只提供基础的 L4(TCP)负载均衡,缺少:

需求Service Mesh 提供的能力
流量管理灰度发布、A/B 测试、流量镜像、熔断、重试
可观测性分布式链路追踪、指标采集、访问日志
安全服务间 mTLS 加密、访问控制
策略限流、超时配置、故障注入

主流 Service Mesh

方案说明
Istio功能最全面,社区最大,学习曲线较陡
Linkerd轻量级,性能好,易于上手
Consul ConnectHashiCorp 出品,与 Consul 服务发现集成

Istio 架构简述

graph LR
    subgraph Data Plane["数据平面"]
        A[Pod A] --- SA[Sidecar Proxy<br/>Envoy]
        B[Pod B] --- SB[Sidecar Proxy<br/>Envoy]
        SA <-->|加密通信| SB
    end
    subgraph Control Plane["控制平面"]
        IS[istiod<br/>配置管理/证书/服务发现]
    end
    IS -->|下发配置| SA
    IS -->|下发配置| SB

Service Mesh 通过在每个 Pod 旁注入 Sidecar 代理(如 Envoy),拦截所有进出流量,实现上述能力。业务代码无需修改。

⚠️ Service Mesh 属于进阶内容,小型项目或学习阶段不必使用。


4. 存储和配置

4.1 ConfigMap 和 Secret

ConfigMap

ConfigMap 用于存储非敏感的配置数据(键值对或配置文件),与应用代码解耦。

创建 ConfigMap
# 方式1:命令行创建
kubectl create configmap app-config \
  --from-literal=DB_HOST=mysql-service \
  --from-literal=DB_PORT=3306 \
  -n dev

# 方式2:从文件创建
kubectl create configmap nginx-config \
  --from-file=nginx.conf \
  -n dev
# 方式3:YAML 创建
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: dev
data:
  DB_HOST: mysql-service          # 键值对形式
  DB_PORT: "3306"
  app.properties: |               # 文件形式(多行内容)
    server.port=8080
    spring.datasource.url=jdbc:mysql://mysql-service:3306/mydb
使用 ConfigMap

方式1:注入为环境变量

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
  namespace: dev
spec:
  containers:
  - name: app
    image: my-app:1.0
    env:
    - name: DB_HOST                      # 容器中的环境变量名
      valueFrom:
        configMapKeyRef:
          name: app-config               # ConfigMap 名称
          key: DB_HOST                   # ConfigMap 中的 key
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DB_PORT

方式2:挂载为配置文件

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
  namespace: dev
spec:
  containers:
  - name: app
    image: my-app:1.0
    volumeMounts:
    - name: config-volume
      mountPath: /app/config             # 挂载到容器内的路径
  volumes:
  - name: config-volume
    configMap:
      name: app-config                   # ConfigMap 名称
      # ConfigMap 的每个 key 变成 /app/config/ 下的一个文件
操作命令
查看 ConfigMapkubectl get configmap -n dev
查看内容kubectl describe configmap app-config -n dev
删除kubectl delete configmap app-config -n dev

Secret

Secret 用于存储敏感数据(密码、Token、证书等),与 ConfigMap 类似但数据以 Base64 编码存储。

创建 Secret
# 方式1:命令行创建
kubectl create secret generic db-secret \
  --from-literal=DB_USER=admin \
  --from-literal=DB_PASSWORD=p@ssw0rd \
  -n dev
# 方式2:YAML 创建(值需 Base64 编码)
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
  namespace: dev
type: Opaque
data:
  DB_USER: YWRtaW4=               # echo -n 'admin' | base64
  DB_PASSWORD: cEBzc3cwcmQ=       # echo -n 'p@ssw0rd' | base64
使用 Secret
# 注入为环境变量(与 ConfigMap 类似,将 configMapKeyRef 换为 secretKeyRef)
apiVersion: v1
kind: Pod
metadata:
  name: app-pod
  namespace: dev
spec:
  containers:
  - name: app
    image: my-app:1.0
    env:
    - name: DB_USER
      valueFrom:
        secretKeyRef:
          name: db-secret                # Secret 名称
          key: DB_USER
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASSWORD
操作命令
查看 Secretkubectl get secret -n dev
查看内容(Base64 编码)kubectl get secret db-secret -n dev -o yaml
解码查看kubectl get secret db-secret -n dev -o jsonpath='{.data.DB_PASSWORD}' | base64 -d

⚠️ Secret 不是真正的加密,Base64 只是编码,任何人拿到都能解码。生产环境建议配合 RBAC 限制访问权限,或使用外部密钥管理(如 Vault、AWS Secrets Manager)。

ConfigMap vs Secret 对比

对比项ConfigMapSecret
用途非敏感配置(数据库地址、端口等)敏感数据(密码、Token、证书)
存储方式明文Base64 编码
大小限制1MB1MB
使用方式环境变量 / 挂载文件环境变量 / 挂载文件
引用方式configMapKeyRefsecretKeyRef

4.2 存储

Volume(卷)

在 2.1.4 多容器 Pod 中已介绍过 emptyDir。Volume 是 K8s 中为 Pod 提供存储的机制,生命周期与 Pod 绑定或独立于 Pod。

常用 Volume 类型回顾

类型存储位置生命周期适用场景
emptyDirWorker 节点磁盘随 Pod 销毁Pod 内容器间共享临时数据
hostPathWorker 节点指定路径节点存在就在访问节点文件(日志、Docker socket)
configMapetcd(通过 ConfigMap)随 ConfigMap 存在挂载配置文件
secretetcd(通过 Secret)随 Secret 存在挂载敏感配置
persistentVolumeClaim外部存储独立于 Pod 和节点数据库、文件存储等持久化需求

PersistentVolume(PV)和 PersistentVolumeClaim(PVC)

emptyDirhostPath 的数据会随 Pod/节点丢失,不适合需要持久化存储的场景(如数据库)。

K8s 通过 PV + PVC 机制实现持久化存储:

概念说明类比
PersistentVolume (PV)集群中一块预先准备好的存储资源硬盘
PersistentVolumeClaim (PVC)Pod 对存储的申请("我需要 10Gi 空间")购买硬盘的订单

流程:管理员创建 PV → 开发者创建 PVC 申请存储 → K8s 自动将 PVC 绑定到匹配的 PV → Pod 挂载 PVC 使用

创建 PV
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv                            # PV 是集群级资源,不属于任何 namespace
spec:
  capacity:
    storage: 10Gi                         # 存储容量
  accessModes:
  - ReadWriteOnce                         # 访问模式(见下方说明)
  persistentVolumeReclaimPolicy: Retain   # 回收策略(见下方说明)
  storageClassName: manual                # 存储类名(与 PVC 匹配)
  hostPath:
    path: /data/my-pv                     # 存储在节点上的路径(仅测试用)

访问模式

模式简写说明
ReadWriteOnceRWO单节点读写
ReadOnlyManyROX多节点只读
ReadWriteManyRWX多节点读写(需存储支持,如 NFS)

回收策略

策略说明
RetainPVC 删除后 PV 保留数据,需手动清理
DeletePVC 删除后 PV 和存储一起删除(云盘常用)
Recycle清除数据后重新可用(已废弃)
创建 PVC
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
  namespace: dev
spec:
  accessModes:
  - ReadWriteOnce                         # 需与 PV 匹配
  resources:
    requests:
      storage: 5Gi                        # 申请 5Gi(PV 需 ≥ 5Gi)
  storageClassName: manual                # 需与 PV 的 storageClassName 匹配
在 Pod 中使用 PVC
apiVersion: v1
kind: Pod
metadata:
  name: db-pod
  namespace: dev
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASSWORD
    volumeMounts:
    - name: db-storage
      mountPath: /var/lib/mysql           # MySQL 数据目录
  volumes:
  - name: db-storage
    persistentVolumeClaim:
      claimName: my-pvc                   # 引用 PVC 名称
操作命令
创建 PVkubectl apply -f pv.yaml
创建 PVCkubectl apply -f pvc.yaml
查看 PVkubectl get pv
查看 PVCkubectl get pvc -n dev
查看绑定状态PV 和 PVC 的 STATUS 都显示 Bound 表示绑定成功

StorageClass

手动创建 PV 太繁琐。StorageClass 实现动态供给:PVC 创建时自动创建对应的 PV。

# storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-storage
provisioner: kubernetes.io/aws-ebs       # 存储供应商(不同环境不同)
parameters:
  type: gp3                               # 存储类型参数
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer   # 等 Pod 调度后再创建 PV

使用 StorageClass 的 PVC(无需手动创建 PV):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: auto-pvc
  namespace: dev
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  storageClassName: fast-storage          # 引用 StorageClass,自动创建 PV

流程对比

  • 手动:管理员创建 PV → 开发者创建 PVC → 绑定
  • 动态(StorageClass):开发者创建 PVC(指定 StorageClass)→ K8s 自动创建 PV → 自动绑定
操作命令
查看 StorageClasskubectl get storageclass
查看默认 StorageClasskubectl get sc(带 (default) 标记的)

常见 provisioner

环境provisioner
AWS EBSkubernetes.io/aws-ebsebs.csi.aws.com
GCE PDkubernetes.io/gce-pd
阿里云diskplugin.csi.alibabacloud.com
NFSnfs-subdir-external-provisioner
本地测试(Kind)rancher.io/local-path(Kind 默认自带)