Abstract:
This talk will introduce you to the concept of Kubernetes Volume plugins. We will not only help you understand the basic concepts, but more importantly, using practical examples, we will show how you can develop your own volume plugins and contribute them back to the community of the OSS project as large as Kubernetes.
We will conclude the talk by discussing various challenges one can come across when contributing to a high velocity OSS project of Kubernetes' size which can help you avoid the pain and enjoy the path.
Sched Link: http://sched.co/6BYB
16. 1. Add it to the API (pkg/api/{,v1/}types.go):
type VolumeSource struct {
EmptyDir *EmptyDirVolumeSource `json:"emptyDir,omitempty"`
Flocker *FlockerVolumeSource `json:"flocker,omitempty"`
...
17. 2. Add it to the Kubelet (cmd/kubelet/app/plugins.go):
func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
allPlugins := []volume.VolumePlugin{}
allPlugins = append(allPlugins, empty_dir.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, git_repo.ProbeVolumePlugins()...)
...
26. func (b *gitRepoVolumeBuilder) SetUpAt(dir string, fsGroup *int64) error {
if volumeutil.IsReady(b.getMetaDir()) {
return nil
}
wrapped, err := b.plugin.host.NewWrapperBuilder(b.volName, wrappedVolumeSpec, &b.pod, b.opts)
if err != nil {
return err
}
if err := wrapped.SetUpAt(dir, fsGroup); err != nil {
return err
}
args := []string{"clone", b.source}
if len(b.target) != 0 {
args = append(args, b.target)
}
if output, err := b.execCommand("git", args, dir); err != nil {
return fmt.Errorf("failed to exec 'git %s': %s: %v",
strings.Join(args, " "), output, err)
}
files, err := ioutil.ReadDir(dir)
if err != nil {
return err
}
if len(b.revision) == 0 {
// Done!
volumeutil.SetReady(b.getMetaDir())
return nil
}
var subdir string
switch {
case b.target == ".":
// if target dir is '.', use the current dir
subdir = path.Join(dir)
case len(files) == 1:
// if target is not '.', use the generated folder
subdir = path.Join(dir, files[0].Name())
default:
// if target is not '.', but generated many files, it's wrong
return fmt.Errorf("unexpected directory contents: %v", files)
}
if output, err := b.execCommand("git", []string{"checkout", b.revision}, subdir); err != nil {
return fmt.Errorf("failed to exec 'git checkout %s': %s: %v", b.revision, output, err)
}
if output, err := b.execCommand("git", []string{"reset", "--hard"}, subdir); err != nil {
return fmt.Errorf("failed to exec 'git reset --hard': %s: %v", output, err)
}
volumeutil.SetReady(b.getMetaDir())
return nil
}
27. 1. Check meta: was it called before? Is it ready?
2. Use empty dir to prepare the path
3. git clone it
4. Checkout the revision sent on the pod definition
5. Job done? Mark as ready
28. Important bit of empty_dir
switch ed.medium {
case api.StorageMediumDefault:
err = ed.setupDir(dir)
case api.StorageMediumMemory:
err = ed.setupTmpfs(dir, securityContext)
default:
err = fmt.Errorf("unknown storage medium %q", ed.medium)
}
volume.SetVolumeOwnership(ed, fsGroup)
32. func (b flockerBuilder) SetUpAt(dir string, fsGroup *int64) error {
if volumeutil.IsReady(b.getMetaDir()) {
return nil
}
if b.client == nil {
c, err := b.newFlockerClient()
if err != nil {
return err
}
b.client = c
}
datasetID, err := b.client.GetDatasetID(dir)
if err != nil {
return err
}
s, err := b.client.GetDatasetState(datasetID)
if err != nil {
return fmt.Errorf("The volume '%s' is not available in Flocker. You need to create this manually with Flocker CLI before using it.", dir)
}
primaryUUID, err := b.client.GetPrimaryUUID()
if err != nil {
return err
}
if s.Primary != primaryUUID {
if err := b.updateDatasetPrimary(datasetID, primaryUUID); err != nil {
return err
}
}
b.flocker.path = s.Path
volumeutil.SetReady(b.getMetaDir())
return nil
}
33. 1. Was it called? Is it ready?
2. Is the dataset ready? If not, not my problem mate
3. If primary UUIDs doesn't match (rescheduled pod),
update them
4. Wait until ready
5. Mark as ready
34. 5. Implement the Persistent Volume Plugin
type PersistentVolumePlugin interface {
VolumePlugin
GetAccessModes() []api.PersistentVolumeAccessMode
}