K8s 部署学习笔记

K8s 部署学习笔记

一、环境准备

1.1 安装 minikube

powershell

复制代码
# 下载 minikube(Windows)
# 访问 https://github.com/kubernetes/minikube/releases
# 下载 minikube-windows-amd64.exe,重命名为 minikube.exe,放到 C:\minikube\

# 验证安装
C:\minikube\minikube.exe version

1.2 启动 minikube 集群

powershell

复制代码
# 基本启动
C:\minikube\minikube.exe start --driver=docker --memory=4096 --cpus=2

# 国内镜像加速(如果网络慢)
C:\minikube\minikube.exe start --driver=docker --memory=4096 --cpus=2 --image-mirror-country=cn

常见问题:网络问题导致镜像拉取失败

表格

错误 解决
cannot pull kicbase image 配置 Docker 镜像加速器,或手动拉取镜像
registry.cn-hangzhou.aliyuncs.com/... not found 阿里云镜像源缺少某些镜像,改用默认源

二、部署过程中的问题与解决

问题 1:ImagePullBackOff(镜像拉取失败)

现象:

powershell

复制代码
kubectl get pods -n camp
# NAME                    READY   STATUS             RESTARTS   AGE
# camp-auth-xxx           0/1     ImagePullBackOff   0          5m

原因分析:

  • 镜像仓库需要认证(私有镜像)

  • 镜像不存在或拼写错误

  • 网络问题(国内访问 ghcr.io 慢/被墙)

错误日志:

plain

复制代码
Failed to pull image "ghcr.io/...": unauthorized

解决方案:

方案 A:本地构建并加载镜像(推荐用于学习)

powershell

复制代码
# 1. 确认本地有镜像
docker images | findstr camp

# 2. 给镜像打上 YAML 中期望的标签
docker tag kubernetes-microservices-camp-auth:latest ghcr.io/elishatheodore/kubernetes-microservices/camp-auth:latest
docker tag kubernetes-microservices-camp-web:latest ghcr.io/elishatheodore/kubernetes-microservices/camp-web:latest
docker tag kubernetes-microservices-camp-backend:latest ghcr.io/elishatheodore/kubernetes-microservices/camp-backend:latest

# 3. 加载到 minikube
minikube image load ghcr.io/elishatheodore/kubernetes-microservices/camp-auth:latest
minikube image load ghcr.io/elishatheodore/kubernetes-microservices/camp-web:latest
minikube image load ghcr.io/elishatheodore/kubernetes-microservices/camp-backend:latest

# 4. 验证
minikube ssh -- docker images | findstr camp

方案 B:配置镜像拉取密钥(用于私有仓库)

powershell

复制代码
# 创建 docker-registry 密钥
kubectl create secret docker-registry ghcr-secret `
  --docker-server=ghcr.io `
  --docker-username=你的GitHub用户名 `
  --docker-password=你的GitHubToken `
  -n camp

# 在 Deployment 中添加 imagePullSecrets
# spec.template.spec.imagePullSecrets:
#   - name: ghcr-secret

问题 2:imagePullPolicy 导致重复拉取镜像

现象: 即使镜像已加载到 minikube,Pod 仍然尝试从远程拉取。

原因: 当镜像标签是 latest 时,K8s 默认 imagePullPolicy: Always,每次都从远程拉取。

解决: 修改 Deployment,添加 imagePullPolicy: Never

yaml

复制代码
spec:
  containers:
    - name: camp-auth
      image: ghcr.io/elishatheodore/kubernetes-microservices/camp-auth:latest
      imagePullPolicy: Never  # ← 添加这一行

批量修改命令:

powershell

复制代码
(Get-Content auth-frontend-deployment.yaml) -replace 'imagePullPolicy: Always', 'imagePullPolicy: Never' | Set-Content auth-frontend-deployment.yaml

问题 3:PVC Pending(持久化存储未绑定)

现象:

powershell

复制代码
kubectl get pvc -n camp
# NAME                STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS
# camp-database-pvc   Pending                                      default

原因分析:

  • StorageClass default 不存在

  • minikube 的 storage-provisioner 未启用

错误日志:

plain

复制代码
storageclass.storage.k8s.io "default" not found

解决方案:

方案 A:创建 StorageClass

powershell

复制代码
# 查看现有 StorageClass
kubectl get storageclass

# 创建 default StorageClass
@"
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: default
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: k8s.io/minikube-hostpath
"@ | kubectl apply -f -

方案 B:使用 minikube 自带的 standard StorageClass

修改 PVC YAML,将 storageClassName: default 改为 storageClassName: standard

方案 C:手动创建 PV(绕过动态供给)

yaml

复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: camp-database-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: default
  hostPath:
    path: /tmp/camp-database

问题 4:subPath 挂载目录到文件

现象:

powershell

复制代码
kubectl describe pod camp-backend-xxx -n camp
# Error: failed to start container "camp-backend"
# not a directory: Are you trying to mount a directory onto a file (or vice-versa)?

