基本存储类型
EmptyDir
- 描述:当 Pod 被调度到节点上时,Kubernetes 会为 Pod 创建一个空目录,所有在该 Pod 中的容器都可以访问这个目录。
- 特点:
- 生命周期与 Pod 绑定,Pod 删除时,数据也会丢失。
- 适用于临时存储需求,如缓存或临时计算数据。
- 支持多种存储类型(如
tmpfs
)可以根据需求选择。
HostPath
- 描述:将主机节点上的文件或目录挂载到 Pod 中的容器内。
- 特点:
- 允许 Pod 访问宿主机的文件系统。
- 数据存储在节点上,如果 Pod 被调度到不同的节点上,数据不可用。
- 适用于单节点集群或测试环境中,不推荐在生产环境中使用。
- 存在潜在的安全风险,因为容器可以访问宿主机的文件系统。
NFS
- 描述:网络存储解决方案将存储分布到多个节点或机器,Kubernetes 可以使用这些存储系统作为 PV 后端。
- 特点:
- 提供集群级别的共享存储,支持多个 Pod 挂载相同的卷。
- 适用于需要共享数据的应用,如分布式数据库。
- 支持高可用性、数据复制、故障恢复等功能。
- 需要额外的配置和管理,通常适用于大型分布式应用或企业级场景。
EmptyDir详解
EmptyDir 是一种轻量级的存储选项,用于 Pod 内部容器之间的数据共享或临时存储。下面是一些关于 EmptyDir 的补充信息:
-
生命周期:EmptyDir 的生命周期与 Pod 绑定。当 Pod 被创建时,EmptyDir 被创建并挂载到 Pod 中所有需要它的容器上。当 Pod 被删除时,EmptyDir 及其内容也会被删除。
-
使用场景:
-
临时存储:对于需要临时写入和读取数据,但不要求数据持久化的场景,如缓存或会话数据。
-
容器间数据共享:当 Pod 中运行多个容器需要共享文件时,EmptyDir 可以作为一个共享存储空间。
-
数据处理:在数据被处理并存储到更持久的存储解决方案之前,可以临时存储在 EmptyDir 中。
-
-
性能:EmptyDir 存储的性能通常与宿主机的磁盘性能相当,因为它直接存储在宿主机上。
-
限制:由于 EmptyDir 与 Pod 的生命周期绑定,因此它不适合存储需要跨 Pod 持久化的数据。此外,EmptyDir 不保证数据的备份或复制,所以在 Pod 重启或重建时数据可能会丢失。
-
配置:EmptyDir 可以通过 Pod 定义中的
spec.volumes
字段来配置,无需指定宿主机上的路径。 -
安全性:EmptyDir 默认只对 Pod 内部的容器可见,提供了一定程度的隔离。
在一个Pod中准备两个容器nginx和busybox,然后声明一个Volume分别挂在到两个容器的目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读到控制台。
[root@k8s-master ~]# vim volume-emptydir.yaml
[root@k8s-master ~]# kubectl apply -f volume-emptydir.yaml
Error from server (NotFound): error when creating "volume-emptydir.yaml": namespaces "test" not found
[root@k8s-master ~]# kubectl create ns test
namespace/test created
[root@k8s-master ~]# kubectl apply -f volume-emptydir.yaml
pod/volume-emptydir created
[root@k8s-master ~]# kubectl get pod -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-emptydir 0/2 ContainerCreating 0 35s <none> k8s-node1 <none> <none>
[root@k8s-master ~]# kubectl get pod -n test -w
NAME READY STATUS RESTARTS AGE
volume-emptydir 0/2 ContainerCreating 0 40s
volume-emptydir 2/2 Running 0 56s
^C[root@k8s-master ~]# kubectl exec -it volume-emptydir -n test /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
Defaulted container "nginx" out of: nginx, busybox
root@volume-emptydir:/# echo 'This is EmptyDir test' > /usr/share/nginx/html/index.html
root@volume-emptydir:/# exit
exit
[root@k8s-master ~]# kubectl get pod -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-emptydir 2/2 Running 0 80s 10.244.36.81 k8s-node1 <none> <none>
[root@k8s-master ~]# curl 10.244.36.81
This is EmptyDir test
[root@k8s-master ~]# kubectl logs -f volume-emptydir -n test -c busybox
10.244.235.192 - - [25/Jan/2025:09:39:19 +0000] "GET / HTTP/1.1" 200 22 "-" "curl/7.29.0" "-"
10.244.235.192 - - [25/Jan/2025:09:39:40 +0000] "GET / HTTP/1.1" 200 22 "-" "curl/7.29.0" "-"
10.244.235.192 - - [25/Jan/2025:09:39:41 +0000] "GET / HTTP/1.1" 200 22 "-" "curl/7.29.0" "-"
通过curl命令进行访问,可以看到访问成功的日志信息;
HostPath详解
-
EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。
-
HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。
-
数据持久性:与
EmptyDir
不同,HostPath
卷将 Node 主机上的一个目录挂载到 Pod 中,使得 Pod 内的容器可以访问和修改该目录上的文件。由于这些文件存储在 Node 主机上,因此即使 Pod 被删除,数据仍然可以在 Node 主机上保持。 -
用途:
HostPath
适用于需要持久化数据的场景,例如数据库文件、配置文件等。然而,由于HostPath
直接使用了 Node 主机的文件系统,可能会带来一些安全和管理上的挑战,例如权限管理、数据一致性等问题。
-
[root@k8s-master ~]# vim volume-hostpath.yaml
[root@k8s-master ~]# kubectl apply -f volume-hostpath.yaml
pod/volume-hostpath created
[root@k8s-master ~]# kubectl get pod -n test -w
NAME READY STATUS RESTARTS AGE
volume-emptydir 2/2 Running 0 9m26s
volume-hostpath 2/2 Running 0 6s
^C[root@k8s-master ~]# kubectl describe pod volume-hostpath -n test
Name: volume-hostpath
Namespace: test
Priority: 0
Node: k8s-node1/192.168.58.232
Start Time: Sat, 25 Jan 2025 04:47:14 -0500
Labels: <none>
Annotations: cni.projectcalico.org/containerID: 12d55de1744ff89a73d0fb3c4f9cf45427847f3ca631f130147e2a41b9916c53cni.projectcalico.org/podIP: 10.244.36.82/32cni.projectcalico.org/podIPs: 10.244.36.82/32
Status: Running
IP: 10.244.36.82
IPs:IP: 10.244.36.82
Containers:nginx:Container ID: docker://c0c42dab2b85a9d336abcba543be34740ce44c19453d41435882cc4e356ea18eImage: nginx:1.17.1Image ID: docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbbPort: 80/TCPHost Port: 0/TCPState: RunningStarted: Sat, 25 Jan 2025 04:47:16 -0500Ready: TrueRestart Count: 0Environment: <none>Mounts:/var/log/nginx from logs-volume (rw)/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bqnr4 (ro)busybox:Container ID: docker://ee04657f326faa26619d0ffe9acb277885aa792737aed9d3e343c570d17ff0a8Image: busybox:1.30Image ID: docker-pullable://busybox@sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3dPort: <none>Host Port: <none>Command:/bin/sh-ctail -f /logs/access.logState: RunningStarted: Sat, 25 Jan 2025 04:47:16 -0500Ready: TrueRestart Count: 0Environment: <none>Mounts:/logs from logs-volume (rw)/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bqnr4 (ro)
Conditions:Type StatusInitialized True Ready True ContainersReady True PodScheduled True
Volumes:logs-volume:Type: HostPath (bare host directory volume)Path: /root/logsHostPathType: DirectoryOrCreatekube-api-access-bqnr4:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 25s default-scheduler Successfully assigned test/volume-hostpath to k8s-node1Normal Pulled 23s kubelet Container image "nginx:1.17.1" already present on machineNormal Created 23s kubelet Created container nginxNormal Started 23s kubelet Started container nginxNormal Pulled 23s kubelet Container image "busybox:1.30" already present on machineNormal Created 23s kubelet Created container busyboxNormal Started 23s kubelet Started container busybox
[root@k8s-master ~]# kubectl get pod -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-emptydir 2/2 Running 0 10m 10.244.36.81 k8s-node1 <none> <none>
volume-hostpath 2/2 Running 0 98s 10.244.36.82 k8s-node1 <none> <none>
describe中看的pod调度到node1节点,在master节点执行curl进行访问,到node1节点下查看是否存在/root/logs目录,并查看日志信息:
[root@k8s-node1 ~]# ll /root/logs/
total 4
-rw-r--r--. 1 root root 95 Jan 25 04:49 access.log
-rw-r--r--. 1 root root 0 Jan 25 04:47 error.log[root@k8s-node1 ~]# tail -f /root/logs/access.log
10.244.235.192 - - [25/Jan/2025:09:49:00 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.244.235.192 - - [25/Jan/2025:09:49:48 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
NFS
-
虽然
HostPath
可以用于解决数据持久化的问题,但它并不适用于跨节点的数据共享和高可用性场景。一旦 Pod 从一个节点迁移到另一个节点,HostPath
卷中的数据就无法访问。这是因为HostPath
卷依赖于特定节点上的文件系统,而不是一个独立的网络存储系统。 -
为了解决这个问题,确保数据在节点迁移时仍然可用,通常推荐使用网络文件存储系统,如 NFS (Network File System) 或 CIFS (Common Internet File System)。这两种协议允许 Pod 访问远程存储系统上的数据,就好像它们是本地文件一样。
-
NFS 是一种网络文件系统协议,它允许客户端计算机访问服务器上的文件和目录,就像它们是本地文件一样。通过设置 NFS 服务器,您可以将 Pod 中的存储直接连接到 NFS 系统上。这样,即使 Pod 从一个节点迁移到另一个节点,只要网络连接正常,Pod 就可以继续访问数据。
需要在每个机器上都安装NFS
yum install nfs-utils -y
[root@k8s-master ~]# mkdir /nfstest
[root@k8s-master ~]# vim /etc/exports
[root@k8s-master ~]# systemctl restart rpcbind.service nfs-server.service[root@k8s-master ~]# vim volume-nfs.yaml
[root@k8s-master ~]# kubectl apply -f volume-nfs.yaml
pod/volume-nfs created
[root@k8s-master ~]# kubectl get pod -n test -w
NAME READY STATUS RESTARTS AGE
volume-nfs 0/2 ContainerCreating 0 2s
volume-nfs 0/2 ContainerCreating 0 3s
volume-nfs 2/2 Running 0 3s
^C[root@k8s-master ~]kubectl get pod -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-nfs 2/2 Running 0 16s 10.244.36.88 k8s-node1 <none> <none>
[root@k8s-master ~]# cd /nfstest/
[root@k8s-master nfstest]# ll
total 4
-rw-r--r--. 1 root root 95 Jan 25 05:18 access.log
-rw-r--r--. 1 root root 0 Jan 25 05:18 error.log
[root@k8s-master nfstest]# tai -f access.log
-bash: tai: command not found
[root@k8s-master nfstest]# tail -f access.log
10.244.235.192 - - [25/Jan/2025:10:18:20 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.244.235.192 - - [25/Jan/2025:10:18:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
在node1和node2节点执行如下命令:
[root@k8s-node1 ~]# showmount -e 192.168.58.231
Export list for 192.168.58.231:
/nfstest 192.168.58.0/24
在master节点使用curl命令进行测试,查看master节点/nfstest目录下是否存在访问日志:
[root@k8s-master ~]# curl 10.244.36.88
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8s-master nfstest]# tail -f access.log
10.244.235.192 - - [25/Jan/2025:10:18:20 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
10.244.235.192 - - [25/Jan/2025:10:18:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"