什么是容器卷
数据卷 (Data Volumes )是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于 Linux 中的 mount 行为。
容器挂载原理
containerd创建的容器里的数据存储在下面的目录中
[root@master01 httpbin]#ls /run/containerd/io.containerd.runtime.v2.task/k8s.io/{podid}/rootfs/
所以我们可以这样思考一下
- docker挂载也使用了命名空间的机制,一个容器(也就是一个进程)单独记录一套挂载信息。
- 每个容器中的数据目录都存储在上面的目录中。我们进入容器ls 获取的信息就是上面的信息,只是在进入容器的时候使用了CLONE_NEWNS机制也就是chroot 功能。
- 所以容器挂载卷,使用了两个机制,第一 CLONE_NEWNS 命名空间机制,让你以为你是在一台新的系统上,其实是原始系统的一个目录中,第二使用挂载命名空间,这样可以使这个新的系统只能看到它自己的挂载信息。
- 这样来完成容器挂载的操作。
- 对于k8s来说,远程挂载也可以实现,所以可以使用类似于AWS等存储系统。
k8s中容器挂载的方式
让我们先重温一下,k8s如何将volumes挂载到容器内部,下面是一段nginx,静态文件挂载到node上的yaml配置。
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: ssx-nginx-c
image: nginx:latest #使用镜像nginx: 创建container,该container默认80端口可访问
ports:
- containerPort: 80 # 开启本容器的80端口可访问
volumeMounts: #挂载持久存储卷
- name: volume #挂载设备的名字,与volumes[*].name 需要对应
mountPath: /usr/share/nginx/html #挂载到容器的某个路径下
volumes:
- name: volume #和上面保持一致 这是本地的文件路径,上面是容器内部的路径
hostPath:
path: /opt/web/dist #此路径需要实现创建
- volumeMounts: 下可配置 指定挂载卷挂载到容器内部指定目录中。
- volumes: 配置了当前挂载卷的类型,名称,以及挂载类型的一些属性等
对于存储来说,我们需要确定使用那些挂载类型可以满足当前容器的需求,所以我们需要对挂载类型进行一一列举分析。
挂载类型
下面只列举几个常用的类型,至于全部支持的类型请查看源码staging/src/k8s.io/api/core/v1/types.go:VolumeSource{}
hostPath
直接挂载到node节点上的目录中
容器删除时,挂载的内容不会消失
type HostPathVolumeSource struct {
// node路径
Path string `json:"path" protobuf:"bytes,1,opt,name=path"`
// 挂载类型
Type *HostPathType `json:"type,omitempty" protobuf:"bytes,2,opt,name=type"`
}
// +enum
type HostPathType string
const (
//对于向后兼容,如果未设置,则将其留空
HostPathUnset HostPathType=“”
//如果给定路径上不存在任何内容,将在那里创建一个空目录
//如文件模式0755所需,具有与Kubelet相同的组和所有权。
HostPathDirectoryOrCreate HostPathType=“DirectoryOr创建”
//给定路径上必须存在目录
HostPathDirectory HostPathType=“Directory”
//如果给定路径上不存在任何内容,将在那里创建一个空文件
//如文件模式0644所需,具有与Kubelet相同的组和所有权。
HostPathFileOrCreate HostPathType=“FileOrCreate”
//文件必须存在于给定路径
HostPathFile HostPathType=“File”
//给定路径上必须存在UNIX套接字
HostPathSocket HostPathType=“Socket”
//给定路径上必须存在字符设备
HostPathCharDev HostPathType=“CharDevice”
//给定路径上必须存在块设备
HostPathBlockDev HostPathType=“BlockDevice”
)
使用此类卷时要小心,因为:
- HostPaths 可以公开特权系统凭据(例如 Kubelet)或特权 API(例如容器运行时套接字),可用于容器逃逸或攻击集群的其他部分。
- 由于节点上的文件不同,具有相同配置(例如从 PodTemplate 创建)的 Pod 在不同节点上的行为可能不同
- 在底层主机上创建的文件或目录只能由 root 写入。您要么需要在 特权容器中以 root 身份运行您的进程,要么修改主机上的文件权限以便能够写入hostPath卷
emptyDir
secret
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
secret是指定目录,而里面的key就是文件名,value是文件内容,configmap也一致。
configmap
spec:
containers:
- name: test
image: busybox:1.28
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level
cephfs
apiVersion: v1
kind: Pod
metadata:
name: cephfs
spec:
containers:
- name: cephfs-rw
image: kubernetes/pause
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs
volumes:
- name: cephfs
cephfs:
monitors:
- 10.16.154.78:6789
- 10.16.154.82:6789
- 10.16.154.83:6789
# by default the path is /, but you can override and mount a specific path of the filesystem by using the path attribute
# path: /some/path/in/side/cephfs
user: admin
secretFile: "/etc/ceph/admin.secret"
readOnly: true
nfs
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /my-nfs-data
name: test-volume
volumes:
- name: test-volume
nfs:
server: my-nfs-server.example.com
path: /my-nfs-volume
readOnly: true
PVC
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
readOnly: true
参考文献
https://kubernetes.io/docs/concepts/storage/volumes/ (讲解volumes每个类型的用途)
https://github.com/kubernetes/examples/blob/master/volumes/cephfs/cephfs.yaml (ceph例子)
https://blog.csdn.net/hwruirui/article/details/119566635(pid命名空间讲解)