原因: YAML 中配置了 subPath: camp.db,但 PVC 挂载的是一个目录,不是文件。

原始配置(错误):

yaml

复制代码
volumeMounts:
  - name: database-storage
    mountPath: /app/camp.db   # ← 期望挂载为文件
    subPath: camp.db           # ← 但 PVC 是目录

解决方案:

去掉 subPath,改为挂载目录:

yaml

复制代码
volumeMounts:
  - name: database-storage
    mountPath: /app/data       # ← 改为挂载目录

注意: 这样修改后,应用的数据库路径也需要相应调整(如从 /app/camp.db 改为 /app/data/camp.db)。


问题 5:CrashLoopBackOff(容器启动后崩溃)

现象:

powershell

复制代码
kubectl get pods -n camp
# NAME              READY   STATUS             RESTARTS   AGE
# camp-backend-xxx  0/1     CrashLoopBackOff   5          10m

排查步骤:

powershell

复制代码
# 1. 查看日志
kubectl logs camp-backend-xxx -n camp

# 2. 查看详细事件
kubectl describe pod camp-backend-xxx -n camp

常见原因:

表格

原因 日志特征 解决
应用启动失败 应用错误日志 修复应用代码或配置
健康检查失败 Liveness probe failed 修改探针路径或延迟时间
资源不足 OOMKilled 增加内存限制
权限问题 Permission denied 修改文件权限或 SecurityContext

问题 6:Kustomize 补丁找不到目标

现象:

powershell

复制代码
kubectl apply -k .
# error: no matches for Id Deployment.v1.apps/camp-backend.[noNs]
# failed to find unique target for patch

原因: patchesStrategicMerge 中的 patch 没有指定 namespace,但资源在 camp 命名空间中。

解决: 给 patch 添加 namespace: camp

yaml

复制代码
patchesStrategicMerge:
  - |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: camp-backend
      namespace: camp  # ← 添加这一行

三、K8s 核心概念详解

3.1 Pod vs Container

表格

Pod Container
定义 K8s 最小调度单位 Docker 运行实例
包含 1 个或多个 Container 单个应用进程
关系 Pod 是 Container 的"外壳" Container 运行在 Pod 内
生命周期 由控制器管理(Deployment 等) 随 Pod 创建和销毁

类比: Pod 是一间公寓,Container 是公寓里的住户。


3.2 Deployment vs ReplicaSet vs Pod

plain

复制代码
Deployment(管理)
    ↓ 创建/管理
ReplicaSet(副本控制)
    ↓ 创建/管理
Pod(实际运行)

表格

资源 职责
Deployment 声明式管理应用,支持滚动更新、回滚
ReplicaSet 确保指定数量的 Pod 副本在运行
Pod 实际承载容器的运行实例

为什么需要三层?

  • Deployment 负责版本管理(更新策略)

  • ReplicaSet 负责数量控制(故障自愈)

  • Pod 负责实际运行


3.3 Service 类型对比

表格

类型 访问方式 适用场景
ClusterIP 集群内部访问(默认) 微服务之间通信
NodePort 节点 IP + 端口 外部临时访问
LoadBalancer 云厂商负载均衡器 生产环境外部访问
ExternalName DNS 别名 映射外部服务

本项目使用 ClusterIP + Ingress 的原因:

  • ClusterIP 只暴露集群内部

  • Ingress 作为统一入口,路由到不同 Service

  • 节省云厂商负载均衡器费用


3.4 ConfigMap vs Secret

表格

ConfigMap Secret
存储内容 非敏感配置(URL、日志级别) 敏感数据(密码、Token)
编码方式 明文 Base64(不是加密!)
挂载方式 环境变量或文件 环境变量或文件
安全性 中(Base64 易解码)

重要: Secret 的 Base64 只是编码,不是加密。生产环境应使用:

  • Sealed Secret

  • HashiCorp Vault

  • 云厂商 Secret Manager


3.5 PersistentVolume vs PersistentVolumeClaim vs StorageClass

plain

复制代码
StorageClass(存储模板)
    ↓ 动态创建
PersistentVolume(实际存储卷)
    ↓ 绑定
PersistentVolumeClaim(存储申请)
    ↓ 挂载
Pod(使用存储)

表格

资源 类比 职责
StorageClass 存储"套餐" 定义存储类型(SSD/HDD/本地)
PersistentVolume 实际硬盘 集群中的存储资源
PersistentVolumeClaim 购买申请 用户申请使用存储

emptyDir vs PVC:

表格

emptyDir PVC
生命周期 随 Pod 销毁 独立于 Pod
数据持久化 ❌ Pod 重启丢失 ✅ 数据保留
适用场景 临时缓存 数据库、文件存储

3.6 HPA(Horizontal Pod Autoscaler)

工作原理:

plain

复制代码
Metrics Server 采集 CPU/内存
        ↓
HPA Controller 计算需要的副本数
        ↓
