Explorar el Código

Merge pull request #41016 from kolyshkin/cgroup-init

Brian Goff hace 5 años
padre
commit
260c26b7be

+ 17 - 39
daemon/daemon_unix.go

@@ -500,8 +500,8 @@ func verifyPlatformContainerResources(resources *containertypes.Resources, sysIn
 	if resources.NanoCPUs > 0 && resources.CPUQuota > 0 {
 	if resources.NanoCPUs > 0 && resources.CPUQuota > 0 {
 		return warnings, fmt.Errorf("Conflicting options: Nano CPUs and CPU Quota cannot both be set")
 		return warnings, fmt.Errorf("Conflicting options: Nano CPUs and CPU Quota cannot both be set")
 	}
 	}
-	if resources.NanoCPUs > 0 && (!sysInfo.CPUCfsPeriod || !sysInfo.CPUCfsQuota) {
-		return warnings, fmt.Errorf("NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted")
+	if resources.NanoCPUs > 0 && !sysInfo.CPUCfs {
+		return warnings, fmt.Errorf("NanoCPUs can not be set, as your kernel does not support CPU CFS scheduler or the cgroup is not mounted")
 	}
 	}
 	// The highest precision we could get on Linux is 0.001, by setting
 	// The highest precision we could get on Linux is 0.001, by setting
 	//   cpu.cfs_period_us=1000ms
 	//   cpu.cfs_period_us=1000ms
@@ -518,17 +518,14 @@ func verifyPlatformContainerResources(resources *containertypes.Resources, sysIn
 		warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
 		warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
 		resources.CPUShares = 0
 		resources.CPUShares = 0
 	}
 	}
-	if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
-		warnings = append(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
+	if (resources.CPUPeriod != 0 || resources.CPUQuota != 0) && !sysInfo.CPUCfs {
+		warnings = append(warnings, "Your kernel does not support CPU CFS scheduler. CPU period/quota discarded.")
 		resources.CPUPeriod = 0
 		resources.CPUPeriod = 0
+		resources.CPUQuota = 0
 	}
 	}
 	if resources.CPUPeriod != 0 && (resources.CPUPeriod < 1000 || resources.CPUPeriod > 1000000) {
 	if resources.CPUPeriod != 0 && (resources.CPUPeriod < 1000 || resources.CPUPeriod > 1000000) {
 		return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
 		return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
 	}
 	}
-	if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
-		warnings = append(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
-		resources.CPUQuota = 0
-	}
 	if resources.CPUQuota > 0 && resources.CPUQuota < 1000 {
 	if resources.CPUQuota > 0 && resources.CPUQuota < 1000 {
 		return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
 		return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
 	}
 	}
@@ -1649,51 +1646,32 @@ func setupOOMScoreAdj(score int) error {
 	return err
 	return err
 }
 }
 
 
