第八部分 kubernetes之 存储卷
脱离节点而存在共享存储。
存储卷不属于容器,他属于pod
缓存,宿主机,不具备真正意义上存储,宿主机退役后,存储资源随之丢失,除非宿主机上也挂载独立的卷信息。
容器真正意义上的存储卷类型
emptyDir:pod删除,存储内容也删除,只能当临时存储空间或缓存使用,无真正意义上持久性
hostPath:在宿主机上挂载一个目录,宿主机单点故障,无真正意义上持久性
网络存储:
传统存储:
SAN:iSCSI,...
NAS:nfs、cifs
分布式存储:
glusterfs,rbd,cephfs
云存储:
EBS、Azure Disk、
任何存储服务,关键数据一定要做好异地备份。
存储类别:存储卷级别,存储要求高低分配。
容器怎么使用存储卷:pod上面定义volume(指明挂载哪个存储)->容器上挂载存储卷(volumeMounts)
定义pod容器挂载
1、emptyDir操作
[root@k8s-master ~]# kubectl explain pods.spec.volumes.emptyDir
[root@k8s-master volumes]# cat pod-vol-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-demo
namespace: default
labels:
app: myapp
tier: frontend
annotations:
k8s.mastet/create-by: "sunny wei"
spec:
containers:
- image: ikubernetes/myapp:v1
name: myapp
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
- image: busybox:latest
name: busybox
volumeMounts:
- name: html
mountPath: /data
command:
- "/bin/sh"
- "-c"
- "while true;do echo $(date) >> /data/index.html;sleep 1;done;"
nodeSelector:
disktype: ssd
volumes:
- name: html
emptyDir: {}
[root@k8s-master volumes]# kubectl create -f pod-vol-demo.yaml
pod/pod-vol-demo created
[root@k8s-master volumes]# kubectl get pods pod-vol-demo
NAME READY STATUS RESTARTS AGE
pod-vol-demo 2/2 Running 0 25s
[root@k8s-master volumes]# kubectl describe pods pod-vol-demo
Name: pod-vol-demo
Namespace: default
Priority: 0
PriorityClassName: <none>
...
当pod当中有多个容器运行时,需要describe定位是哪个容器,避免不必要的排查异常。
[root@k8s-master volumes]# kubectl get pods pod-vol-demo -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-vol-demo 2/2 Running 0 2m30s 10.244.1.3 k8s-node1 <none> <none>
[root@k8s-master volumes]# curl 10.244.1.3
Wed Jul 12 14:19:39 UTC 2023
...
进入pod容器内查看,
[root@master volumes]# kubectl exec -it myapp -c myapp -- /bin/sh
[root@k8s-master volumes]# kubectl exec -it pod-vol-demo -c busybox -- tail -2 /data/index.html
Wed Jul 12 14:25:23 UTC 2023
Wed Jul 12 14:25:24 UTC 2023
[root@k8s-master volumes]# kubectl exec -it pod-vol-demo -c myapp -- tail -2 /usr/share/nginx/html/index.html
Wed Jul 12 14:19:39 UTC 2023
Wed Jul 12 14:19:40 UTC 2023
这个方式是把存储临时放到docker对应的宿主机上进行存储。登录宿主机查看
[root@k8s-node1 ~]# docker ps |grep k8s_myapp_pod
[root@k8s-node1 ~]# docker inspect cb81760edd07
[root@k8s-node1 ~]# tail -2 /var/lib/kubelet/pods/0dba96e1-20bf-11ee-afb0-000c29250b06/volumes/kubernetes.io~empty-dir/html/index.html
Wed Jul 12 14:32:47 UTC 2023
Wed Jul 12 14:32:48 UTC 2023
上面示例证明,同一个存储卷,可以在同一个pod内多个容器之间使用。
gitRepo仓库,将数据存储在仓库,对应宿主机需要有git操作能力。本质上也是emptyDir方式。
仓库有数据更新,pod运行过程中不会主动去同步仓库数据,只在拉取镜像数据过程会同步数据。
为解决难点,可以借助运行两个容灾,一个主,一个辅助(定时更新仓库镜像)容器。
还有,他不能把修改的内容及时推到仓库,pod重建后,会丢失。
2、hostPath存储卷
hostPath:pod删除重建后,宿主机上数据依然存在,pod也会获取到。
不足的是,节点宿主机宕机,数据会丢失。
[root@k8s-master ~]# kubectl explain pod.spec.volumes.hostPath
每个节点创建目录和文件
[root@k8s-node1 ~]# mkdir -p /data/pod/volume1 &&echo "node1.mage.com">/data/pod/volume1/index.html
[root@k8s-node2 ~]# mkdir -p /data/pod/volume1 &&echo "node2.mage.com">/data/pod/volume1/index.html
[root@k8s-master volumes]# cat pod-hostpath-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-hostpath
namespace: default
spec:
containers:
- image: ikubernetes/myapp:v1
name: myapp
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
hostPath:
path: /data/pod/volume1
type: DirectoryOrCreate
[root@k8s-master volumes]# kubectl create -f pod-hostpath-demo.yaml
pod/pod-vol-hostpath created
[root@k8s-master volumes]# kubectl get pods pod-vol-hostpath -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-vol-hostpath 1/1 Running 0 26s 10.244.1.5 k8s-node1 <none> <none>
[root@k8s-master volumes]#
[root@k8s-master volumes]# kubectl get pods pod-vol-hostpath -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-vol-hostpath 1/1 Running 0 28s 10.244.1.5 k8s-node1 <none> <none>
[root@k8s-master volumes]# curl 10.244.1.5
node1.mage.com
[root@k8s-master volumes]# kubectl delete -f pod-hostpath-demo.yaml # 删除重建后,数据没有丢失
pod "pod-vol-hostpath" deleted
[root@k8s-master volumes]# kubectl create -f pod-hostpath-demo.yaml
pod/pod-vol-hostpath created
[root@k8s-master volumes]# kubectl get pods pod-vol-hostpath -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-vol-hostpath 1/1 Running 0 48s 10.244.2.42 k8s-node2 <none> <none>
[root@k8s-master volumes]# curl 10.244.2.42
node2.mage.com
自此,完成hostpath主机共享存储,主机down之后,数据丢失。
3、采用nfs存储,实现存储共享。
各节点确保有mount命令,都需要安装相关命令
部署nfs存储服务
[root@stor ~]# mkdir -p /data/volumes
[root@stor ~]# yum install nfs-utils -y
[root@stor ~]# echo "<h1>NFS stor01</h1>">/data/volumes/index.html
[root@stor ~]# echo "/data/volumes 192.168.1.0/24(rw,no_root_squash)" >>/etc/exports
[root@stor ~]# systemctl restart nfs
[root@stor ~]# showmount -e 127.0.0.1
Export list for 127.0.0.1:
/data/volumes 192.168.1.0/24
客户端查看可挂载情况
[root@k8s-node2 ~]# showmount -e 192.168.1.203
Export list for 192.168.1.203:
/data/volumes 192.168.1.0/24
容器部署nfs卷服务
[root@k8s-master volumes]# cat pod-nfs-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nfs-demo
namespace: default
spec:
containers:
- image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
name: myapp
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
path: /data/volumes
server: 192.168.1.203
[root@k8s-master volumes]# kubectl create -f pod-nfs-demo.yaml
pod/pod-nfs-demo created
[root@k8s-master volumes]# kubectl get pod pod-nfs-demo -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nfs-demo 1/1 Running 0 25s 10.244.1.6 k8s-node1 <none> <none>
[root@k8s-master volumes]# curl 10.244.1.6
<h1>NFS stor01</h1>
删除pod重建也可以正常访问。
验证nfs使用情况:Mount挂载,容器服务检测,挂载有效。
使用nfs存储需要将存储信息和目录固定指定,不能动态创建存储结构。
4、pvc存储卷
生产和消费模型:如吃芹菜,不需要自己去种,想吃的时候直接去购买即可。
如下图形架构,
pvc跟pv上面的数据绑定,图
存储管理员配置共享存储
[root@stor ~]# mkdir -pv /data/volumes/{v1,v2,v3,v4,v5}
[root@stor ~]# cat /etc/exports
/data/volumes 192.168.1.0/24(rw,no_root_squash)
/data/volumes/v1 192.168.1.0/24(rw,no_root_squash)
/data/volumes/v2 192.168.1.0/24(rw,no_root_squash)
/data/volumes/v3 192.168.1.0/24(rw,no_root_squash)
/data/volumes/v4 192.168.1.0/24(rw,no_root_squash)
/data/volumes/v5 192.168.1.0/24(rw,no_root_squash)
[root@stor ~]# systemctl restart nfs
[root@stableor ~]# showmount -e 192.168.1.203
Nfs服务部署完毕,以此作为存储,在其上部署PV。
创建pv服务
[root@k8s-master volumes]# cat !$
cat pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume
...
[root@k8s-master volumes]# kubectl create -f pv-nfs.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
[root@k8s-master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 2Gi RWO,RWX Retain Available 16s
pv002 5Gi RWO Retain Available 15s
pv003 20Gi RWO,RWX Retain Available 15s
pv004 10Gi RWO,RWX Retain Available 15s
pv005 10Gi RWO,RWX Retain Available 15s
自此,三个PV完成部署,创建一个PVC服务。
[root@k8s-master volumes]# cat pod-vol-pvc.yaml
[root@k8s-master volumes]# kubectl create -f pod-vol-pvc.yaml
persistentvolumeclaim/mypvc created
pod/pod-vol-pvc created
[root@k8s-master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 2Gi RWO,RWX Retain Available 14m
pv002 5Gi RWO Retain Available 14m
pv003 20Gi RWO,RWX Retain Bound default/mypvc 14m
pv004 10Gi RWO,RWX Retain Released default/mypvc 14m
pv005 10Gi RWO,RWX Retain Released default/mypvc 14m
[root@k8s-master volumes]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound pv003 20Gi RWO,RWX 63s
[root@k8s-master ~]# kubectl describe pods pod-vol-pvc
一般删除pod,不会删除pvc删除,pvc不属于节点,他是标准的k8s资源,在etcd上运行。
只要etcd正常,pvc就没有问题,只有pod在节点上运行,其他资源数据都保存在etcd里面。不要主动删除pvc,删除pvc,pv里面的数据取决于pvc回收策略。
早期版本k8s有bug,可以直接删除pv,新版本不能直接删除pv,只要有绑定的pvc,就不支持删除pv。
建议使用有状态存储的pod做测试,看数据是否丢失。