本文面向具备 Linux 基础的运维与开发工程师,系统介绍 Kubernetes 核心概念、集群部署流程及日常运维操作,附带可直接复用的命令与 YAML 配置。


一、Kubernetes 基础

1.1 什么是 Kubernetes

Kubernetes(K8s)是 Google 开源的容器编排平台,用于自动化容器化应用的部署、扩缩、负载均衡和自愈。它将底层基础设施抽象为统一的 API,使应用与底层环境解耦。

1.2 整体架构

Kubernetes 采用主从(Master-Worker)架构

┌─────────────────────────────────┐
│         Control Plane (Master)  │
│  ┌──────────┐  ┌─────────────┐  │
│  │ API Server│  │  Scheduler  │  │
│  └──────────┘  └─────────────┘  │
│  ┌──────────┐  ┌─────────────┐  │
│  │Controller │  │   etcd      │  │
│  │ Manager   │  │ (KV Store)  │  │
│  └──────────┘  └─────────────┘  │
└─────────────────────────────────┘
         ▲  API  ▲
         │       │
┌────────┴───────┴────────────────┐
│         Worker Nodes            │
│  ┌──────┐ ┌──────┐ ┌────────┐  │
│  │kubelet│ │kube- │ │Container│  │
│  │      │ │proxy │ │ Runtime │  │
│  └──────┘ └──────┘ └────────┘  │
│  ┌──────────────────────────┐   │
│  │   Pod  Pod  Pod  Pod     │   │
│  └──────────────────────────┘   │
└─────────────────────────────────┘

1.3 核心组件

Control Plane(控制平面)组件:

组件

作用

kube-apiserver

集群的统一入口,所有操作通过 REST API 进行

etcd

分布式键值存储,保存集群所有状态数据

kube-scheduler

根据资源、亲和性等策略将 Pod 调度到合适的 Node

kube-controller-manager

运行各种控制器(Deployment、ReplicaSet、Node 等)

Worker Node 组件:

组件

作用

kubelet

管理本节点上 Pod 的生命周期

kube-proxy

维护网络规则,实现 Service 的负载均衡

Container Runtime

实际运行容器的引擎(containerd、CRI-O 等)

1.4 Master 与 Node

  • Master 节点:运行控制平面组件,负责集群的决策与管理。生产环境建议至少 3 台以实现高可用。

  • Node 节点:运行实际工作负载(Pod),可按需横向扩展。

1.5 etcd 与 API Server

etcd 是集群的"单一数据源",所有资源对象(Pod、Service、ConfigMap 等)都以键值对形式存储。API Server 是 etcd 的唯一客户端,其他组件均通过 API Server 间接读写 etcd。

查看 etcd 健康状态:

etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint health

二、使用 kubeadm 部署集群

2.1 环境准备

硬件要求(每节点最低):

  • 2 核 CPU

  • 2 GB 内存

  • 20 GB 磁盘

系统要求: CentOS 7/8、Ubuntu 20.04/22.04、Rocky Linux 8/9

所有节点执行基础配置:

# 关闭 swap(Kubernetes 要求)
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab

# 关闭 SELinux(CentOS/RHEL)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

# 加载内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

# 配置 sysctl
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF
sudo sysctl --system

# 配置主机名和 hosts
sudo hostnamectl set-hostname k8s-master  # 各节点设置不同主机名
cat <<EOF | sudo tee -a /etc/hosts
192.168.1.10  k8s-master
192.168.1.11  k8s-node1
192.168.1.12  k8s-node2
EOF

2.2 安装 containerd 和 kubeadm

所有节点执行:

# 安装 containerd
sudo apt-get update
sudo apt-get install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 修改 SystemdCgroup = true
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd

# 添加 Kubernetes APT 源(以 v1.30 为例)
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl enable kubelet

CentOS/RHEL 系统:

# 添加 YUM 源
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key
EOF
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable kubelet

2.3 初始化 Master 节点

# 在 k8s-master 上执行
sudo kubeadm init \
  --apiserver-advertise-address=192.168.1.10 \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=10.96.0.0/12 \
  --image-repository registry.aliyuncs.com/google_containers

# 初始化完成后,配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

提示: --image-repository 指向国内镜像源可加速拉取。若网络条件良好,可省略此参数。

