4.1 K8s存储之 Volume
官方文档:https://kubernetes.io/docs/concepts/storage/volumes/
存储卷属于Pod不属于容器,同一个Pod内的多个容器可以共享此存储卷。这是因为每个Pod都有一个Pause的基础容器,所有Pod内的存储卷、命名空间等都是分配给这个Pause容器的,Pod内的主容器就是共享这个pause容器的网络名称空间(ipc、net、uts)及存储卷。
**存储卷种类:**使用kubectl explain pods.spec.volumes查看支持的存储卷:
emptyDir:空目录,用作临时目录或者缓存使用,随着Pod的删除而删除(Pod重启不会删除),按需创建,只在节点本地使用。当用作缓存时(emptyDir.medium=Memory),emptyDir关联的宿主机目录是宿主机的内存。
gitRepo:宿主机使用git clone来创建一个目录,然后将该目录以emptyDir的形式挂载到pod中。一旦gitRepo卷创建完毕后,无论是本地目录的修改还是远程仓库的修改,都不会影响对方。
[root@k8smaster volumes]# cat pod-vol-emptyDir2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: httpd
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ['/bin/httpd','-f','-h','/data/web/html']
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /data/web/html
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data
command:
- "/bin/sh"
- "-c"
- "while true;do echo $(date) >>/data/index.html ;sleep 1;done"
volumes:
- name: html
emptyDir: {} #emptyDir.medium=""|Memory表示使用磁盘还是使用内存。默认使用磁盘
将主机节点的文件系统中的文件或目录挂载到集群中。
节点级的持久化,如果节点宕机,数据丢失。
[root@k8smaster volumes]# cat pod-vol-hostPath.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-hostpath
namespace: default
spec:
containers:
- name: myapp-container
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
hostPath:
path: /data/pod/volume1
type: DirectoryOrCreate #可选
hostPath.type支持的取值:
| Value | Behavior |
|---|---|
| 空字符串(默认值)用于向后兼容,这意味着在安装hostPath卷之前不会执行任何检查。 | |
DirectoryOrCreate | 如果给定的目录中不存在,则会根据需要在此处创建一个空目录,权限设置为0755,与Kubelet命令具有相同的组和属主。 |
Directory | 给定的目录必须存在 |
FileOrCreate | 如果给定的文件不存在,则会根据需要在此处创建一个空文件,权限设置为0644,与Kubelet命令具有相同的组和属主。 |
File | 给定的文件必须存在 |
Socket | 给定的unix socker必须存在 |
CharDevice | 给定的字符设备必须存在 |
BlockDevice | 给定的块设备必须存在 |
- SAN(存储区域网络):iSCSI,……
- NAS(网络附加存储):nfs,cifs,……
[root@k8smaster volumes]# cat pod-vol-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-vol-nfs
namespace: default
spec:
containers:
- name: myapp-pod-vol-nfs
image: ikubernetes/myapp:v1
volumeMounts:
- name: html #要挂载的volume名称
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
path: /data/volumes
server: 192.168.5.241
#注意: 使用nfs时,所有Node节点要安装nfs-utils包,否则mount命令无法实现nfs类型的挂载;此外nfs服务支持多客户端同时读写操作(nfs server自己具有持锁能力),但是nfs性能可能不建议在大规模环境中使用
一般是文件系统级别、块级别
- glusterfs,rbd(ceph),cephfs,……
- vsphereVolume
#在glusterfs上创建volume
方式1:
直接使用heketi创建,例如创建3个volume:
heketi-cli volume create --size=50 --durability=none --name es1
heketi-cli volume create --size=50 --durability=none --name es2
heketi-cli volume create --size=50 --durability=none --name es3
1、创建连接外置的gusterfs的endpoint
apiVersion: v1
kind: Endpoints
metadata:
name: glusterfs-cluster
subsets:
- addresses:
- ip: 172.22.62.31 #glusterfs-node的IP
ports:
- port: 1 #port为1-65535之间的任意值,实际没有用到这个值
- addresses:
- ip: 172.22.62.36
ports:
- port: 1
- addresses:
- ip: 172.22.62.40
ports:
- port: 1
---
apiVersion: v1
kind: Service
metadata:
name: glusterfs-cluster
spec:
ports:
- port: 1
ep也可以这样写:
apiVersion: v1 kind: Endpoints metadata: name: glusterfs-cluster subsets: - addresses: - ip: 172.22.62.31 - ip: 172.22.62.36 - ip: 172.22.62.40 ports: - port: 1 protocol: TCP
2、在glusterfs中创建一个名为“es1”的volume,(这步骤我们已经在之前通过heketi创建了)
3、pod中使用volume:
volumes:
- name: glusterfsvol
glusterfs:
endpoints: glusterfs-cluster #glustfs-cluster
path: es1 #Glusterfs volume name
readOnly: true
- awsEBS,Azure Disk,gcePersistentDisk……
pvc与pv是一一对应关系。一旦pvc与pv绑定后,此时该pvc就可以定义为一个存储卷。可以实现对多种存储后端的抽象。
示例:glusterfs手动创建的pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: gluster-es1
labels:
name: gluster-es1
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
storageClassName: "test"
glusterfs:
endpoints: "glusterfs-cluster"
path: "es1"
readOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: gluster-es2
labels:
name: gluster-es2
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
storageClassName: "test"
glusterfs:
endpoints: "glusterfs-cluster"
path: "es2"
readOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: gluster-es3
labels:
name: gluster-es3
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
storageClassName: "test"
glusterfs:
endpoints: "glusterfs-cluster"
path: "es3"
readOnly: false
- configMap
- secret
- downwardAPI 节点和pod的某些信息
apiVersion: v1
kind: Pod
metadata:
name: test-env-pod
namespace: kube-system
spec:
containers:
- name: test-env-pod
image: busybox:latest
command: ["/bin/sh", "-c", "env"]
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
#我们可以看到上面我们使用了一种新的方式来设置env的值:valueFrom。另外我们需要注意的是 POD 的 name 和 namespace 属于元数据,是在 POD 创建之前就已经定下来了的,所以我们使用 metata 获取就可以了,但是对于 POD 的 IP 则不一样,因为我们知道 POD IP 是不固定的,POD 重建了就变了,它属于状态数据,所以我们使用 status 去获取。
#除了使用fieldRef获取 POD 的基本信息外,还可以通过resourceFieldRef去获取容器的资源请求和资源限制信息。