-func (daemon *Daemon) initCgroupsPath(path string) error {
+func (daemon *Daemon) initCPURtController(mnt, path string) error {
 	if path == "/" || path == "." {
 	if path == "/" || path == "." {
 		return nil
 		return nil
 	}
 	}
 
 
-	if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 {
-		return nil
-	}
-
-	if cgroups.IsCgroup2UnifiedMode() {
-		return fmt.Errorf("daemon-scoped cpu-rt-period and cpu-rt-runtime are not implemented for cgroup v2")
-	}
-
 	// Recursively create cgroup to ensure that the system and all parent cgroups have values set
 	// Recursively create cgroup to ensure that the system and all parent cgroups have values set
 	// for the period and runtime as this limits what the children can be set to.
 	// for the period and runtime as this limits what the children can be set to.
-	daemon.initCgroupsPath(filepath.Dir(path))
-
-	mnt, root, err := cgroups.FindCgroupMountpointAndRoot("", "cpu")
-	if err != nil {
+	if err := daemon.initCPURtController(mnt, filepath.Dir(path)); err != nil {
 		return err
 		return err
 	}
 	}
-	// When docker is run inside docker, the root is based of the host cgroup.
-	// Should this be handled in runc/libcontainer/cgroups ?
-	if strings.HasPrefix(root, "/docker/") {
-		root = "/"
-	}
 
 
-	path = filepath.Join(mnt, root, path)
-	sysInfo := daemon.RawSysInfo(true)
-	if err := maybeCreateCPURealTimeFile(sysInfo.CPURealtimePeriod, daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil {
+	path = filepath.Join(mnt, path)
+	if err := os.MkdirAll(path, 0755); err != nil {
 		return err
 		return err
 	}
 	}
-	return maybeCreateCPURealTimeFile(sysInfo.CPURealtimeRuntime, daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path)
+	if err := maybeCreateCPURealTimeFile(daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil {
+		return err
+	}
+	return maybeCreateCPURealTimeFile(daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path)
 }
 }
 
 
-func maybeCreateCPURealTimeFile(sysinfoPresent bool, configValue int64, file string, path string) error {
-	if sysinfoPresent && configValue != 0 {
-		if err := os.MkdirAll(path, 0755); err != nil {
-			return err
-		}
-		if err := ioutil.WriteFile(filepath.Join(path, file), []byte(strconv.FormatInt(configValue, 10)), 0700); err != nil {
-			return err
-		}
+func maybeCreateCPURealTimeFile(configValue int64, file string, path string) error {
+	if configValue == 0 {
+		return nil
 	}
 	}
-	return nil
+	return ioutil.WriteFile(filepath.Join(path, file), []byte(strconv.FormatInt(configValue, 10)), 0700)
 }
 }
 
 
 func (daemon *Daemon) setupSeccompProfile() error {
 func (daemon *Daemon) setupSeccompProfile() error {

+ 2 - 2
daemon/info_unix.go

@@ -30,8 +30,8 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
 	v.KernelMemory = sysInfo.KernelMemory
 	v.KernelMemory = sysInfo.KernelMemory
 	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
 	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
 	v.OomKillDisable = sysInfo.OomKillDisable
 	v.OomKillDisable = sysInfo.OomKillDisable
-	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
-	v.CPUCfsQuota = sysInfo.CPUCfsQuota
+	v.CPUCfsPeriod = sysInfo.CPUCfs
+	v.CPUCfsQuota = sysInfo.CPUCfs
 	v.CPUShares = sysInfo.CPUShares
 	v.CPUShares = sysInfo.CPUShares
 	v.CPUSet = sysInfo.Cpuset
 	v.CPUSet = sysInfo.Cpuset
 	v.PidsLimit = sysInfo.PidsLimit
 	v.PidsLimit = sysInfo.PidsLimit

+ 32 - 4
daemon/oci_linux.go

@@ -824,15 +824,32 @@ func WithCgroups(daemon *Daemon, c *container.Container) coci.SpecOpts {
 			cgroupsPath = filepath.Join(parent, c.ID)
 			cgroupsPath = filepath.Join(parent, c.ID)
 		}
 		}
 		s.Linux.CgroupsPath = cgroupsPath
 		s.Linux.CgroupsPath = cgroupsPath
+
+		// the rest is only needed for CPU RT controller
+
+		if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 {
+			return nil
+		}
+
+		if cgroups.IsCgroup2UnifiedMode() {
+			return errors.New("daemon-scoped cpu-rt-period and cpu-rt-runtime are not implemented for cgroup v2")
+		}
+
+		// FIXME this is very expensive way to check if cpu rt is supported
+		sysInfo := daemon.RawSysInfo(true)
+		if !sysInfo.CPURealtime {
+			return errors.New("daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by the kernel")
+		}
+
 		p := cgroupsPath
 		p := cgroupsPath
 		if useSystemd {
 		if useSystemd {
 			initPath, err := cgroups.GetInitCgroup("cpu")
 			initPath, err := cgroups.GetInitCgroup("cpu")
 			if err != nil {
 			if err != nil {
-				return err
+				return errors.Wrap(err, "unable to init CPU RT controller")
 			}
 			}
 			_, err = cgroups.GetOwnCgroup("cpu")
 			_, err = cgroups.GetOwnCgroup("cpu")
 			if err != nil {
 			if err != nil {
-				return err
+				return errors.Wrap(err, "unable to init CPU RT controller")
 			}
 			}
 			p = filepath.Join(initPath, s.Linux.CgroupsPath)
 			p = filepath.Join(initPath, s.Linux.CgroupsPath)
 		}
 		}
@@ -843,8 +860,19 @@ func WithCgroups(daemon *Daemon, c *container.Container) coci.SpecOpts {
 			parentPath = filepath.Clean("/" + parentPath)
 			parentPath = filepath.Clean("/" + parentPath)
 		}
 		}
 
 
-		if err := daemon.initCgroupsPath(parentPath); err != nil {
-			return fmt.Errorf("linux init cgroups path: %v", err)
+		mnt, root, err := cgroups.FindCgroupMountpointAndRoot("", "cpu")
+		if err != nil {
+			return errors.Wrap(err, "unable to init CPU RT controller")
+		}
+		// When docker is run inside docker, the root is based of the host cgroup.
+		// Should this be handled in runc/libcontainer/cgroups ?
+		if strings.HasPrefix(root, "/docker/") {
+			root = "/"
+		}
+		mnt = filepath.Join(mnt, root)
+
+		if err := daemon.initCPURtController(mnt, parentPath); err != nil {
+			return errors.Wrap(err, "unable to init CPU RT controller")
 		}
 		}
 		return nil
 		return nil
 	}
 	}