初始化成功后,终端会输出 kubeadm join 命令,务必保存:

kubeadm join 192.168.1.10:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxx

2.4 Worker 节点加入集群

# 在每个 Worker 节点上执行
sudo kubeadm join 192.168.1.10:6443 \
  --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxx

若 token 过期,在 Master 上重新生成:

kubeadm token create --print-join-command

2.5 安装网络插件(CNI)

Kubernetes 要求安装 CNI 插件,否则节点状态为 NotReady

Calico(推荐,支持 NetworkPolicy):

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml

Flannel(轻量,适合学习环境):

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

验证集群状态:

kubectl get nodes
# NAME          STATUS   ROLES           AGE   VERSION
# k8s-master    Ready    control-plane   5m    v1.30.0
# k8s-node1     Ready    <none>          3m    v1.30.0
# k8s-node2     Ready    <none>          3m    v1.30.0

kubectl get pods -n kube-system

三、kubectl 常用命令

3.1 集群与资源查看

# 查看集群信息
kubectl cluster-info

# 查看所有节点
kubectl get nodes -o wide

# 查看所有命名空间的 Pod
kubectl get pods --all-namespaces

# 查看资源详情(以 Pod 为例)
kubectl describe pod <pod-name> -n <namespace>

# 查看资源的 YAML 定义
kubectl get deployment nginx -o yaml

# 以 JSON 格式输出
kubectl get svc -o json

# 查看所有资源类型
kubectl api-resources

3.2 创建与管理资源

# 从 YAML 文件创建资源
kubectl apply -f deployment.yaml

# 删除资源
kubectl delete -f deployment.yaml
kubectl delete pod <pod-name>

# 强制删除卡在 Terminating 的 Pod
kubectl delete pod <pod-name> --grace-period=0 --force

# 扩缩容
kubectl scale deployment nginx --replicas=5

# 滚动更新
kubectl set image deployment/nginx nginx=nginx:1.25

# 查看更新状态
kubectl rollout status deployment/nginx

# 回滚到上一版本
kubectl rollout undo deployment/nginx

# 查看修订历史
kubectl rollout history deployment/nginx

3.3 调试与日志

# 查看 Pod 日志
kubectl logs <pod-name>
kubectl logs <pod-name> -c <container-name>  # 多容器 Pod
kubectl logs -f <pod-name> --tail=100         # 实时尾部 100 行

# 进入容器
kubectl exec -it <pod-name> -- /bin/bash

# 查看资源使用(需要 metrics-server)
kubectl top pods
kubectl top nodes

# 快速创建临时 Pod 进行测试
kubectl run debug --rm -it --image=busybox -- /bin/sh

3.4 上下文与命名空间

# 查看当前上下文
kubectl config current-context

# 切换上下文
kubectl config use-context <context-name>

# 设置默认命名空间
kubectl config set-context --current --namespace=production

# 创建命名空间
kubectl create namespace dev

四、Pod 详解

4.1 Pod 定义

Pod 是 Kubernetes 的最小调度单元,一个 Pod 可包含一个或多个容器,它们共享网络命名空间和存储卷。

# pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-demo
  labels:
    app: nginx
    env: demo
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    ports:
    - containerPort: 80
kubectl apply -f pod-demo.yaml
kubectl get pod nginx-demo -o wide

4.2 Pod 生命周期

Pod 有以下阶段(Phase):

阶段

含义

Pending

已被调度,等待容器创建(拉取镜像等)

Running

至少一个容器正在运行

Succeeded

所有容器正常退出

Failed

至少一个容器异常退出

Unknown

无法获取 Pod 状态

Pod 的条件(Conditions)包括 PodScheduledInitializedContainersReadyReady

4.3 多容器 Pod 模式

Sidecar 模式 — 辅助容器与主容器共享网络和存储:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  # 主容器:Web 应用
  - name: app
    image: myapp:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/app

  # Sidecar 容器:日志收集
  - name: log-collector
    image: fluentd:v1.16
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/app
      readOnly: true

  volumes:
  - name: shared-logs
    emptyDir: {}

4.4 资源限制

apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: app
    image: nginx:1.25
    resources:
      requests:        # 调度依据:最低保障
        cpu: "250m"    # 0.25 核
        memory: "128Mi"
      limits:          # 硬上限:超出会被 OOM Kill
        cpu: "500m"
        memory: "256Mi"

