func (m *Manager) Apply(pid int) error { var ( c = m.Cgroups unitName = getUnitName(c) slice = "system.slice" properties []systemdDbus.Property ) if c.Slice != "" { slice = c.Slice } properties = append(properties, systemdDbus.PropSlice(slice), systemdDbus.PropDescription("docker container "+c.Name), newProp("PIDs", []uint32{uint32(pid)}), ) // Always enable accounting, this gets us the same behaviour as the fs implementation, // plus the kernel has some problems with joining the memory cgroup at a later time. properties = append(properties, newProp("MemoryAccounting", true), newProp("CPUAccounting", true), newProp("BlockIOAccounting", true)) if hasTransientDefaultDependencies { properties = append(properties, newProp("DefaultDependencies", false)) } if c.Memory != 0 { properties = append(properties, newProp("MemoryLimit", uint64(c.Memory))) } // TODO: MemoryReservation and MemorySwap not available in systemd if c.CpuShares != 0 { properties = append(properties, newProp("CPUShares", uint64(c.CpuShares))) } if c.BlkioWeight != 0 { properties = append(properties, newProp("BlockIOWeight", uint64(c.BlkioWeight))) } // We need to set kernel memory before processes join cgroup because // kmem.limit_in_bytes can only be set when the cgroup is empty. // And swap memory limit needs to be set after memory limit, only // memory limit is handled by systemd, so it's kind of ugly here. if c.KernelMemory > 0 { if err := setKernelMemory(c); err != nil { return err } } if _, err := theConn.StartTransientUnit(unitName, "replace", properties, nil); err != nil { return err } if err := joinDevices(c, pid); err != nil { return err } // TODO: CpuQuota and CpuPeriod not available in systemd // we need to manually join the cpu.cfs_quota_us and cpu.cfs_period_us if err := joinCpu(c, pid); err != nil { return err } if err := joinMemory(c, pid); err != nil { return err } // we need to manually join the freezer, net_cls, net_prio and cpuset cgroup in systemd // because it does not currently support it via the dbus api. if err := joinFreezer(c, pid); err != nil { return err } if err := joinNetPrio(c, pid); err != nil { return err } if err := joinNetCls(c, pid); err != nil { return err } if err := joinCpuset(c, pid); err != nil { return err } if err := joinHugetlb(c, pid); err != nil { return err } // FIXME: Systemd does have `BlockIODeviceWeight` property, but we got problem // using that (at least on systemd 208, see https://github.com/opencontainers/runc/libcontainer/pull/354), // so use fs work around for now. if err := joinBlkio(c, pid); err != nil { return err } paths := make(map[string]string) for sysname := range subsystems { subsystemPath, err := getSubsystemPath(m.Cgroups, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return err } paths[sysname] = subsystemPath } m.Paths = paths if paths["cpu"] != "" { if err := fs.CheckCpushares(paths["cpu"], c.CpuShares); err != nil { return err } } return nil }
func (m *Manager) Apply(pid int) error { var ( c = m.Cgroups unitName = getUnitName(c) slice = "system.slice" properties []systemdDbus.Property ) if c.Paths != nil { paths := make(map[string]string) for name, path := range c.Paths { _, err := getSubsystemPath(m.Cgroups, name) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return err } paths[name] = path } m.Paths = paths return cgroups.EnterPid(m.Paths, pid) } if c.Parent != "" { slice = c.Parent } properties = append(properties, systemdDbus.PropSlice(slice), systemdDbus.PropDescription("docker container "+c.Name), newProp("PIDs", []uint32{uint32(pid)}), // This is only supported on systemd versions 218 and above. newProp("Delegate", true), ) // Always enable accounting, this gets us the same behaviour as the fs implementation, // plus the kernel has some problems with joining the memory cgroup at a later time. properties = append(properties, newProp("MemoryAccounting", true), newProp("CPUAccounting", true), newProp("BlockIOAccounting", true)) if hasTransientDefaultDependencies { properties = append(properties, newProp("DefaultDependencies", false)) } if c.Resources.Memory != 0 { properties = append(properties, newProp("MemoryLimit", uint64(c.Resources.Memory))) } if c.Resources.CpuShares != 0 { properties = append(properties, newProp("CPUShares", uint64(c.Resources.CpuShares))) } if c.Resources.BlkioWeight != 0 { properties = append(properties, newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight))) } // We need to set kernel memory before processes join cgroup because // kmem.limit_in_bytes can only be set when the cgroup is empty. // And swap memory limit needs to be set after memory limit, only // memory limit is handled by systemd, so it's kind of ugly here. if c.Resources.KernelMemory > 0 { if err := setKernelMemory(c); err != nil { return err } } if _, err := theConn.StartTransientUnit(unitName, "replace", properties, nil); err != nil { return err } if err := joinCgroups(c, pid); err != nil { return err } paths := make(map[string]string) for _, s := range subsystems { subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name()) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return err } paths[s.Name()] = subsystemPath } m.Paths = paths return nil }
func (m *Manager) Apply(pid int) error { var ( c = m.Cgroups unitName = getUnitName(c) slice = "system.slice" properties []systemd.Property ) if c.Slice != "" { slice = c.Slice } properties = append(properties, systemd.PropSlice(slice), systemd.PropDescription("docker container "+c.Name), newProp("PIDs", []uint32{uint32(pid)}), ) // Always enable accounting, this gets us the same behaviour as the fs implementation, // plus the kernel has some problems with joining the memory cgroup at a later time. properties = append(properties, newProp("MemoryAccounting", true), newProp("CPUAccounting", true), newProp("BlockIOAccounting", true)) if hasTransientDefaultDependencies { properties = append(properties, newProp("DefaultDependencies", false)) } if c.Memory != 0 { properties = append(properties, newProp("MemoryLimit", uint64(c.Memory))) } // TODO: MemoryReservation and MemorySwap not available in systemd if c.CpuShares != 0 { properties = append(properties, newProp("CPUShares", uint64(c.CpuShares))) } if c.BlkioWeight != 0 { properties = append(properties, newProp("BlockIOWeight", uint64(c.BlkioWeight))) } if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil { return err } if err := joinDevices(c, pid); err != nil { return err } // TODO: CpuQuota and CpuPeriod not available in systemd // we need to manually join the cpu.cfs_quota_us and cpu.cfs_period_us if err := joinCpu(c, pid); err != nil { return err } // -1 disables memorySwap if c.MemorySwap >= 0 && c.Memory != 0 { if err := joinMemory(c, pid); err != nil { return err } } // we need to manually join the freezer and cpuset cgroup in systemd // because it does not currently support it via the dbus api. if err := joinFreezer(c, pid); err != nil { return err } if err := joinCpuset(c, pid); err != nil { return err } // FIXME: Systemd does have `BlockIODeviceWeight` property, but we got problem // using that (at least on systemd 208, see https://github.com/docker/libcontainer/pull/354), // so use fs work around for now. if err := joinBlkio(c, pid); err != nil { return err } paths := make(map[string]string) for sysname := range subsystems { subsystemPath, err := getSubsystemPath(m.Cgroups, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return err } paths[sysname] = subsystemPath } m.Paths = paths return nil }
func Apply(c *cgroups.Cgroup, pid int) (map[string]string, error) { var ( unitName = getUnitName(c) slice = "system.slice" properties []systemd.Property res = &systemdCgroup{} ) res.cgroup = c if c.Slice != "" { slice = c.Slice } properties = append(properties, systemd.PropSlice(slice), systemd.PropDescription("docker container "+c.Name), newProp("PIDs", []uint32{uint32(pid)}), ) // Always enable accounting, this gets us the same behaviour as the fs implementation, // plus the kernel has some problems with joining the memory cgroup at a later time. properties = append(properties, newProp("MemoryAccounting", true), newProp("CPUAccounting", true), newProp("BlockIOAccounting", true)) if hasTransientDefaultDependencies { properties = append(properties, newProp("DefaultDependencies", false)) } if c.Memory != 0 { properties = append(properties, newProp("MemoryLimit", uint64(c.Memory))) } // TODO: MemoryReservation and MemorySwap not available in systemd if c.CpuShares != 0 { properties = append(properties, newProp("CPUShares", uint64(c.CpuShares))) } if c.BlkioWeight != 0 { properties = append(properties, newProp("BlockIOWeight", uint64(c.BlkioWeight))) } if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil { return nil, err } if err := joinDevices(c, pid); err != nil { return nil, err } // -1 disables memorySwap if c.MemorySwap >= 0 && c.Memory != 0 { if err := joinMemory(c, pid); err != nil { return nil, err } } // we need to manually join the freezer and cpuset cgroup in systemd // because it does not currently support it via the dbus api. if err := joinFreezer(c, pid); err != nil { return nil, err } if err := joinCpuset(c, pid); err != nil { return nil, err } paths := make(map[string]string) for _, sysname := range []string{ "devices", "memory", "cpu", "cpuset", "cpuacct", "blkio", "perf_event", "freezer", } { subsystemPath, err := getSubsystemPath(res.cgroup, sysname) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return nil, err } paths[sysname] = subsystemPath } return paths, nil }
func (m *Manager) Apply(pid int) error { var ( c = m.Cgroups unitName = getUnitName(c) slice = "system.slice" properties []systemdDbus.Property ) if c.Paths != nil { paths := make(map[string]string) for name, path := range c.Paths { _, err := getSubsystemPath(m.Cgroups, name) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return err } paths[name] = path } m.Paths = paths return cgroups.EnterPid(m.Paths, pid) } if c.Parent != "" { slice = c.Parent } properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name)) // if we create a slice, the parent is defined via a Wants= if strings.HasSuffix(unitName, ".slice") { // This was broken until systemd v229, but has been back-ported on RHEL environments >= 219 if !hasStartTransientSliceUnit { return fmt.Errorf("systemd version does not support ability to start a slice as transient unit") } properties = append(properties, systemdDbus.PropWants(slice)) } else { // otherwise, we use Slice= properties = append(properties, systemdDbus.PropSlice(slice)) } // only add pid if its valid, -1 is used w/ general slice creation. if pid != -1 { properties = append(properties, newProp("PIDs", []uint32{uint32(pid)})) } if hasDelegate { // This is only supported on systemd versions 218 and above. properties = append(properties, newProp("Delegate", true)) } // Always enable accounting, this gets us the same behaviour as the fs implementation, // plus the kernel has some problems with joining the memory cgroup at a later time. properties = append(properties, newProp("MemoryAccounting", true), newProp("CPUAccounting", true), newProp("BlockIOAccounting", true)) if hasTransientDefaultDependencies { properties = append(properties, newProp("DefaultDependencies", false)) } if c.Resources.Memory != 0 { properties = append(properties, newProp("MemoryLimit", uint64(c.Resources.Memory))) } if c.Resources.CpuShares != 0 { properties = append(properties, newProp("CPUShares", uint64(c.Resources.CpuShares))) } if c.Resources.BlkioWeight != 0 { properties = append(properties, newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight))) } // We have to set kernel memory here, as we can't change it once // processes have been attached to the cgroup. if c.Resources.KernelMemory != 0 { if err := setKernelMemory(c); err != nil { return err } } if _, err := theConn.StartTransientUnit(unitName, "replace", properties, nil); err != nil { return err } if err := joinCgroups(c, pid); err != nil { return err } paths := make(map[string]string) for _, s := range subsystems { subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name()) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { continue } return err } paths[s.Name()] = subsystemPath } m.Paths = paths return nil }