From 57a8c2e5e844ee403c9a703c621780de7c7343f0 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Mon, 15 Oct 2018 15:42:12 -0400 Subject: Mount proper cgroup for systemd to manage inside of the container. We are still requiring oci-systemd-hook to be installed in order to run systemd within a container. This patch properly mounts /sys/fs/cgroup/systemd/libpod_parent/libpod-UUID on /sys/fs/cgroup/systemd inside of container. Since we need the UUID of the container, we needed to move Systemd to be a config option of the container. Signed-off-by: Daniel J Walsh --- libpod/container.go | 3 +++ libpod/container_easyjson.go | 12 +++++++++ libpod/container_internal_linux.go | 41 +++++++++++++++++++++++++++++++ libpod/options.go | 12 +++++++++ pkg/spec/createconfig.go | 4 +++ pkg/spec/spec.go | 50 -------------------------------------- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/libpod/container.go b/libpod/container.go index 4e17b1102..62db87fa0 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -346,6 +346,9 @@ type ContainerConfig struct { // IsInfra is a bool indicating whether this container is an infra container used for // sharing kernel namespaces in a pod IsInfra bool `json:"pause"` + + // Systemd tells libpod to setup the container in systemd mode + Systemd bool `json:"systemd"` } // ContainerStatus returns a string representation for users diff --git a/libpod/container_easyjson.go b/libpod/container_easyjson.go index f78366065..53ad5b7ee 100644 --- a/libpod/container_easyjson.go +++ b/libpod/container_easyjson.go @@ -1682,6 +1682,8 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(in *jlexer.Lexer, ou } case "pause": out.IsInfra = bool(in.Bool()) + case "systemd": + out.Systemd = bool(in.Bool()) default: in.SkipRecursive() } @@ -2344,6 +2346,16 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(out *jwriter.Writer, } out.Bool(bool(in.IsInfra)) } + { + const prefix string = ",\"systemd\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Bool(bool(in.Systemd)) + } out.RawByte('}') } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 0353124dd..05604246f 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -188,6 +188,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } + if c.config.Systemd { + c.setupSystemd(g.Mounts(), g) + } + // Look up and add groups the user belongs to, if a group wasn't directly specified if !rootless.IsRootless() && !strings.Contains(c.config.User, ":") { groups, err := chrootuser.GetAdditionalGroupsForUser(c.state.Mountpoint, uint64(g.Config.Process.User.UID)) @@ -294,6 +298,43 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { return g.Config, nil } +// systemd expects to have /run, /run/lock and /tmp on tmpfs +// It also expects to be able to write to /sys/fs/cgroup/systemd and /var/log/journal +func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) { + options := []string{"rw", "rprivate", "noexec", "nosuid", "nodev"} + for _, dest := range []string{"/run", "/run/lock"} { + if MountExists(mounts, dest) { + continue + } + tmpfsMnt := spec.Mount{ + Destination: dest, + Type: "tmpfs", + Source: "tmpfs", + Options: append(options, "tmpcopyup", "size=65536k"), + } + g.AddMount(tmpfsMnt) + } + for _, dest := range []string{"/tmp", "/var/log/journal"} { + if MountExists(mounts, dest) { + continue + } + tmpfsMnt := spec.Mount{ + Destination: dest, + Type: "tmpfs", + Source: "tmpfs", + Options: append(options, "tmpcopyup"), + } + g.AddMount(tmpfsMnt) + } + systemdMnt := spec.Mount{ + Destination: "/sys/fs/cgroup/systemd", + Type: "bind", + Source: fmt.Sprintf("/sys/fs/cgroup/systemd%s/libpod-%s", CgroupfsDefaultCgroupParent, c.ID()), + Options: []string{"bind", "private"}, + } + g.AddMount(systemdMnt) +} + // Add an existing container's namespace to the spec func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr string, specNS string) error { nsCtr, err := c.runtime.state.Container(ctr) diff --git a/libpod/options.go b/libpod/options.go index 9f966cead..228b38ba5 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -349,6 +349,18 @@ func WithShmDir(dir string) CtrCreateOption { } } +// WithSystemd turns on systemd mode in the container +func WithSystemd() CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return ErrCtrFinalized + } + + ctr.config.Systemd = true + return nil + } +} + // WithShmSize sets the size of /dev/shm tmpfs mount. func WithShmSize(size int64) CtrCreateOption { return func(ctr *Container) error { diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index d34b21189..6ac9d82da 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -319,6 +319,10 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib if c.Interactive { options = append(options, libpod.WithStdin()) } + if c.Systemd && (strings.HasSuffix(c.Command[0], "init") || + strings.HasSuffix(c.Command[0], "systemd")) { + options = append(options, libpod.WithSystemd()) + } if c.Name != "" { logrus.Debugf("appending name %s", c.Name) options = append(options, libpod.WithName(c.Name)) diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 4c855d659..b1cca2c9e 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -5,7 +5,6 @@ import ( "path" "strings" - "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/rootless" "github.com/docker/docker/daemon/caps" "github.com/docker/docker/pkg/mount" @@ -261,12 +260,6 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint addedResources = true } - if config.Systemd && (strings.HasSuffix(config.Command[0], "init") || - strings.HasSuffix(config.Command[0], "systemd")) { - if err := setupSystemd(config, &g); err != nil { - return nil, errors.Wrap(err, "failed to setup systemd") - } - } for _, i := range config.Tmpfs { // Default options if nothing passed options := []string{"rw", "rprivate", "noexec", "nosuid", "nodev", "size=65536k"} @@ -408,49 +401,6 @@ func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) } } -// systemd expects to have /run, /run/lock and /tmp on tmpfs -// It also expects to be able to write to /sys/fs/cgroup/systemd and /var/log/journal - -func setupSystemd(config *CreateConfig, g *generate.Generator) error { - mounts, err := config.GetVolumeMounts([]spec.Mount{}) - if err != nil { - return err - } - options := []string{"rw", "rprivate", "noexec", "nosuid", "nodev"} - for _, dest := range []string{"/run", "/run/lock"} { - if libpod.MountExists(mounts, dest) { - continue - } - tmpfsMnt := spec.Mount{ - Destination: dest, - Type: "tmpfs", - Source: "tmpfs", - Options: append(options, "tmpcopyup", "size=65536k"), - } - g.AddMount(tmpfsMnt) - } - for _, dest := range []string{"/tmp", "/var/log/journal"} { - if libpod.MountExists(mounts, dest) { - continue - } - tmpfsMnt := spec.Mount{ - Destination: dest, - Type: "tmpfs", - Source: "tmpfs", - Options: append(options, "tmpcopyup"), - } - g.AddMount(tmpfsMnt) - } - tmpfsMnt := spec.Mount{ - Destination: "/sys/fs/cgroup/systemd", - Type: "tmpfs", - Source: "tmpfs", - Options: append(options, "size=65536k"), - } - g.AddMount(tmpfsMnt) - return nil -} - func addPidNS(config *CreateConfig, g *generate.Generator) error { pidMode := config.PidMode if IsNS(string(pidMode)) { -- cgit v1.2.3-54-g00ecf