最佳实践:

  • requests 保证 Pod 获得基本资源

  • limits 防止单个 Pod 耗尽节点资源

  • 始终设置 requests,按需设置 limits

4.5 健康检查(探针)

apiVersion: v1
kind: Pod
metadata:
  name: healthcheck-demo
spec:
  containers:
  - name: app
    image: myapp:v1
    ports:
    - containerPort: 8080

    # 存活探针:失败则重启容器
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 10
      failureThreshold: 3

    # 就绪探针:失败则从 Service 端点移除
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

    # 启动探针:保护慢启动应用
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      failureThreshold: 30
      periodSeconds: 10

探针支持三种检测方式:

方式

用途

httpGet

HTTP 状态码 2xx/3xx 为成功

tcpSocket

TCP 端口可达为成功

exec

命令退出码为 0 为成功


五、Deployment

5.1 创建 Deployment

# deployment-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1          # 滚动更新时最多多出的 Pod 数
      maxUnavailable: 0     # 更新过程中不允许不可用
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "100m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "128Mi"
kubectl apply -f deployment-nginx.yaml
kubectl get deployment nginx
kubectl get replicasets
kubectl get pods -l app=nginx

5.2 更新策略

滚动更新(默认): 逐步用新版 Pod 替换旧版,保证服务不中断。

# 方式一:修改镜像
kubectl set image deployment/nginx nginx=nginx:1.26

# 方式二:编辑 YAML
kubectl edit deployment nginx

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

# 暂停/恢复滚动更新(用于批量修改多个字段)
kubectl rollout pause deployment/nginx
kubectl set image deployment/nginx nginx=nginx:1.26
kubectl set resources deployment/nginx -c=nginx --limits=cpu=300m
kubectl rollout resume deployment/nginx

5.3 回滚

# 查看修订历史
kubectl rollout history deployment/nginx

# 查看特定版本的详情
kubectl rollout history deployment/nginx --revision=2

# 回滚到上一版本
kubectl rollout undo deployment/nginx

# 回滚到指定版本
kubectl rollout undo deployment/nginx --to-revision=1

5.4 水平自动扩缩(HPA)

HPA 根据 CPU/内存使用率自动调整副本数。

# hpa-nginx.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300   # 缩容冷静期 5 分钟
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
# 前提:安装 metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

kubectl apply -f hpa-nginx.yaml
kubectl get hpa
kubectl describe hpa nginx-hpa

六、Service

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

6.1 ClusterIP(默认)

集群内部访问,不暴露到外部。

apiVersion: v1
kind: Service
metadata:
  name: nginx-clusterip
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
  - port: 80           # Service 端口
    targetPort: 80      # 容器端口
    protocol: TCP
kubectl get svc nginx-clusterip
# 内部访问:curl http://nginx-clusterip.default.svc.cluster.local

6.2 NodePort

在每个节点上开放一个端口(30000-32767),外部可通过 <NodeIP>:<NodePort> 访问。

apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080     # 可选:指定端口,不指定则自动分配

6.3 LoadBalancer

使用云厂商的负载均衡器(适用于 AWS ELB、阿里云 SLB 等)。

apiVersion: v1
kind: Service
metadata:
  name: nginx-lb
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: slb.s1.small
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80

6.4 Endpoints

Service 通过 Endpoints 资源跟踪后端 Pod 的 IP 列表:

kubectl get endpoints nginx-clusterip
# NAME               ENDPOINTS                                 AGE
# nginx-clusterip    10.244.1.5:80,10.244.2.8:80,10.244.3.3:80  5m

手动管理 Endpoints(适用于外部服务):

apiVersion: v1
kind: Endpoints
metadata:
  name: external-db
subsets:
- addresses:
  - ip: 10.0.0.100
  ports:
  - port: 5432
    protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  ports:
  - port: 5432
    targetPort: 5432

七、Ingress

Ingress 是集群的"七层网关",提供基于域名和路径的 HTTP/HTTPS 路由。

7.1 安装 Nginx Ingress Controller

# 使用 Helm 安装
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --set controller.service.type=NodePort \
  --set controller.service.nodePorts.http=30080 \
  --set controller.service.nodePorts.https=30443

