上一篇介绍创建存储pv的流程,那个有个存储需要挂载到容器里面才能被使用,下面还需要一个通用的接口felx去将存储挂载到容器里面。
kubernetes存储的使用和协助需要分别实现挂载和解挂的接口
kubernetes下面pkg/volume/volume.go

type Attacher interface {
    // 挂载存储到主机
    Attach(spec *Spec, nodeName types.NodeName) (string, error)

    // 检查存储是否以及挂载
    VolumesAreAttached(specs []*Spec, nodeName types.NodeName) (map[*Spec]bool, error)

    // 等待存储被挂载
    WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error)

    // 获取挂载路径
    GetDeviceMountPath(spec *Spec) (string, error)

    // 格式化并挂载到pod下的目录
    MountDevice(spec *Spec, devicePath string, deviceMountPath string) error
}

下面解挂的接口

type Detacher interface {
    // 从主机上面解挂
    Detach(deviceName string, nodeName types.NodeName) error

    // 解挂pod下的目录
    UnmountDevice(deviceMountPath string) error
}

介绍完接口了,那么第三方的存储如何对接呢,那就是flexvolume,它就是通过调用第三方存储的二进制可执行文件去使用存储
具体看它的代码实现pkg/volume/flexvolume/attacher.go,
这是加载的例子

func (a *flexVolumeAttacher) Attach(spec *volume.Spec, hostName types.NodeName) (string, error) {

    call := a.plugin.NewDriverCall(attachCmd)
    call.AppendSpec(spec, a.plugin.host, nil)
    call.Append(string(hostName))

    status, err := call.Run()
    if isCmdNotSupportedErr(err) {
        return (*attacherDefaults)(a).Attach(spec, hostName)
    } else if err != nil {
        return "", err
    }
    return status.DevicePath, err
}

这是一个挂载的例子

func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
    // Mount only once.
    alreadyMounted, err := prepareForMount(a.plugin.host.GetMounter(a.plugin.GetPluginName()), deviceMountPath)
    if err != nil {
        return err
    }
    if alreadyMounted {
        return nil
    }

    call := a.plugin.NewDriverCall(mountDeviceCmd)
    call.Append(deviceMountPath)
    call.Append(devicePath)
    call.AppendSpec(spec, a.plugin.host, nil)

    _, err = call.Run()
    if isCmdNotSupportedErr(err) {
        // Devicepath is empty if the plugin does not support attach calls. Ignore mountDevice calls if the
        // plugin does not implement attach interface.
        if devicePath != "" {
            return (*attacherDefaults)(a).MountDevice(spec, devicePath, deviceMountPath, a.plugin.host.GetMounter(a.plugin.GetPluginName()))
        } else {
            return nil
        }
    }
    return err
}

如果对driver感兴趣看,pkg/volume/flexvolume/driver-call.go,就是通过golang的os/exec去调用二进制文件。
这样我们的第三放存储实现这些接口就可以被k8s调用了。那么kubelet怎么知道你的存储插件在那里呢?答案是通过
–volume-plugin-dir指定你存储插件的位置,默认值是/usr/libexec/kubernetes/kubelet-plugins/volume/exec/。把你的二进制文件放到这个目录下面,这个和cni的执行是一样的。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