EmptyDir 类型:同一个pod内的容器都能读写 EmptyDir 中文件。一旦 pod 离开了宿主机,EmptyDir 中的数据就会被永久删除。所以目前 EmptyDir 类型的 volume主 要用作临时空间。
缺省情况下,EmptyDir 是使用主机磁盘进行存储的,需要使用 tmpfs 作为 emptyDir 的可用存储资源也是可以的,只需要在创建 emptyDir 卷时增加一个 emptyDir.medium 字段的定义,并赋值为 "Memory" 即可。
根据官方给出的建议,emptyDir可以在以下几种场景下使用:
- 临时空间,例如基于磁盘的合并排序
- 设置检查点以从崩溃事件中恢复未执行完毕的长计算
- 保存内容管理器容器从Web服务器容器提供数据时所获取的文件
$ cat emtptydir.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-emptydir
labels:
app: wordpress-emptydir
tier: mysql-emptydir
spec:
selector:
matchLabels:
app: wordpress-emptydir
tier: mysql-emptydir
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress-emptydir
tier: mysql-emptydir
spec:
containers:
- image: mysql:5.6
name: mysql-emptydir
env:
- name: MYSQL_ROOT_PASSWORD
value: changeme
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
emptyDir: {}
operationExecutor.MountVolume
--> GenerateMountVolumeFunc
--> volumePlugin.NewMounter (第 1 章节讲解)
--> volumeMounter.SetUp (第 2 章节讲解)
emptyDir 源码实现路径为: pkg/volume/emptydir 目录
emptyDir 插件名称为 kubernetes.io/empty-dir
type emptyDirPlugin struct {
host volume.VolumeHost
}
var _ volume.VolumePlugin = &emptyDirPlugin{}
const (
emptyDirPluginName = "kubernetes.io/empty-dir"
hugePagesPageSizeMountOption = "pagesize"
)
func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
return host.GetPodVolumeDir(uid, stringsutil.EscapeQualifiedNameForDisk(emptyDirPluginName), volName)
}
func (plugin *emptyDirPlugin) Init(host volume.VolumeHost) error {
plugin.host = host
return nil
}
1. NewMounter 函数
这个主要实例化 emptyDir 结构,medium数据存储在disk / memory / hugepages
mounter接口实现了 mount umount等一大堆方法
StorageMediumDefault StorageMedium = "" // use whatever the default is for the node, assume anything we don't explicitly handle is this StorageMediumMemory StorageMedium = "Memory" // use memory (e.g. tmpfs on linux) StorageMediumHugePages StorageMedium = "HugePages" // use hugepages
func (plugin *emptyDirPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter(plugin.GetPluginName()), &realMountDetector{plugin.host.GetMounter(plugin.GetPluginName())}, opts)
}
func (plugin *emptyDirPlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, mounter mount.Interface, mountDetector mountDetector, opts volume.VolumeOptions) (volume.Mounter, error) {
medium := v1.StorageMediumDefault
if spec.Volume.EmptyDir != nil { // Support a non-specified source as EmptyDir.
medium = spec.Volume.EmptyDir.Medium
}
return &emptyDir{
pod: pod,
volName: spec.Name(),
medium: medium,
mounter: mounter,
mountDetector: mountDetector,
plugin: plugin,
MetricsProvider: volume.NewMetricsDu(getPath(pod.UID, spec.Name(), plugin.host)),
}, nil
}
2. Setup函数
就是创建目录,看看SetUpAt进行哪些操作
// SetUp creates new directory.
func (ed *emptyDir) SetUp(fsGroup *int64) error {
return ed.SetUpAt(ed.GetPath(), fsGroup)
}
3. SetUpAt函数
3.1 IsLikelyNotMountPoint函数验证是否已经mount上了
notMnt, err := ed.mounter.IsLikelyNotMountPoint(dir)
// Getting an os.IsNotExist err from is a contingency; the directory
// may not exist yet, in which case, setup should run.
if err != nil && !os.IsNotExist(err) {
return err
}
3.2 根据 medium 类型执行不同操作,分别分析
default 直接 disk,memory hugepages三种
switch ed.medium {
case v1.StorageMediumDefault:
err = ed.setupDir(dir)
case v1.StorageMediumMemory:
err = ed.setupTmpfs(dir)
case v1.StorageMediumHugePages:
err = ed.setupHugepages(dir)
default:
err = fmt.Errorf("unknown storage medium %q", ed.medium)
}
4. setupDir函数
创建目录,权限0777,比较简单就是验证权限
// setupDir creates the directory with the default permissions specified by the perm constant.
func (ed *emptyDir) setupDir(dir string) error {
// Create the directory if it doesn't already exist.
if err := os.MkdirAll(dir, perm); err != nil {
return err
}
// stat the directory to read permission bits
fileinfo, err := os.Lstat(dir)
if err != nil {
return err
}
5. setupTmpfs函数
也需要创建目录,最后也是需要mount操作,将tmpfs挂载到 dir目录
// setupTmpfs creates a tmpfs mount at the specified directory.
func (ed *emptyDir) setupTmpfs(dir string) error {
if ed.mounter == nil {
return fmt.Errorf("memory storage requested, but mounter is nil")
}
if err := ed.setupDir(dir); err != nil {
return err
}
// Make SetUp idempotent.
medium, isMnt, err := ed.mountDetector.GetMountMedium(dir)
if err != nil {
return err
}
// If the directory is a mountpoint with medium memory, there is no
// work to do since we are already in the desired state.
if isMnt && medium == v1.StorageMediumMemory {
return nil
}
klog.V(3).Infof("pod %v: mounting tmpfs for volume %v", ed.pod.UID, ed.volName)
return ed.mounter.Mount("tmpfs", dir, "tmpfs", nil /* options */)
}
总结:
比较简单,就是pod删除了,数据就没有了
三种模式,默认直接存disk,创建目录
memory 挂载 tmpfs