Deployment 调整 ReplicaSet
        ↓
Pod 数量变化

关键参数:

表格

参数 说明
minReplicas 最小副本数(防止缩容到 0)
maxReplicas 最大副本数(防止无限扩容)
targetCPUUtilizationPercentage CPU 使用率阈值
scaleDownDelaySeconds 缩容冷却时间(默认 5 分钟)

注意: HPA 需要 Metrics Server 才能获取指标。如果显示 <unknown>,说明 Metrics Server 未安装或未就绪。


3.7 ResourceQuota vs LimitRange

表格

ResourceQuota LimitRange
作用范围 整个命名空间 单个 Pod/容器
限制对象 总资源使用量 单个容器的资源默认值
示例 命名空间最多 20 个 Pod 单个容器默认内存限制 512Mi

关系:

  • ResourceQuota = 小区总用水量限制

  • LimitRange = 每户的用水配额


四、常用命令速查

4.1 资源管理

bash

复制代码
# 查看资源
kubectl get pods -n camp                    # 查看 Pod
kubectl get deployment -n camp                # 查看 Deployment
kubectl get svc -n camp                       # 查看 Service
kubectl get pvc -n camp                       # 查看 PVC
kubectl get hpa -n camp                       # 查看 HPA
kubectl get all -n camp                       # 查看所有资源

# 查看详情
kubectl describe pod <pod-name> -n camp       # 查看 Pod 详情(排错)
kubectl logs <pod-name> -n camp               # 查看日志
kubectl logs -f deployment/camp-backend -n camp  # 持续查看日志

# 进入容器
kubectl exec -it <pod-name> -n camp -- sh     # 进入容器调试

4.2 资源操作

bash

复制代码
# 扩缩容
kubectl scale deployment camp-backend --replicas=5 -n camp

# 删除资源
kubectl delete pod <pod-name> -n camp          # 删除单个 Pod
kubectl delete deployment camp-backend -n camp # 删除 Deployment
kubectl delete namespace camp                  # 删除整个命名空间

# 端口转发
kubectl port-forward svc/camp-backend-service 8000:8000 -n camp

4.3 minikube 管理

bash

复制代码
# 启动/停止/删除
minikube start --driver=docker --memory=4096 --cpus=2
minikube stop
minikube delete

# 镜像管理
minikube image load <image-name>              # 加载本地镜像
minikube ssh -- docker images                 # 查看 minikube 中的镜像

# 插件
minikube addons enable ingress                # 启用 Ingress
minikube addons enable metrics-server         # 启用 Metrics Server
minikube addons list                          # 查看插件列表

五、部署最佳实践

5.1 部署顺序

plain

复制代码
1. Namespace(命名空间)
2. ConfigMap / Secret(配置)
3. PersistentVolumeClaim(存储)
4. Deployment(应用)
5. Service(网络暴露)
6. Ingress(入口)
7. HPA / ResourceQuota(高级功能)

5.2 排错流程

plain

复制代码
Pod 异常
  ↓
kubectl describe pod <name>  ← 看 Events
  ↓
  ├─ ImagePullBackOff → 检查镜像名、权限、imagePullPolicy
  ├─ Pending → 检查资源、节点、PVC
  ├─ CrashLoopBackOff → 查看日志、检查探针
  └─ ...

5.3 学习建议

表格

阶段 内容
第一阶段 理解 Pod、Deployment、Service 基本概念
第二阶段 掌握 ConfigMap、Secret、PVC 的使用
第三阶段 学习 Ingress、HPA、ResourceQuota
第四阶段 尝试 Helm、Kustomize 等部署工具
第五阶段 部署到云厂商 K8s(AKS/EKS/ACK)
相关推荐
前端Baymax1 小时前
K8s PodCrashLoopBackOff假阳性排查
云原生·容器·kubernetes
java_logo1 小时前
Docker Compose 部署 Apache Superset:轻松搭建开源 BI 平台
docker·开源·apache·superset·轩辕镜像·superset部署方案·docker superset
zy happy1 小时前
VMware虚拟机添加新的硬盘
java·linux·jvm·docker
hz567892 小时前
音视频技术SDK选型指南:企业实时互动场景的关键能力解析
网络·云计算·音视频·实时音视频·信息与通信
ShirleyWang0123 小时前
Day02 K3s NGF(Nginx Gateway Fabric)单 Worker 环境网关更新与故障处置 SOP
linux·服务器·python·k8s·k3s
ShirleyWang0123 小时前
DAY01 K3s 私有化部署排障复盘与 SOP
linux·服务器·k8s·k3s·企业部署
A-刘晨阳4 小时前
低配N1也能搭家庭录像中心:Go2RTC与EasyNVR双容器实战
运维·云计算·cpolar
阿标在干嘛13 小时前
从物理机到K8s:政策快报平台的容器化部署实践
云原生·容器·kubernetes
IT瑞先生15 小时前
docker-compose下快速部署实操——持续更新...
运维·docker·容器