或使用 YAML:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml

7.2 基本路由配置

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-clusterip
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

7.3 PathType 说明

PathType

行为

示例

Prefix

按 URL 前缀匹配

/api 匹配 /api/api/users/api/v2

Exact

精确匹配

/api 只匹配 /api,不匹配 /api/

ImplementationSpecific

由 Ingress Controller 决定

取决于具体实现

7.4 TLS 配置

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls-secret    # 包含 tls.crt 和 tls.key 的 Secret
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-clusterip
            port:
              number: 80

创建 TLS Secret:

kubectl create secret tls app-tls-secret \
  --cert=tls.crt \
  --key=tls.key

7.5 常用 Annotations

metadata:
  annotations:
    # 限速
    nginx.ingress.kubernetes.io/limit-rps: "10"
    nginx.ingress.kubernetes.io/limit-connections: "5"

    # 请求体大小限制
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"

    # 超时设置
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "60"

    # CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://frontend.example.com"

    # 自定义错误页面
    nginx.ingress.kubernetes.io/custom-http-errors: "404,503"

    # 跨域 WebSocket 支持
    nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
    nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"

八、ConfigMap 与 Secret

8.1 ConfigMap

存储非敏感的配置数据。

从字面值创建:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: "production"
  APP_DEBUG: "false"
  database.properties: |
    db.host=mysql.default.svc.cluster.local
    db.port=3306
    db.name=myapp

从文件创建:

kubectl create configmap nginx-conf --from-file=nginx.conf
kubectl create configmap app-config --from-env-file=config.env

在 Pod 中使用:

apiVersion: v1
kind: Pod
metadata:
  name: config-demo
spec:
  containers:
  - name: app
    image: myapp:v1
    # 方式一:环境变量
    env:
    - name: APP_ENV
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_ENV
    # 方式二:整个 ConfigMap 映射为环境变量
    envFrom:
    - configMapRef:
        name: app-config
    # 方式三:挂载为文件
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

8.2 Secret

存储敏感数据(密码、Token、证书等),数据以 Base64 编码存储。

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  DB_USER: YWRtaW4=          # echo -n 'admin' | base64
  DB_PASS: cEBzc3cwcmQxMjM=  # echo -n 'p@ssw0rd123' | base64
# 使用 kubectl 更方便
kubectl create secret generic db-secret \
  --from-literal=DB_USER=admin \
  --from-literal=DB_PASS='p@ssw0rd123'

# 创建 TLS Secret
kubectl create secret tls my-tls --cert=cert.pem --key=key.pem

# 创建 Docker Registry Secret
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass

在 Pod 中使用 Secret:

spec:
  containers:
  - name: app
    image: myapp:v1
    env:
    - name: DB_USER
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_USER
    - name: DB_PASS
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASS
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: db-secret

安全建议: 生产环境建议启用 etcd 加密(EncryptionConfiguration)或使用外部密钥管理(如 Vault)。


九、持久卷(Persistent Volume)

9.1 PV 与 PVC 概念

  • PV(PersistentVolume):集群级别的存储资源,由管理员预先创建或动态供给。

  • PVC(PersistentVolumeClaim):用户的存储请求,声明所需的容量和访问模式。

用户提交 PVC → Kubernetes 匹配合适的 PV → 绑定 → Pod 挂载使用

9.2 静态供给

创建 PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteMany        # 多节点读写
  persistentVolumeReclaimPolicy: Retain   # 删除 PVC 后保留数据
  nfs:
    server: 192.168.1.100
    path: /data/k8s-volumes/pv1

创建 PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  # storageClassName: ""   # 空字符串表示不使用动态供给

在 Pod 中使用:

apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod
spec:
  containers:
  - name: app
    image: nginx:1.25
    volumeMounts:
    - name: data
      mountPath: /usr/share/nginx/html
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: nfs-pvc

9.3 动态供给(StorageClass)

StorageClass 定义了动态创建 PV 的"模板"。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: nfs-subdir-external-provisioner  # 需要部署 Provisioner
parameters:
  archiveOnDelete: "false"
  server: 192.168.1.100
  share: /data/k8s-volumes
reclaimPolicy: Delete
volumeBindingMode: Immediate

