存储卷
SAN:iSCSI,
NAS:nfs,cifs,http
分布式存储:glusterfs,rbd(ceph),cephfs
云存储:EBS,Azure Disk,
储存方式:emptyDir,hostPath
Volumes:卷
Persistent Volumes:持久卷(pvc)
Volume Snapshots
CSI Volume Cloning
Storage Classes:存储类
存储卷常用类型
非持久性存储
emptyDir
hostPath
网络连接性存储
SAN:iSCSI
NFS:nfs,cfs
分布式存储
glusterfs、rbd、cephfs
云端存储
EBS、Azure Disk、阿里云、gitRepo
https://www.cnblogs.com/caibao666/p/11268826.html
1 emptyDir
在节点上运行pod实例时才会创建emptyDir volume。它首先是节点上的一个空目录,pod中的任何容器都可以用volume的形式挂载使用它。如果容器因为某种原因被删除并重新启动,创建的emptyDir不会删除也不会被清空。当pod实例离开节点调度到其它节点或因为缩容被删除时,emptyDir被删除,相当于pod还在但数据丢了
常用于作为临时目录、或缓存使用。
medium:此目录所在的存储介质的类型,可取值为default或Memory,默认default,表示使用节点的默认存储介质;Memory表示使用基于ram的临时文件系统
tmpfs:空间受限于内存,但性能非常好,通常用于为容器中的应用提供缓存空间。
sizeLimit:当前存储卷的空间限额,默认值为nil,表示不限制;在medium字段值为Memory时,建议务必定义此限额。
# kubectl explain pods.spec.volumes
# vi pod-volumes-demo.yaml
apiVsersion: v1
kind: Pod
metadata:
name: pod-volumes
namespace: default
labels:
app: myapp
tier: frontend
annotations:
cluster.com/created-by: "cluster domain"
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
volumeMounts:
- name: html
mountPath: /data/web/html
- name: busybox
image: busybox:latest
imagePolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data
command:
- "/bin/bash"
- "-C"
- "echo $(data) >> /data/index.htnl"
volumes:
- name: html
emptyDir: {}
# kubectl exec -it pod-demo {myapp,busybox} -- /bin/sh #都可以看到index.html
------------
# vi pod-volumes-demo.yaml
apiVsersion: v1
kind: Pod
metadata:
name: pod-volumes
namespace: default
labels:
app: myapp
tier: frontend
annotations:
cluster.com/created-by: "cluster domain"
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
volumeMounts:
- name: html
mountPath: /data/web/html
volumes:
- name: html
emptyDir: {}
2 使用hostPath
https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
这种类型的卷将文件或目录从宿主机节点的文件系统挂载到您的Pod中,当pod删除时,本地仍然保留文件
type:
值为空:空字符串(默认)用于向后兼容,这意味着在安装hostPath卷之前不会执行任何检查。
DirectoryOrCreate: 如果给定路径中不存在任何内容,则将根据需要创建一个空目录,权限设置为0755,与Kubelet具有相同的组和所有权。
Directory: 目录必须存在于给定路径中
FileOrCreate:如果给定路径中不存在任何内容,则会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。
File:文件必须存在于给定路径中
Socket:UNIX套接字必须存在于给定路径中
CharDevice:字符设备必须存在于给定路径中
BlockDevice:块设备必须存在于给定路径中
# vi pod-hostpath-volumes.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-volumes-hostpath
namespace: default
spec:
containers:
- name: myapp
image: ikuebernetes/myapp:v1
voloumesMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
hostPath:
path: /data/pod/volumes
type: DirectoryOrCreate
# mkdir /data/pod/volumes
# kubectl apply -f pod-hostpath-volumes.yaml
3 使用共享存储:nfs:
NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。Pod被删除时,Volume被卸载,内容被保留。这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递。
有nfs存储,各节点挂载nfs
# yum -y install nfs-utils
# vi /etc/exports
/data/volumes 172.20.0.0/16(rw,no_root_squash)
# systemctl start nfs
# showmount -e nfs-机器ip
节点上挂载:
# mount -t nfs stor01.cluster.com:/data/volumes /data/volumes
# vi pod-volumes-nfs.yaml
apiVsersion: v1
kind: Pod
metadata:
name: pod-volumes-nfs
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /data/web/html
volumes:
- name: html
nfs:
path: /data/volumes
server: stor01.cluster.com
readOnly: false
server:nfs服务器的IP地址或主机名,必选字段
path:nfs服务器共享的文件系统路径,必选字段
readOnly:是否以只读方式挂载,默认为false
4、Persistent Volume(PV)和Persistent Volume Claim(PVC)
pv:持久卷,是底层的共享存储的一种抽象
pvc:持久卷声明,是对于存储需求的一种声明,就是向k8s系统发出的一种资源需求申请
PV的访问模型:
accessModes:
ReadWriteOnce【简写:RWO】: 单路读写,即仅能有一个节点挂载读写
ReadOnlyMany【ROX】: 多路只读
ReadWriteMany【RWX】:多路读写
创建持久卷pv:
cat local-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv0001
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data01"
kind:PersistentVolume → 我们已将种类定义为PersistentVolume,它告诉kubernetes使用的yaml文件是用于创建持久卷的。
name:pv0001 → 我们正在创建的PersistentVolume的名称。
capacity: → 此规格将定义我们尝试创建的PV的容量。
storage:10Gi → 这告诉底层基础结构我们正在尝试在定义的路径上声明10Gi空间。
ReadWriteOnce → 这将告诉我们正在创建的卷的访问权限。
path: "/tmp/data01" → 此定义告诉计算机我们正在尝试在基础结构的该路径下创建卷。
persistentVolumeReclaimPolicy:指定当PV的回收策略为Recycle,
支持的策略有:
Retain – 需要管理员手工回收。
Recycle – 清除PV中的数据,效果相当于执行rm -rf /thevolume/*。
Delete – 删除Storage Provider上的对应存储资源,例如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume等。
storageClassName:指定PV的class为nfs。相当于为PV设置了一个分类,PVC可以指定 class申请相应class的 PV。
RWX:为ReadWriteMany的简写
Retain:是回收策略
。Retain表示需要不使用了需要手动回收
# kubectl apply -f local-pv.yaml
# kubectl get pv
# kubectl describe pv pv0001
创建pvc:
cat myclaim-1.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
kind:PersistentVolumeClaim → 它指示基础结构我们正在尝试声明指定的空间量。
name:myclaim-1 → 我们尝试创建的声明的名称。
ReadWriteOnce → 这将指定我们尝试创建的声明的模式。
storage:3Gi → 这将告诉kubernetes我们正在尝试声明的空间量。
# kubectl apply -f myclaim-1.yaml
# kubectl get pvc
在POD中使用pv和pvc
cat pod-pv.yaml
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
name: frontendhttp
spec:
containers:
- name: myfrontend
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/tomcat/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim-1
volumeMounts: →这是容器中将要进行安装的路径。
volumes: →此定义定义了我们要声明的体积定义。
persistentVolumeClaim: →在此之下,我们定义将在定义的pod中使用的卷名。
5、local
与emptyDir相似,它也占用节点的存储空间。不同点是它是kubernetes中的一种对象类型,用户可以像管理普通对象一样管理它。emptyDir在pod实例开时运行时分配,当pod离节点时删除。local类型的volume则由用户创建,系统在合适的节点上为其分配资源,调度到这个节点上的pod可以挂载它,pod离开时它也不会消失,除非用户删除。示例:
示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 100Gi
# volumeMode field requires BlockVolume Alpha feature gate to be enabled.
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- example-node
6、存储的动态供给
什么是动态供给?
每次使用存储要先创建pv, 再创建pvc,真累! 所以我们可以实现使用存储的动态供给特性。
静态存储需要用户申请PVC时保证容量和读写类型与预置PV的容量及读写类型完全匹配, 而动态存储则无需如此.
管理员无需预先创建大量的PV作为存储资源
Kubernetes从1.4版起引入了一个新的资源对象StorageClass,可用于将存储资源定义为具有显著特性的类(Class)而不是具体的PV。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或者由其按需为用户动态创建PV,这样就免去
了需要先创建PV的过程。
PV对存储系统的支持可通过其插件来实现,目前,Kubernetes支持如下类 型的插件。
官方地址:https://kubernetes.io/docs/concepts/storage/storage-classes/
官方插件是不支持NFS动态供给的,但是我们可以用第三方的插件来实现
第三方插件地址: https://github.com/kubernetes-retired/external-storage
storageclass底层可以是glusterfs,cephfs等不同的集群。
https://blog.51cto.com/u_13760351/2639942
1、下载并创建storageclass
mv class.yaml storageclass-nfs.yml
cat storageclass-nfs.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "false"
# kubectl apply -f storageclass-nfs.yml
# kubectl get storageclass
2.下载并创建rbac
因为storage自动创建pv需要经过kube-apiserver,所以需要授权。
mv rbac.yaml storageclass-nfs-rbac.yaml
cat storageclass-nfs-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
# kubectl apply -f storageclass-nfs-rbac.yaml
3.创建动态供给的deployment
需要一个deployment来专门实现pv与pvc的自动创建
vim deploy-nfs-client-provisioner.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image:registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.0.137
- name: NFS_PATH
value: /data
volumes:
- name: nfs-client-root
nfs:
server: 192.168.0.137
path: /data
# kubectl apply -f deploy-nfs-client-provisioner.yml
# kubectl get pods |grep nfs-client-provisioner
7、configmap
configmap和secret是两种特殊的存储卷,它们不是给pod提供存储空间用的,而是给我们的管理员或者用户提供了从外部向pod内部注入信息的方式。
configmap:把配置文件放在配置中心上,然后多个pod读取配置中心的配置文件。不过,configmap中的配置信息都是明文的,所以不安全。
secret:功能和configmap一样,只不过配置中心存储的配置文件不是明文的。
configmap和secret也是专属于某个名称空间的。
用户首先创建configMap并创建数据保存其中,此时数据保存在kubernetes的etcd数据库中,volume还不存在。当用户在pod中引用创建的configMap时,系统首先在节点上创建volume并将数据保存其中,这个volume占用的是节占的存储空间。此后就可以像使用普通volume一样使用它。
configMap是kubernetes中的一种对象类型,核心本质是以volume的方式将单独管理的配置信息传递给pod中的容器,并非用来存储持久化数据
http://blog.itpub.net/28916011/viewspace-2214804/
configmap内容:
server {
server_name myapp.zhixin.com;
listen 80;
root /data/web/html;
}
# kubectl describe cm nginx-www
Name: nginx-www
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
:
----
server {
server_name myapp.xx.com;
listen 80;
root /data/web/html;
}
(1)用ENV方式来把configmap注入到pod中去:
cat pod-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-cm-1
namespace: default
labels:
app: myapp #kv格式的,也可以用花括号表示
tier: frontend #定义所属的层次
annotations:
chenzx.com/created-by: "cluster-admin" #这是注解的键值对
spec:
containers:
- name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示
image: tomcat
ports:
- name: http
containerPort: 80
env: #这是一个容器的属性
- name: NGINX_SERVER_PORT
valueFrom: #kubectl explain pods.spec.containers.env.valueFrom
configMapKeyRef: #表示我们要引用一个configmap来获取数据
name: nginx-config #这是configmap的名字,也就是通过kubectl get cm获取的名字
key: nginx_port #通过kubectl describe cm nginx-config的键
#下面开始引用第二个环境变量
- name: NGINX_SERVER_NAME
valueFrom:
configMapKeyRef:
name: nginx-config
key: server_name
# kubectl apply -f pod-configmap.yaml
(2)用配置mount存储卷的方法把configmap注入到pod中。
# cat pod-configmap2.ymal
apiVersion: v1
kind: Pod
metadata:
name: pod-cm-2
namespace: default
labels:
app: myapp #kv格式的,也可以用花括号表示
tier: frontend #定义所属的层次
annotations:
chenzx.com/created-by: "cluster-admin" #这是注解的键值对
spec:
containers:
- name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/conf.d/
readOnly: true
volumes:
- name: nginxconf
configMap:
name: nginx-config
# kubectl apply -f pod-configmap2.ymal
登录容器后:执行命令printenv结果:
NGINX_SERVER_PORT=80
NGINX_SERVER_NAME=myapp.xx.com
(3)下面我们再把前面创建的文件注入到POD中:
# cat pod-configmap3.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-cm-3
namespace: default
labels:
app: myapp #kv格式的,也可以用花括号表示
tier: frontend #定义所属的层次
annotations:
chenzx.com/created-by: "cluster-admin" #这是注解的键值对
spec:
containers:
- name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/conf.d/
readOnly: true
volumes:
- name: nginxconf
configMap:
name: nginx-www
# kubectl apply -f pod-configmap3.yaml
登录容器后:cd /etc/nginx/conf.d/ ;cat nginx.conf