소스 검색

Merge pull request #41016 from kolyshkin/cgroup-init

Brian Goff 5 년 전
부모
커밋
260c26b7be
8개의 변경된 파일92개의 추가작업 그리고 114개의 파일을 삭제
  1. 17 39
      daemon/daemon_unix.go
  2. 2 2
      daemon/info_unix.go
  3. 32 4
      daemon/oci_linux.go
  4. 2 4
      pkg/sysinfo/cgroup2_linux.go
  5. 4 10
      pkg/sysinfo/sysinfo.go
  6. 7 17
      pkg/sysinfo/sysinfo_linux.go
  7. 26 32
      runconfig/hostconfig_test.go
  8. 2 6
      runconfig/hostconfig_unix.go

+ 17 - 39
daemon/daemon_unix.go

@@ -500,8 +500,8 @@ func verifyPlatformContainerResources(resources *containertypes.Resources, sysIn
 	if resources.NanoCPUs > 0 && resources.CPUQuota > 0 {
 		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
 	//   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.")
 		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.CPUQuota = 0
 	}
 	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)")
 	}
-	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 {
 		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
 }
 
-func (daemon *Daemon) initCgroupsPath(path string) error {
+func (daemon *Daemon) initCPURtController(mnt, path string) error {
 	if path == "/" || path == "." {
 		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
 	// 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
 	}
-	// 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 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 {

+ 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.KernelMemoryTCP = sysInfo.KernelMemoryTCP
 	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.CPUSet = sysInfo.Cpuset
 	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)
 		}
 		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
 		if useSystemd {
 			initPath, err := cgroups.GetInitCgroup("cpu")
 			if err != nil {
-				return err
+				return errors.Wrap(err, "unable to init CPU RT controller")
 			}
 			_, err = cgroups.GetOwnCgroup("cpu")
 			if err != nil {
-				return err
+				return errors.Wrap(err, "unable to init CPU RT controller")
 			}
 			p = filepath.Join(initPath, s.Linux.CgroupsPath)
 		}
@@ -843,8 +860,19 @@ func WithCgroups(daemon *Daemon, c *container.Container) coci.SpecOpts {
 			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
 	}

+ 2 - 4
pkg/sysinfo/cgroup2_linux.go

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

+ 4 - 10
pkg/sysinfo/sysinfo.go

@@ -62,17 +62,11 @@ type cgroupCPUInfo struct {
 	// Whether CPU shares is supported or not
 	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 {

+ 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")
 	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

+ 26 - 32
runconfig/hostconfig_test.go

@@ -240,46 +240,41 @@ func TestDecodeHostConfig(t *testing.T) {
 
 func TestValidateResources(t *testing.T) {
 	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{
 		{
-			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
 
 		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 {
 			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
 	}
 
-	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 {