在Kubernetes集群中运行的应用通常以Pod形式存在,而Pod本质上具有"临时性"的特点。当我们需要部署MySQL、Redis等有状态服务时,数据持久化就成为了必须解决的痛点问题。
我曾在生产环境中遇到过这样的场景:某次集群节点意外重启后,由于没有配置持久化存储,导致关键业务数据全部丢失。那次事故让我深刻认识到,理解并正确使用Kubernetes的持久化存储机制,是每个云原生工程师的必修课。
Pod的生命周期特性决定了其存储的临时性:
这些特性对于无状态应用可能影响不大,但对于数据库、文件服务等有状态应用就是灾难性的。通过持久化存储方案,我们可以确保:
EmptyDir是最基础的存储卷类型,它会在Pod所在节点上创建一个空目录,并将其挂载到Pod内的指定路径。这个目录的生命周期与Pod绑定,具有以下特点:
在实际应用中,EmptyDir适合用作:
下面是一个典型的EmptyDir使用示例:
yaml复制apiVersion: v1
kind: Pod
metadata:
name: cache-pod
spec:
containers:
- name: main-container
image: nginx
volumeMounts:
- name: cache-volume
mountPath: /var/cache/nginx
- name: sidecar-container
image: busybox
command: ["sh", "-c", "tail -f /dev/null"]
volumeMounts:
- name: cache-volume
mountPath: /tmp/cache
volumes:
- name: cache-volume
emptyDir: {}
关键配置说明:
volumes字段定义了名为cache-volume的EmptyDir卷volumeMounts挂载同一个卷到不同路径注意事项:EmptyDir默认使用节点磁盘存储,但可以通过设置
medium: Memory改为使用内存。内存模式速度更快,但需注意内存资源限制,避免影响节点稳定性。
通过以下命令可以查看EmptyDir的实际存储位置:
bash复制# 获取Pod的UID
kubectl get pod cache-pod -o jsonpath='{.metadata.uid}'
# 在节点上查看实际存储路径
ls /var/lib/kubelet/pods/<PodUID>/volumes/kubernetes.io~empty-dir/cache-volume
EmptyDir的工作机制是典型的"双向绑定":
HostPath允许将节点上的文件系统直接挂载到Pod中,相比EmptyDir具有更长的生命周期:
典型使用场景包括:
以下是一个收集节点日志的DaemonSet配置示例:
yaml复制apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: collector
image: fluentd
volumeMounts:
- name: node-logs
mountPath: /host/var/log
volumes:
- name: node-logs
hostPath:
path: /var/log
type: Directory
关键参数说明:
path:指定节点上的绝对路径type:定义路径处理方式,常用值有:
Directory:必须存在的目录DirectoryOrCreate:不存在则创建目录File:必须存在的文件FileOrCreate:不存在则创建空文件在实际使用中,我们发现HostPath有几个重要限制:
节点亲和性问题:
安全风险:
维护复杂性:
NFS(Network File System)通过将存储服务集中化,解决了HostPath的节点绑定问题:
NFS特别适合以下场景:
在部署NFS客户端前,需要先设置NFS服务器。以下是CentOS上的基本配置:
bash复制# 服务端安装
yum install -y nfs-utils rpcbind
# 创建共享目录
mkdir -p /data/volumes
chmod 777 /data/volumes
# 配置导出目录
echo "/data/volumes *(rw,no_root_squash,sync)" >> /etc/exports
# 启动服务
systemctl enable --now rpcbind nfs-server
下面是一个WordPress应用使用NFS的完整示例:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 3
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: wordpress:php7.4-apache
volumeMounts:
- name: wp-data
mountPath: /var/www/html
volumes:
- name: wp-data
nfs:
server: 192.168.1.100
path: /data/volumes/wordpress
关键配置项:
server:NFS服务器IP或主机名path:NFS服务器上的导出路径readOnly:可选,默认可读写在生产环境使用NFS时,我们总结了几点优化经验:
网络配置:
挂载参数:
rsize和wsize(通常设为8192)async模式提高写入性能timeo和retrans应对网络波动服务器优化:
| 特性 | EmptyDir | HostPath | NFS | 云存储(如EBS) | 分布式存储(如Ceph) |
|---|---|---|---|---|---|
| 生命周期 | Pod | 节点 | 持久 | 持久 | 持久 |
| 数据共享 | Pod内 | 节点内 | 跨Pod | 通常单Pod | 跨Pod |
| 迁移性 | 无 | 无 | 高 | 中等 | 高 |
| 性能 | 高 | 高 | 中等 | 高 | 可变 |
| 可靠性 | 低 | 中等 | 中等 | 高 | 高 |
| 复杂度 | 低 | 低 | 中等 | 低 | 高 |
根据我们的实践经验,建议按照以下流程选择存储方案:
数据是否需要持久化?
是否接受单节点绑定?
是否需要高性能低延迟?
是否需要多Pod共享?
对可靠性的要求?
对于企业级生产环境,我们通常会考虑更高级的存储方案:
CSI驱动:
分布式文件系统:
云原生存储方案:
在实际架构设计中,我们通常会根据业务需求组合多种存储方案。例如,将关键业务数据放在高性能分布式存储上,而将临时性数据使用EmptyDir处理。