From 0998808a752a8a7ae43f2630023b22c1b3de47a4 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Mon, 13 Aug 2018 15:39:11 -0400 Subject: Create pod CGroups when using the systemd cgroup driver Signed-off-by: Matthew Heon Closes: #1266 Approved by: baude --- libpod/oci_linux.go | 10 ++++++-- libpod/pod_internal.go | 8 +++++-- libpod/runtime_pod_linux.go | 46 ++++++++++++++++++++++++++++------- libpod/util.go | 58 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 13 deletions(-) diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index bdf859d7d..dacc92c62 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -24,8 +24,14 @@ func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd if r.cgroupManager == SystemdCgroupsManager { unitName := createUnitName("libpod-conmon", ctr.ID()) - logrus.Infof("Running conmon under slice %s and unitName %s", cgroupParent, unitName) - if err := utils.RunUnderSystemdScope(cmd.Process.Pid, cgroupParent, unitName); err != nil { + realCgroupParent := cgroupParent + splitParent := strings.Split(cgroupParent, "/") + if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 { + realCgroupParent = splitParent[len(splitParent)-1] + } + + logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName) + if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil { logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err) } } else { diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go index c8d8405bb..1ba4487ab 100644 --- a/libpod/pod_internal.go +++ b/libpod/pod_internal.go @@ -2,6 +2,7 @@ package libpod import ( "context" + "fmt" "path/filepath" "strings" "time" @@ -67,8 +68,11 @@ func (p *Pod) refresh() error { if p.config.UsePodCgroup { switch p.runtime.config.CgroupManager { case SystemdCgroupsManager: - // NOOP for now, until proper systemd cgroup management - // is implemented + cgroupPath, err := systemdSliceFromPath(p.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", p.ID())) + if err != nil { + logrus.Errorf("Error creating CGroup for pod %s: %v", p.ID(), err) + } + p.state.CgroupPath = cgroupPath case CgroupfsCgroupsManager: p.state.CgroupPath = filepath.Join(p.config.CgroupParent, p.ID()) diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 58affa45f..3592c2fee 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -4,6 +4,7 @@ package libpod import ( "context" + "fmt" "path" "path/filepath" "strings" @@ -70,12 +71,23 @@ func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) { } else if len(pod.config.CgroupParent) < 6 || !strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") { return nil, errors.Wrapf(ErrInvalidArg, "did not receive systemd slice as cgroup parent when using systemd to manage cgroups") } - // Creating CGroup path is currently a NOOP until proper systemd - // cgroup management is merged + // If we are set to use pod cgroups, set the cgroup parent that + // all containers in the pod will share + if pod.config.UsePodCgroup { + cgroupPath, err := systemdSliceFromPath(pod.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", pod.ID())) + if err != nil { + return nil, errors.Wrapf(err, "unable to create pod cgroup for pod %s", pod.ID()) + } + pod.state.CgroupPath = cgroupPath + } default: return nil, errors.Wrapf(ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.CgroupManager) } + if pod.config.UsePodCgroup { + logrus.Debugf("Got pod cgroup as %s", pod.state.CgroupPath) + } + if err := r.state.AddPod(pod); err != nil { return nil, errors.Wrapf(err, "error adding pod to state") } @@ -91,11 +103,20 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) return ErrRuntimeStopped } + if !p.valid { + if ok, _ := r.state.HasPod(p.ID()); !ok { + // Pod was either already removed, or never existed to + // begin with + return nil + } + } + p.lock.Lock() defer p.lock.Unlock() - if !p.valid { - return ErrPodRemoved + // Force a pod update + if err := p.updatePod(); err != nil { + return err } ctrs, err := r.state.PodContainers(p) @@ -216,20 +237,27 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) // Remove pod cgroup, if present if p.state.CgroupPath != "" { + logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath) + switch p.runtime.config.CgroupManager { case SystemdCgroupsManager: - // NOOP for now, until proper systemd cgroup management - // is implemented + if err := deleteSystemdCgroup(p.state.CgroupPath); err != nil { + // The pod is already almost gone. + // No point in hard-failing if we fail + // this bit of cleanup. + logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + } case CgroupfsCgroupsManager: // Delete the cgroupfs cgroup - logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath) - cgroup, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(p.state.CgroupPath)) if err != nil && err != cgroups.ErrCgroupDeleted { return err } else if err == nil { if err := cgroup.Delete(); err != nil { - return err + // The pod is already almost gone. + // No point in hard-failing if we fail + // this bit of cleanup. + logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) } } default: diff --git a/libpod/util.go b/libpod/util.go index 13235059f..5b16b5755 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -9,10 +9,12 @@ import ( "strings" "time" + "github.com/containerd/cgroups" "github.com/containers/image/signature" "github.com/containers/image/types" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // Runtime API constants @@ -123,6 +125,62 @@ func WaitForFile(path string, timeout time.Duration) error { } } +// systemdSliceFromPath makes a new systemd slice under the given parent with +// the given name. +// The parent must be a slice. The name must NOT include ".slice" +func systemdSliceFromPath(parent, name string) (string, error) { + cgroupPath, err := assembleSystemdCgroupName(parent, name) + if err != nil { + return "", err + } + + logrus.Debugf("Created cgroup path %s for parent %s and name %s", cgroupPath, parent, name) + + if err := makeSystemdCgroup(cgroupPath); err != nil { + return "", errors.Wrapf(err, "error creating cgroup %s", cgroupPath) + } + + logrus.Debugf("Created cgroup %s", cgroupPath) + + return cgroupPath, nil +} + +// makeSystemdCgroup creates a systemd CGroup at the given location. +func makeSystemdCgroup(path string) error { + controller, err := cgroups.NewSystemd(SystemdDefaultCgroupParent) + if err != nil { + return err + } + + return controller.Create(path, &spec.LinuxResources{}) +} + +// deleteSystemdCgroup deletes the systemd cgroup at the given location +func deleteSystemdCgroup(path string) error { + controller, err := cgroups.NewSystemd(SystemdDefaultCgroupParent) + if err != nil { + return err + } + + return controller.Delete(path) +} + +// assembleSystemdCgroupName creates a systemd cgroup path given a base and +// a new component to add. +// The base MUST be systemd slice (end in .slice) +func assembleSystemdCgroupName(baseSlice, newSlice string) (string, error) { + const sliceSuffix = ".slice" + + if !strings.HasSuffix(baseSlice, sliceSuffix) { + return "", errors.Wrapf(ErrInvalidArg, "cannot assemble cgroup path with base %q - must end in .slice", baseSlice) + } + + noSlice := strings.TrimSuffix(baseSlice, sliceSuffix) + final := fmt.Sprintf("%s/%s-%s%s", baseSlice, noSlice, newSlice, sliceSuffix) + + return final, nil +} + type byDestination []spec.Mount func (m byDestination) Len() int { -- cgit v1.2.3-54-g00ecf