+ 2 - 4
pkg/sysinfo/cgroup2_linux.go

@@ -90,10 +90,8 @@ func applyCPUCgroupInfoV2(info *SysInfo, controllers map[string]struct{}, _ stri
 		return warnings
 		return warnings
 	}
 	}
 	info.CPUShares = true
 	info.CPUShares = true
-	info.CPUCfsPeriod = true
-	info.CPUCfsQuota = true
-	info.CPURealtimePeriod = false
-	info.CPURealtimeRuntime = false
+	info.CPUCfs = true
+	info.CPURealtime = false
 	return warnings
 	return warnings
 }
 }
 
 

+ 4 - 10
pkg/sysinfo/sysinfo.go

@@ -62,17 +62,11 @@ type cgroupCPUInfo struct {
 	// Whether CPU shares is supported or not
 	// Whether CPU shares is supported or not
 	CPUShares bool
 	CPUShares bool
 
 
-	// Whether CPU CFS(Completely Fair Scheduler) period is supported or not
-	CPUCfsPeriod bool
+	// Whether CPU CFS (Completely Fair Scheduler) is supported
+	CPUCfs bool
 
 
-	// Whether CPU CFS(Completely Fair Scheduler) quota is supported or not
-	CPUCfsQuota bool
-
-	// Whether CPU real-time period is supported or not
-	CPURealtimePeriod bool
-
-	// Whether CPU real-time runtime is supported or not
-	CPURealtimeRuntime bool
+	// Whether CPU real-time scheduler is supported
+	CPURealtime bool
 }
 }
 
 
 type cgroupBlkioInfo struct {
 type cgroupBlkioInfo struct {

+ 7 - 17
pkg/sysinfo/sysinfo_linux.go

@@ -144,27 +144,17 @@ func applyCPUCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
 
 
 	info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares")
 	info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares")
 	if !info.CPUShares {
 	if !info.CPUShares {
-		warnings = append(warnings, "Your kernel does not support cgroup cpu shares")
+		warnings = append(warnings, "Your kernel does not support CPU shares")
 	}
 	}
 
 
-	info.CPUCfsPeriod = cgroupEnabled(mountPoint, "cpu.cfs_period_us")
-	if !info.CPUCfsPeriod {
-		warnings = append(warnings, "Your kernel does not support cgroup cfs period")
+	info.CPUCfs = cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
+	if !info.CPUCfs {
+		warnings = append(warnings, "Your kernel does not support CPU CFS scheduler")
 	}
 	}
 
 
-	info.CPUCfsQuota = cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
-	if !info.CPUCfsQuota {
-		warnings = append(warnings, "Your kernel does not support cgroup cfs quotas")
-	}
-
-	info.CPURealtimePeriod = cgroupEnabled(mountPoint, "cpu.rt_period_us")
-	if !info.CPURealtimePeriod {
-		warnings = append(warnings, "Your kernel does not support cgroup rt period")
-	}
-
-	info.CPURealtimeRuntime = cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
-	if !info.CPURealtimeRuntime {
-		warnings = append(warnings, "Your kernel does not support cgroup rt runtime")
+	info.CPURealtime = cgroupEnabled(mountPoint, "cpu.rt_period_us")
+	if !info.CPURealtime {
+		warnings = append(warnings, "Your kernel does not support CPU realtime scheduler")
 	}
 	}
 
 
 	return warnings
 	return warnings

+ 26 - 32
runconfig/hostconfig_test.go

@@ -240,46 +240,41 @@ func TestDecodeHostConfig(t *testing.T) {
 
 
 func TestValidateResources(t *testing.T) {
 func TestValidateResources(t *testing.T) {
 	type resourceTest struct {
 	type resourceTest struct {
-		ConfigCPURealtimePeriod   int64
-		ConfigCPURealtimeRuntime  int64
-		SysInfoCPURealtimePeriod  bool
-		SysInfoCPURealtimeRuntime bool
-		ErrorExpected             bool
-		FailureMsg                string
+		ConfigCPURealtimePeriod  int64
+		ConfigCPURealtimeRuntime int64
+		SysInfoCPURealtime       bool
+		ErrorExpected            bool
+		FailureMsg               string
 	}
 	}
 
 
 	tests := []resourceTest{
 	tests := []resourceTest{
 		{
 		{
-			ConfigCPURealtimePeriod:   1000,
-			ConfigCPURealtimeRuntime:  1000,
-			SysInfoCPURealtimePeriod:  true,
-			SysInfoCPURealtimeRuntime: true,
-			ErrorExpected:             false,
-			FailureMsg:                "Expected valid configuration",
+			ConfigCPURealtimePeriod:  1000,
+			ConfigCPURealtimeRuntime: 1000,
+			SysInfoCPURealtime:       true,
+			ErrorExpected:            false,
+			FailureMsg:               "Expected valid configuration",
 		},
 		},
 		{
 		{
-			ConfigCPURealtimePeriod:   5000,
-			ConfigCPURealtimeRuntime:  5000,
-			SysInfoCPURealtimePeriod:  false,
-			SysInfoCPURealtimeRuntime: true,
-			ErrorExpected:             true,
-			FailureMsg:                "Expected failure when cpu-rt-period is set but kernel doesn't support it",
+			ConfigCPURealtimePeriod:  5000,
+			ConfigCPURealtimeRuntime: 5000,
+			SysInfoCPURealtime:       false,
+			ErrorExpected:            true,
+			FailureMsg:               "Expected failure when cpu-rt-period is set but kernel doesn't support it",
 		},
 		},
 		{
 		{
-			ConfigCPURealtimePeriod:   5000,
-			ConfigCPURealtimeRuntime:  5000,
-			SysInfoCPURealtimePeriod:  true,
-			SysInfoCPURealtimeRuntime: false,
-			ErrorExpected:             true,
-			FailureMsg:                "Expected failure when cpu-rt-runtime is set but kernel doesn't support it",
+			ConfigCPURealtimePeriod:  5000,
+			ConfigCPURealtimeRuntime: 5000,
+			SysInfoCPURealtime:       false,
+			ErrorExpected:            true,
+			FailureMsg:               "Expected failure when cpu-rt-runtime is set but kernel doesn't support it",
 		},
 		},
 		{
 		{
-			ConfigCPURealtimePeriod:   5000,
-			ConfigCPURealtimeRuntime:  10000,
-			SysInfoCPURealtimePeriod:  true,
-			SysInfoCPURealtimeRuntime: false,
-			ErrorExpected:             true,
-			FailureMsg:                "Expected failure when cpu-rt-runtime is greater than cpu-rt-period",
+			ConfigCPURealtimePeriod:  5000,
+			ConfigCPURealtimeRuntime: 10000,
+			SysInfoCPURealtime:       true,
+			ErrorExpected:            true,
+			FailureMsg:               "Expected failure when cpu-rt-runtime is greater than cpu-rt-period",
 		},
 		},
 	}
 	}
 
 
@@ -289,8 +284,7 @@ func TestValidateResources(t *testing.T) {
 		hc.Resources.CPURealtimeRuntime = rt.ConfigCPURealtimeRuntime
 		hc.Resources.CPURealtimeRuntime = rt.ConfigCPURealtimeRuntime
 
 
 		var si sysinfo.SysInfo
 		var si sysinfo.SysInfo
-		si.CPURealtimePeriod = rt.SysInfoCPURealtimePeriod
-		si.CPURealtimeRuntime = rt.SysInfoCPURealtimeRuntime
+		si.CPURealtime = rt.SysInfoCPURealtime
 
 
 		if err := validateResources(&hc, &si); (err != nil) != rt.ErrorExpected {
 		if err := validateResources(&hc, &si); (err != nil) != rt.ErrorExpected {
 			t.Fatal(rt.FailureMsg, err)
 			t.Fatal(rt.FailureMsg, err)

+ 2 - 6
runconfig/hostconfig_unix.go

@@ -85,12 +85,8 @@ func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
 		return nil
 		return nil
 	}
 	}
 
 
-	if hc.Resources.CPURealtimePeriod > 0 && !si.CPURealtimePeriod {
-		return fmt.Errorf("Your kernel does not support cgroup cpu real-time period")
-	}
-
-	if hc.Resources.CPURealtimeRuntime > 0 && !si.CPURealtimeRuntime {
-		return fmt.Errorf("Your kernel does not support cgroup cpu real-time runtime")
+	if (hc.Resources.CPURealtimePeriod != 0 || hc.Resources.CPURealtimeRuntime != 0) && !si.CPURealtime {
+		return fmt.Errorf("Your kernel does not support CPU real-time scheduler")
 	}
 	}
 
 
 	if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod {
 	if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod {