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其实不复杂,核心就是定义路由规则:
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