3、Kubernetes存储与网络:Volume与PV/PVC持久化存储、Ingress与NetworkPolicy网络策略、Helm包管理工具

好,咱们今天聊点硬核的。存储和网络,说白了就是Kubernetes的任督二脉。我刚开始接触K8s时,觉得Pod跑起来就行,结果一搞持久化数据就翻车。你想想看,Pod挂了重建,数据全丢了,这谁受得了?

这一章,我会把存储和网络这两块掰开揉碎讲清楚。包括Volume怎么用、PV/PVC怎么配合、Ingress怎么暴露服务、NetworkPolicy怎么搞安全隔离,最后再聊聊Helm这个包管理神器。

3.1 Volume:Pod里的临时存储

先说说Volume。Kubernetes里的Volume,说白了就是Pod里的一块存储空间。它的生命周期和Pod绑定——Pod在,Volume就在;Pod删了,Volume也就没了。

我习惯把Volume分成两类:临时存储和持久存储。临时存储最常见的就是emptyDir,Pod启动时创建,Pod销毁时清空。适合干嘛?日志缓存、临时文件处理这些场景。

apiVersion: v1
kind: Pod
metadata:
  name: log-collector
spec:
  containers:
  - name: collector
    image: busybox
    command: ["sh", "-c", "while true; do echo $(date) >> /data/log.txt; sleep 5; done"]
    volumeMounts:
    - name: log-storage
      mountPath: /data
  volumes:
  - name: log-storage
    emptyDir: {}

嗯,这里要注意:emptyDir默认存在节点本地磁盘上。如果你用SSD节点,性能还不错。但Pod漂移到其他节点,数据就没了。所以生产环境,千万别拿emptyDir存重要数据。

3.2 PV与PVC:持久化存储的正确姿势

持久化存储,才是生产环境的重头戏。Kubernetes用PV(PersistentVolume)和PVC(PersistentVolumeClaim)这套抽象层来管理。

我个人理解:PV就是管理员准备好的存储资源,PVC就是用户提的存储需求申请。有点像租房——PV是房源,PVC是租客的租房需求。

核心概念:

  • PV:集群级别的存储资源,独立于Pod存在
  • PVC:用户对存储的请求,指定大小、访问模式
  • StorageClass:动态制备PV的模板,省去手动创建PV的麻烦

我在项目中遇到过一个问题:开发团队申请了10个PVC,但运维只准备了5个PV。结果有一半Pod一直Pending。后来我们改用StorageClass动态制备,再也没出过这种问题。

来看一个完整的PV/PVC示例:

# PV定义
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-001
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /data/k8s
    server: 192.168.1.100

---
# PVC定义
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-001
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi

这里有个关键点:accessModes有三种——ReadWriteOnce(单节点读写)、ReadOnlyMany(多节点只读)、ReadWriteMany(多节点读写)。选错了,Pod就挂不上。我建议你根据实际场景选:数据库用ReadWriteOnce,共享文件用ReadWriteMany。

避坑指南:我曾经在生产环境把MySQL的PV配成了ReadWriteMany,结果多个Pod同时写同一个数据文件,直接把表搞坏了。数据库这类有状态服务,老老实实用ReadWriteOnce。

3.3 Ingress:七层流量入口

聊完存储,咱们看看网络。Service是四层负载均衡,但生产环境往往需要七层路由——域名、路径转发、HTTPS终止。这时候就得用Ingress。

Ingress说白了就是一个流量入口控制器。它不像Service那样直接暴露端口,而是通过Ingress Controller(比如Nginx Ingress、Traefik)来干活。

我画了一张图,帮你理解Ingress的工作流程:

用户 请求 Ingress Controller 域名/路径匹配 Service A Service B Pod A1 Pod A2 Pod B1 Pod B2 图例:用户 → Ingress Controller(域名/路径匹配)→ Service → Pod

配置Ingress其实不复杂,核心就是定义路由规则:

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

这里有个坑:pathType有Exact(精确匹配)和Prefix(前缀匹配)两种。我建议API用Prefix,静态资源用Exact,避免路由冲突。

3.4 NetworkPolicy:Pod级别的防火墙

默认情况下,Kubernetes集群里所有Pod都能互相通信。这显然不安全。NetworkPolicy就是用来做Pod网络隔离的——说白了,就是Pod级别的防火墙。

我记得有一次安全审计,对方问:你们的数据库Pod能被前端直接访问吗?我说默认可以。对方当场就摇头。后来我们加了NetworkPolicy,只允许API Pod访问数据库,其他Pod一律拒绝。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-network-policy
spec:
  podSelector:
    matchLabels:
      app: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-server
    ports:
    - protocol: TCP
      port: 3306

重要提醒:NetworkPolicy需要CNI插件支持。如果你用Flannel,它不支持NetworkPolicy。我建议生产环境用Calico或Cilium,它们对网络策略的支持更完善。

配置NetworkPolicy有几个要点:

  • podSelector:指定策略作用的目标Pod
  • policyTypes:Ingress(入站)、Egress(出站),可以同时配置
  • from/to:允许哪些来源或目标
  • ports:允许的端口范围

我个人的习惯是:先默认拒绝所有流量,再按需放行。这样最安全,也最容易排查问题。

3.5 Helm:Kubernetes的包管理神器

最后聊聊Helm。你想想看,每次部署一个复杂应用,要写十几个YAML文件,还要管理版本、配置参数,多累啊。Helm就是来解决这个问题的。

Helm的核心概念有三个:

概念 说明 类比
Chart 应用的打包格式,包含所有K8s资源定义 apt包、yum包
Repository Chart的存储仓库 Docker Hub
Release Chart部署到集群后的运行实例 进程实例

安装Helm很简单,一条命令搞定:

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

然后你就可以用Helm部署应用了。比如部署一个Nginx:

# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami

# 安装Nginx
helm install my-nginx bitnami/nginx

# 查看Release
helm list

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

# 回滚
helm rollback my-nginx 1

经验之谈:我曾经在生产环境用Helm部署了一个复杂的微服务应用,包含20多个组件。第一次部署时参数配错了,导致整个集群资源耗尽。后来我养成了一个习惯:先用helm template生成YAML预览,确认无误再helm install

Helm最强大的地方在于模板化。你可以用Go模板语法,把配置参数抽离出来:

# values.yaml
replicaCount: 3
image:
  repository: nginx
  tag: latest
service:
  port: 80

# deployment.yaml(模板文件)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-nginx
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        ports:
        - containerPort: {{ .Values.service.port }}

这样,不同环境只需要改values.yaml就行。开发、测试、生产各一套配置,省心省力。

好了,这一章的内容就到这里。存储和网络是Kubernetes的基石,搞懂了它们,你就能应对大部分生产场景了。记住:PV/PVC解决数据持久化,Ingress搞定七层路由,NetworkPolicy保障网络安全,Helm提升部署效率。这四个工具用好了,你的K8s运维水平会上一个大台阶。


公众号:蓝海资料掘金营,微信deep3321