ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Kubernetes 存储实战:NFS PV/PVC、ConfigMap 与探针测试-002

2026/9/4 6:54:19 拓冰建站 浏览量
Kubernetes 存储实战:NFS PV/PVC、ConfigMap 与探针测试-002 TOC你提供的https://192.168.30.140:6443是 Kubernetes apiserver 的 API 接口地址本身不是可视化 Web 页面浏览器直接访问报错属于正常现象通过 kubectl 配置对应 kubeconfig 即可正常管理集群。下面基于你这套Kubernetes v1.24.17 三主两从高可用离线集群containerd 运行时 NFS 存储后端系统讲解 K8s 存储体系、有状态/无状态应用部署、Pod 探针三大核心模块所有配置均适配你的环境参数可直接部署验证。一、环境总览与前置准备1.1 集群核心参数确认项值Kubernetes 版本v1.24.17容器运行时containerd 1.6.21高可用 apiserver VIPhttps://192.168.30.140:6443节点规划3 个 Master 2 个 Worker网络插件CalicoPod 网段10.244.0.0/16Service 网段10.96.0.0/12NFS 存储服务器192.168.30.249共享路径/data/k8s1.2 全节点前置配置使用 NFS 持久化存储前所有 Master/Worker 节点必须安装 NFS 客户端否则无法挂载 NFS 卷。CentOS 7 离线环境下提前将nfs-utils及其依赖 RPM 包放入本地源后执行yum install -y nfs-utils # 验证 NFS 连通性 showmount -e 192.168.30.249正常输出应显示/data/k8s 192.168.30.0/24共享信息。二、K8s 存储体系PV、PVC 与 NFS 持久化2.1 核心概念PVPersistentVolume持久化卷是集群级别的存储资源由管理员提前创建对应后端真实存储NFS、Ceph、云盘等生命周期完全独立于 PodPod 删除后 PV 数据依然保留。PVCPersistentVolumeClaim持久化卷声明是用户对存储的需求申请容量、访问模式等。K8s 会自动寻找匹配的 PV 并完成绑定Pod 通过 PVC 间接使用存储无需关心底层存储细节。三种访问模式模式含义适用场景ReadWriteOnceRWO单节点读写挂载单机数据库、单实例应用ReadOnlyManyROX多节点只读挂载静态资源共享、配置文件分发ReadWriteManyRWX多节点同时读写挂载多实例共享日志、文件存储、Web 静态资源NFS 天然支持ReadWriteMany非常适合多 Pod 共享存储的场景。2.2 静态 PV 创建NFS 后端静态供给是离线小规模集群最常用的方式管理员提前在 NFS 上创建目录再在 K8s 中创建对应 PV。步骤1NFS 服务器创建共享目录在 NFS 服务器192.168.30.249上执行mkdir -p /data/k8s/nginx/logs /data/k8s/mysql/data chmod 777 /data/k8s/nginx/logs /data/k8s/mysql/data # 刷新NFS共享 exportfs -r步骤2创建 Nginx 日志共享 PV编写nginx-log-pv.yamlapiVersion: v1 kind: PersistentVolume metadata: name: nginx-log-pv labels: type: nfs app: nginx spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain # 保留策略PVC删除后数据不丢 nfs: server: 192.168.30.249 path: /data/k8s/nginx/logs步骤3创建 MySQL 数据 PV编写mysql-data-pv.yamlapiVersion: v1 kind: PersistentVolume metadata: name: mysql-data-pv labels: type: nfs app: mysql spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain nfs: server: 192.168.30.249 path: /data/k8s/mysql/data步骤4执行创建并验证在 Master 节点执行kubectl apply -f nginx-log-pv.yaml kubectl apply -f mysql-data-pv.yaml # 查看PV状态Available表示就绪可绑定 kubectl get pv2.3 PVC 创建与绑定PVC 通过容量、访问模式、标签筛选匹配的 PV绑定成功后状态变为Bound。Nginx 日志 PVCnginx-log-pvc.yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-log-pvc namespace: default spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi selector: matchLabels: app: nginxMySQL 数据 PVCmysql-data-pvc.yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-data-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi selector: matchLabels: app: mysql执行创建并验证绑定kubectl apply -f nginx-log-pvc.yaml kubectl apply -f mysql-data-pvc.yaml # PVC状态变为Bound即为绑定成功 kubectl get pvc kubectl get pv2.4 回收策略说明Retain保留PVC 删除后PV 和数据保留需管理员手动清理生产环境推荐Delete删除PVC 删除后PV 和数据一并删除仅适合云存储动态卷Recycle回收清空数据后 PV 重新可用已废弃三、配置管理ConfigMap 与 Secret3.1 ConfigMap非敏感配置管理ConfigMap 用于存储配置文件、环境变量等非敏感数据支持热挂载无需将配置打包进镜像。实战创建 Nginx 配置 ConfigMap编写nginx-configmap.yaml同时存放主配置和站点配置apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: # 主配置文件 nginx.conf: | user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for; sendfile on; keepalive_timeout 65; include /etc/nginx/conf.d/*.conf; } # 默认站点配置 default.conf: | server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log warn; location / { try_files $uri $uri/ 404; } # Nginx状态监控页面用于探针检测 location /status { stub_status; allow 127.0.0.1; allow 10.244.0.0/16; deny all; } }创建并验证kubectl apply -f nginx-configmap.yaml kubectl get configmap kubectl describe configmap nginx-conf3.2 Secret敏感数据管理Secret 用于存储密码、密钥、证书等敏感数据内容以 base64 编码存储权限控制更严格。实战创建 MySQL 密码 Secret通过命令行直接创建无需写 yamlkubectl create secret generic mysql-secret \ --from-literalroot-passwordRootk8s2025 \ --from-literaluser-passwordOpsk8s2025验证kubectl get secret kubectl describe secret mysql-secret注意Secret 是编码不是加密生产环境建议配合 RBAC 权限控制或使用外部密钥管理系统Vault 等。四、实战部署有状态 Nginx 应用StatefulSet4.1 StatefulSet 与有状态应用StatefulSet 是 K8s 专为有状态应用设计的控制器核心特性稳定的网络标识Pod 名称固定有序nginx-0、nginx-1、nginx-2通过固定 DNS 域名访问稳定的持久化存储每个 Pod 对应独立 PVCPod 重启/重建后数据不丢失有序部署与扩缩容按序号依次启动/停止适合有依赖关系的应用有序滚动更新从后往前逐个更新保证服务连续性Nginx 作为有状态应用的典型场景多实例统一配置、日志持久化收集、固定节点灰度发布。4.2 完整部署 YAML编写nginx-statefulset.yaml整合Headless Service ConfigMap 配置挂载 NFS 持久化日志# Headless ServiceStatefulSet 必备用于Pod域名解析不分配ClusterIP apiVersion: v1 kind: Service metadata: name: nginx-headless labels: app: nginx spec: selector: app: nginx clusterIP: None ports: - port: 80 name: http --- apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx spec: serviceName: nginx-headless # 绑定Headless Service replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25.3 imagePullPolicy: IfNotPresent # 离线环境优先使用本地镜像 ports: - containerPort: 80 name: http volumeMounts: # 挂载ConfigMap中的主配置文件 - name: nginx-conf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf # 挂载ConfigMap中的站点配置 - name: nginx-conf mountPath: /etc/nginx/conf.d/default.conf subPath: default.conf # 挂载持久化日志目录 - name: nginx-log mountPath: /var/log/nginx volumes: - name: nginx-conf configMap: name: nginx-conf # 卷声明模板为每个Pod自动创建独立PVC volumeClaimTemplates: - metadata: name: nginx-log spec: accessModes: [ReadWriteMany] resources: requests: storage: 5Gi selector: matchLabels: app: nginx离线环境注意提前将nginx:1.25.3镜像导入所有节点的 containerd或修改为私有镜像仓库地址。4.3 部署与有状态特性验证# 部署应用 kubectl apply -f nginx-statefulset.yaml # 查看StatefulSet和Pod kubectl get statefulset kubectl get pods -o wide验证1固定 Pod 名称与有序启动Pod 名称固定为nginx-0、nginx-1、nginx-2按序号依次启动重启后名称不变。验证2稳定 DNS 域名集群内部可通过nginx-0.nginx-headless.default.svc.cluster.local直接访问指定 Pod这是 StatefulSet 的核心标识。验证3数据持久化# 进入nginx-0写入测试日志 kubectl exec -it nginx-0 -- bash -c echo statefulset test log /var/log/nginx/access.log # 删除PodStatefulSet会自动重建 kubectl delete pod nginx-0 # 等待重建完成后验证日志依然存在 kubectl exec -it nginx-0 -- tail /var/log/nginx/access.log五、实战部署无状态 MySQL 应用Deployment5.1 Deployment 与无状态应用无状态应用通过 Deployment 部署核心特点Pod 名称随机生成重启后变化所有 Pod 完全对等无启动依赖和顺序要求扩缩容灵活可任意调整副本数默认不绑定持久化存储Pod 重建后数据丢失说明MySQL 本质是有状态数据库生产环境强烈建议用 StatefulSet 独立持久化存储部署。此处用 Deployment 演示无状态应用的部署逻辑仅用于学习测试。5.2 完整部署 YAML编写mysql-deployment.yaml整合ClusterIP Service Secret 密码注入# MySQL 服务集群内访问 apiVersion: v1 kind: Service metadata: name: mysql spec: selector: app: mysql type: ClusterIP ports: - port: 3306 targetPort: 3306 --- apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0.36 imagePullPolicy: IfNotPresent env: # 从Secret读取root密码 - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password # 创建普通业务用户 - name: MYSQL_USER value: opsuser - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: user-password # 初始化默认数据库 - name: MYSQL_DATABASE value: opsdb ports: - containerPort: 3306 name: mysql # 无状态演示不挂载持久化存储数据仅存在容器内5.3 部署与无状态特性验证# 部署 kubectl apply -f mysql-deployment.yaml # 查看Pod kubectl get pods -l appmysql验证1数据库连接测试启动临时 MySQL 客户端进行连接测试kubectl run mysql-client --rm -it --imagemysql:8.0.36 -- bash # 进入客户端后连接MySQL服务 mysql -h mysql -uroot -pRootk8s2025 show databases; exit;验证2无状态数据丢失特性# 先创建一张测试表 kubectl run mysql-client --rm -it --imagemysql:8.0.36 -- \ mysql -h mysql -uroot -pRootk8s2025 -e use opsdb; create table test(id int); insert into test values(1); select * from test; # 删除PodDeployment会自动重建 kubectl delete pod -l appmysql # 等待重建后再次查询测试表消失数据丢失 kubectl run mysql-client --rm -it --imagemysql:8.0.36 -- \ mysql -h mysql -uroot -pRootk8s2025 -e use opsdb; show tables;5.4 扩展给 MySQL 加上持久化存储如果要实现数据不丢失在 Deployment 中挂载前面创建的 PVC 即可# 在containers中添加 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql # 在spec.template.spec中添加 volumes: - name: mysql-data persistentVolumeClaim: claimName: mysql-data-pvc六、Pod 探针详解与实战测试6.1 三种探针的作用与区别K8s 通过探针检测容器健康状态实现故障自动恢复和流量精准控制是保障服务可用性的核心机制。探针类型核心作用失败触发行为livenessProbe存活探针检测容器是否正常运行连续失败 →重启容器readinessProbe就绪探针检测容器是否能对外提供服务连续失败 → 将 Pod 从 Service 端点中移除停止转发流量startupProbe启动探针检测容器是否启动完成成功后才激活存活/就绪探针解决慢启动应用被误杀的问题6.2 三种探测方式httpGet发送 HTTP GET 请求返回 200~399 状态码视为成功适合 Web 应用tcpSocket尝试建立 TCP 连接连接成功视为成功适合数据库、中间件exec在容器内执行命令退出码为 0 视为成功最灵活支持自定义逻辑6.3 探针通用配置参数参数含义默认值initialDelaySeconds容器启动后延迟多久开始探测0periodSeconds探测间隔时间10stimeoutSeconds单次探测超时时间1sfailureThreshold连续失败多少次触发动作3 次successThreshold失败后连续成功多少次恢复1 次6.4 实战给 Nginx 配置探针修改nginx-statefulset.yaml在 containers 中加入存活和就绪探针containers: - name: nginx image: nginx:1.25.3 ports: - containerPort: 80 name: http # 存活探针检测Nginx进程是否存活 livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3 # 就绪探针检测服务是否可用 readinessProbe: httpGet: path: /status port: 80 initialDelaySeconds: 3 periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 2更新部署kubectl apply -f nginx-statefulset.yaml测试存活探针故障自动重启# 手动停止Nginx进程 kubectl exec -it nginx-0 -- nginx -s stop # 实时观察Pod状态几秒后会自动重启RESTARTS计数1 kubectl get pods -w测试就绪探针故障自动摘流修改 ConfigMap 把/status路径配置错误滚动更新后观察kubectl get pods # READY列会变成0/1表示未就绪 kubectl describe svc nginx-headless # Endpoints中会移除未就绪的Pod流量不再转发6.5 实战给 MySQL 配置探针修改mysql-deployment.yaml加入启动探针 存活探针 就绪探针containers: - name: mysql image: mysql:8.0.36 env: ... ports: - containerPort: 3306 # 启动探针MySQL启动慢先等待启动完成 startupProbe: tcpSocket: port: 3306 initialDelaySeconds: 15 periodSeconds: 5 failureThreshold: 30 # 最多等待150秒启动 # 存活探针检测MySQL进程是否正常 livenessProbe: exec: command: - mysqladmin - ping - -uroot - -pRootk8s2025 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3 # 就绪探针检测数据库是否可读写 readinessProbe: exec: command: - mysql - -uroot - -pRootk8s2025 - -e - SELECT 1; periodSeconds: 5 timeoutSeconds: 2 failureThreshold: 2更新部署并查看状态kubectl apply -f mysql-deployment.yaml kubectl describe pod $(kubectl get pods -l appmysql -o jsonpath{.items[0].metadata.name})6.6 探针最佳实践Web 应用优先用httpGet真实模拟用户请求数据库优先用tcpSocket做存活检测exec做就绪检测启动慢的应用必须加startupProbe防止应用未启动完被误杀就绪探针标准可以比存活探针更严格探针逻辑要轻量避免执行复杂操作导致超时七、常见问题排错指南7.1 PV/PVC 一直 Pending检查 PV 与 PVC 的容量、访问模式是否匹配检查selector标签是否对应所有节点确认安装nfs-utils手动测试 NFS 挂载mount -t nfs 192.168.30.249:/data/k8s /mnt7.2 Pod 一直 ContainerCreating执行kubectl describe pod Pod名称查看事件常见原因离线环境镜像不存在 / 镜像拉取失败ConfigMap / Secret 名称错误不存在PVC 未成功绑定挂载超时7.3 探针持续失败进入容器手动执行探测命令 / 访问探测 URL检查端口是否正确容器内防火墙是否拦截适当调大initialDelaySeconds给应用足够启动时间