云原生 从docker、Jenkins、Kubernetes从入门到精通系列
Kubernetes 目前支持多达 28 种数据卷类型(其中大部分特定于具体的云环境如 GCE/AWS/Azure 等),如需查阅所有的数据卷类型,请查阅 Kubernetes 官方文档 Volumes 。如:
- 非持久性存储
- emptyDir
- HostPath
- 网络连接性存储
- SAN:iSCSI、ScaleIO Volumes、FC (Fibre Channel)
- NFS:nfs,cfs
- 分布式存储
- Glusterfs
- RBD (Ceph Block Device)
- CephFS
- Portworx Volumes
- Quobyte Volumes
- 云端存储
- GCEPersistentDisk
- AWSElasticBlockStore
- AzureFile
- AzureDisk
- Cinder (OpenStack block storage)
- VsphereVolume
- StorageOS
- 自定义存储
- FlexVolume
使用命令 kubectl explain pod.spec.containers.volumeMounts 查看挂载的相关解释。
1、临时存储
1、几种临时存储
Kubernetes 为了不同的目的,支持几种不同类型的临时卷:
- emptyDir: Pod 启动时为空,存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
- configMap、 downwardAPI、 secret: 将不同类型的 Kubernetes 数据注入到 Pod 中
- CSI 临时卷: 类似于前面的卷类型,但由专门支持此特性 的指定 CSI 驱动程序提供
- 通用临时卷: 它可以由所有支持持久卷的存储驱动程序提供
2、emptyDir
使用命令kubectl explain pod.spec.volumes.emptyDir查看命令
- 当 Pod 分派到某个 Node 上时,
emptyDir卷会被创建 - 在 Pod 在该节点上运行期间,卷一直存在。
- 卷最初是空的。
- 尽管 Pod 中的容器挂载
emptyDir卷的路径可能相同也可能不同,这些容器都可以读写emptyDir卷中相同的文件。 - 当 Pod 因为某些原因被从节点上删除时,
emptyDir卷中的数据也会被永久删除。 - 存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
apiVersion: v1
kind: Pod
metadata:
name: "multi-container-pod"
namespace: default
labels:
app: "multi-container-pod"
spec:
volumes: ### 以后见到的所有名字 都应该是一个合法的域名方式
- name: nginx-vol
emptyDir: {} ### docker匿名挂载,外部创建一个位置 /abc
containers: ## kubectl exec -it podName -c nginx-container(容器名)-- /bin/sh
- name: nginx-container
image: "nginx"
volumeMounts: #声明卷挂载 -v
- name: nginx-vol
mountPath: /usr/share/nginx/html
- name: content-container
image: "alpine"
command: ["/bin/sh","-c","while true;do sleep 1; date > /app/index.html;done;"]
volumeMounts:
- name: nginx-vol
mountPath: /app
Pod里面是容器,容器无论怎样重启,不会导致卷丢失。
Pod被真正删除,会导致卷丢失,或者Pod被重新拉起(Pod超出资源限制,kubelet就会杀死Pod,如果保证副本就重新拉起,此时临时卷就没有)。
3、扩展:hostPath
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# 宿主上目录位置
path: /data
# 此字段为可选
type: Directory
apiVersion: v1
kind: Pod
metadata:
name: test-webserver
spec:
containers:
- name: test-webserver
image: k8s.gcr.io/test-webserver:latest
volumeMounts:
- mountPath: /var/local/aaa
name: mydir
- mountPath: /var/local/aaa/1.txt
name: myfile
volumes:
- name: mydir
hostPath:
# 确保文件所在目录成功创建。
path: /var/local/aaa
type: DirectoryOrCreate
- name: myfile
hostPath:
path: /var/local/aaa/1.txt
type: FileOrCreate
典型应用: 解决容器时间问题
apiVersion: v1
kind: Pod
metadata:
name: busy-box-test
namespace: default
spec:
restartPolicy: OnFailure #重启策略
containers:
- name: busy-box-test
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts: #描述容器想把自己的哪个路径进行挂载
- name: localtime
mountPath: /etc/localtime #容器内的时间路径,挂到容器的这个位置
command: ["sleep", "60000"]
volumes: #描述每个volumeMounts到底该怎么挂载
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai #上海时区
2、持久化
1、VOLUME
1、基础
- Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型
- 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长
- 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;
- Kubernetes 不会销毁 持久卷。
- 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
- 使用卷时, 在
.spec.volumes字段中设置为 Pod 提供的卷,并在.spec.containers[*].volumeMounts字段中声明卷在容器中的挂载位置。
支持的卷类型:点击这里
2、使用subPath
有时,在单个 Pod 中共享卷以供多方使用是很有用的。 volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。
3、使用NFS
1、安装NFS
# 在任意机器
yum install -y nfs-utils
# 执行以下命令,启动 nfs 服务;创建共享目录
mkdir -p /nfs/data
#执行命令 vi /etc/exports,创建 exports 文件,文件内容如下:
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
#/nfs/data 172.26.248.0/20(rw,no_root_squash)
systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server
exportfs -r
#检查配置是否生效
exportfs
# 输出结果如下所示
/nfs/data /nfs/data
2、VOLUME进行挂载测试
#测试Pod直接挂载NFS了
apiVersion: v1
kind: Pod
metadata:
name: vol-nfs
namespace: default
spec:
containers:
- name: myapp
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
nfs:
path: /nfs/data #1000G
server: 自己的nfs服务器地址
3、扩展-NFS文件同步
#服务器端防火墙开放111、662、875、892、2049的 tcp / udp 允许,否则远端客户无法连接。
#安装客户端工具
yum install -y nfs-utils
#执行以下命令检查 nfs 服务器端是否有设置共享目录
# showmount -e $(nfs服务器的IP)
showmount -e 192.168.219.130
# 输出结果如下所示
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir /root/nfsmount
# mount -t nfs $(nfs服务器的IP):/root/nfs_root /root/nfsmount
#高可用备份的方式
mount -t nfs 192.168.219.130:/nfs/data /root/nfsmount
# 写入一个测试文件
echo "hello nfs server" > /root/nfsmount/test.txt
#在 nfs 服务器上执行以下命令,验证文件写入成功
cat /root/nfsmount/test.txt
2、PV、PVC、StorageClass
使用命令 kubectl explain pv 查看pv的相关解释。
1、基础概念
- 存储的管理是一个与计算实例的管理完全不同的问题。
- PersistentVolume 子系统为用户 和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来。
- 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。
持久卷(PersistentVolume ):
- 持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者 使用存储类(Storage Class)来动态供应。
- 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于使用他们的Pod的生命周期。
- 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
持久卷申请(PersistentVolumeClaim,PVC):
- 表达的是用户对存储的请求
- 概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。
- Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。
存储类(Storage Class) :
- 尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源,常见的情况是针对不同的 问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。
- 集群管理员需要能够提供不同性质的 PersistentVolume,并且这些 PV 卷之间的差别不 仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户。
- 为了满足这类需求,就有了 存储类(StorageClass) 资源。
2、实战
实战官网演示地址:点这里
提前创好空间haha,就是在data文件夹下创建一个文件夹名为haha
创建yaml文件vi pv-10m.yaml
执行下面的yaml,并查看pv: kubectl get pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-volume-10m
labels:
type: local
spec:
storageClassName: my-nfs-storage
capacity:
storage: 10m
accessModes:
- ReadWriteOnce
nfs: ## 使用nfs存储系统
server: 192.168.219.130 # 没type
path: /nfs/data/haha # abc文件夹提前创建
使用PVC申请:
申请:
创建yaml文件vi pod-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: "nginx-pvc"
namespace: default
labels:
app: "nginx-pvc"
spec:
containers:
- name: nginx-pvc
image: "nginx"
ports:
- containerPort: 80
name: http
volumeMounts:
- name: localtime
mountPath: /etc/localtime
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: localtime
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
- name: html
persistentVolumeClaim:
claimName: nginx-pvc # 你的申请书的名字
restartPolicy: Always
编写申请书:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
namespace: default
labels:
app: nginx-pvc
spec:
storageClassName: my-nfs-storage ## 存储类的名字
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5m
上面两个文件写在一个文件中,使用---分割。
已使用的pv,状态会更改为bound。
Pod删除,申请书与PV的绑定还在。即使PVC删除了,PV的状态会变为释放Released,默认别人也不能绑定。修改回收策略可以让别人挂载。
- 如果申请空间一直没有,则会一直pending状态。
- PV被创建以后(可用的),PVC自动绑定到这个PV卷。
- 以后Pod只需要关联PVC即可。
- Pod删除,PVC还在吗?
- pvc并不会影响。手动删除pvc。
- 按照以前原则。同一个资源的所有关联东西都应该写在一个文件中,方便管理。
- PVC删除会不会影响PV?
- 要看PV的回收策略。比如nfs。回收策略是Recycle。PV不会删除,内容会被清空,PV重新变为Available。
- pvc并不会影响。手动删除pvc。
Pod-->PVC-->PV
3、细节
1、访问模式
访问模式:这里是官网
2、回收策略
回收策略:这里是官网
目前的回收策略有:
- Retain -- 手动回收:PV相关的内容,自己删除。默认规则。
- Recycle -- 基本擦除 (
rm -rf /thevolume/*):清除卷里面的内容 - Delete -- 诸如 AWS EBS 或 GCE PD 卷这类关联存储资产也被删除:PV自己也跟着删除。
目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS 和 GCE PD 卷支持删除(Delete)。
测试Delete回收策略
PV创建pv-delete.yaml,并执行:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-volume-10m-delete
labels:
type: local
spec:
persistentVolumeReclaimPolicy: Delete #删除
storageClassName: my-nfs-storage
capacity:
storage: 10m
accessModes:
- ReadWriteOnce
nfs: ## 使用nfs存储系统
server: 192.168.219.130 # 没type
path: /nfs/data/delete # abc文件夹提前创建
PVC创建pvc-10m-delete.yaml,并执行:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-10-delete
namespace: default
labels:
app: pv-10-delete
spec:
storageClassName: my-nfs-storage ## 存储类的名字
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5m
执行删除命令
kubectl delete pvc pv-10-delete,再次查看:
failed代表回收失败。
说是需要安装删除插件。官网说:仅 NFS 和 HostPath 支持回收(Recycle)。所以,NFS只能使用回收策略。
如果使用回收策略,删除过后,就是重新可用。
3、阶段
各个阶段描述:官网
每个持久卷会处于以下阶段(Phase)之一:
Available卷是一个空闲资源,尚未绑定到任何申领- PV可用。可以和任意PVC绑定。
Bound该卷已经绑定到某申领Released所绑定的申领已被删除,但是关联存储资源尚未被集群回收- PV释放。释放了和PVC的关联关系,绑定不存在。新的不同PVC不能重新绑定上来。
Failed卷的自动回收操作失败
你可以使用 kubectl describe persistentvolume <name> 查看已绑定到 PV 的 PVC 的名称。