部署 NFS Provisioner:

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --set nfs.server=192.168.1.100 \
  --set nfs.path=/data/k8s-volumes \
  --set storageClass.name=nfs-client

PVC 引用 StorageClass 后会自动创建 PV:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: auto-pvc
spec:
  storageClassName: nfs-client
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 5Gi

9.4 访问模式

模式

缩写

说明

ReadWriteOnce

RWO

单节点读写

ReadOnlyMany

ROX

多节点只读

ReadWriteMany

RWX

多节点读写

ReadWriteOncePod

RWOP

单 Pod 读写(K8s 1.22+)


十、Helm 包管理

10.1 安装 Helm

# 方式一:脚本安装
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 方式二:包管理器
# Ubuntu/Debian
sudo apt-get install helm
# CentOS/RHEL
sudo yum install helm

# 验证
helm version

10.2 Chart 结构

Helm Chart 是 Kubernetes 应用的打包格式:

mychart/
├── Chart.yaml          # Chart 元数据(名称、版本)
├── Chart.lock          # 依赖锁定
├── values.yaml         # 默认配置值
├── templates/          # 模板文件
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl    # 模板辅助函数
│   └── tests/
├── charts/             # 子 Chart 依赖
└── README.md

Chart.yaml 示例:

apiVersion: v2
name: myapp
description: A Helm chart for My Application
type: application
version: 1.0.0          # Chart 版本
appVersion: "2.1.0"     # 应用版本
dependencies:
- name: redis
  version: "18.x.x"
  repository: "https://charts.bitnami.com/bitnami"
  condition: redis.enabled

values.yaml 示例:

replicaCount: 3

image:
  repository: myapp
  tag: "2.1.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: nginx
  hosts:
  - host: myapp.example.com
    paths:
    - path: /
      pathType: Prefix
  tls: []

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 256Mi

10.3 常用 Helm 命令

# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# 搜索 Chart
helm search repo nginx
helm search hub wordpress

# 安装 Chart
helm install my-nginx bitnami/nginx -n web --create-namespace

# 自定义 values 安装
helm install my-app ./mychart -f custom-values.yaml
helm install my-app ./mychart --set replicaCount=5 --set image.tag=v3

# 查看已安装的 Release
helm list -A

# 查看 Release 状态
helm status my-nginx

# 查看当前 values
helm get values my-nginx

# 查看全部 values(包含默认值)
helm get values my-nginx --all

# 升级
helm upgrade my-nginx bitnami/nginx --set replicaCount=3

# 升级或安装(不存在则安装)
helm upgrade --install my-nginx bitnami/nginx -f values.yaml

# 回滚
helm rollback my-nginx 1          # 回滚到版本 1

# 查看修订历史
helm history my-nginx

# 卸载
helm uninstall my-nginx -n web

# 干跑(不实际执行)
helm install my-app ./mychart --dry-run --debug

# 模板渲染(调试模板)
helm template my-app ./mychart -f values.yaml

10.4 创建自定义 Chart

# 脚手架创建
helm create mychart

# 验证 Chart 语法
helm lint mychart

# 打包
helm package mychart

# 推送到 OCI Registry(Helm 3.8+)
helm push mychart-1.0.0.tgz oci://registry.example.com/charts

# 推送到 ChartMuseum
helm cm-push mychart-1.0.0.tgz my-repo

附录:快速参考表

操作

命令

查看所有 Pod

kubectl get pods -A

查看节点资源

kubectl top nodes

查看事件

kubectl get events --sort-by=.metadata.creationTimestamp

进入容器

kubectl exec -it <pod> -- bash

端口转发

kubectl port-forward svc/my-svc 8080:80

复制文件

kubectl cp <pod>:/path ./local-path

标签节点

kubectl label node k8s-node1 disk=ssd

污点节点

kubectl taint node k8s-node1 key=val:NoSchedule

查看 Ingress

kubectl get ingress

查看 StorageClass

kubectl get sc

查看 HPA

kubectl get hpa


系列导航: 本文是「服务器运维笔记」系列第 28 篇,覆盖了 Kubernetes 从零到部署的核心流程。后续将深入 StatefulSet、DaemonSet、CronJob、RBAC、网络策略等进阶主题。