kuberuntime_container_windows.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // +build windows
  2. /*
  3. Copyright 2018 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package kuberuntime
  15. import (
  16. "fmt"
  17. "github.com/docker/docker/pkg/sysinfo"
  18. "k8s.io/api/core/v1"
  19. utilfeature "k8s.io/apiserver/pkg/util/feature"
  20. runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
  21. kubefeatures "k8s.io/kubernetes/pkg/features"
  22. kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
  23. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  24. "k8s.io/kubernetes/pkg/securitycontext"
  25. "k8s.io/klog"
  26. )
  27. // applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
  28. func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string, _ *kubecontainer.ContainerID) error {
  29. windowsConfig, err := m.generateWindowsContainerConfig(container, pod, uid, username)
  30. if err != nil {
  31. return err
  32. }
  33. config.Windows = windowsConfig
  34. return nil
  35. }
  36. // generateWindowsContainerConfig generates windows container config for kubelet runtime v1.
  37. // Refer https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/cri-windows.md.
  38. func (m *kubeGenericRuntimeManager) generateWindowsContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string) (*runtimeapi.WindowsContainerConfig, error) {
  39. wc := &runtimeapi.WindowsContainerConfig{
  40. Resources: &runtimeapi.WindowsContainerResources{},
  41. SecurityContext: &runtimeapi.WindowsContainerSecurityContext{},
  42. }
  43. cpuRequest := container.Resources.Requests.Cpu()
  44. cpuLimit := container.Resources.Limits.Cpu()
  45. isolatedByHyperv := kubeletapis.ShouldIsolatedByHyperV(pod.Annotations)
  46. if !cpuLimit.IsZero() {
  47. // Note that sysinfo.NumCPU() is limited to 64 CPUs on Windows due to Processor Groups,
  48. // as only 64 processors are available for execution by a given process. This causes
  49. // some oddities on systems with more than 64 processors.
  50. // Refer https://msdn.microsoft.com/en-us/library/windows/desktop/dd405503(v=vs.85).aspx.
  51. cpuMaximum := 10000 * cpuLimit.MilliValue() / int64(sysinfo.NumCPU()) / 1000
  52. if isolatedByHyperv {
  53. cpuCount := int64(cpuLimit.MilliValue()+999) / 1000
  54. wc.Resources.CpuCount = cpuCount
  55. if cpuCount != 0 {
  56. cpuMaximum = cpuLimit.MilliValue() / cpuCount * 10000 / 1000
  57. }
  58. }
  59. // ensure cpuMaximum is in range [1, 10000].
  60. if cpuMaximum < 1 {
  61. cpuMaximum = 1
  62. } else if cpuMaximum > 10000 {
  63. cpuMaximum = 10000
  64. }
  65. wc.Resources.CpuMaximum = cpuMaximum
  66. }
  67. cpuShares := milliCPUToShares(cpuLimit.MilliValue(), isolatedByHyperv)
  68. if cpuShares == 0 {
  69. cpuShares = milliCPUToShares(cpuRequest.MilliValue(), isolatedByHyperv)
  70. }
  71. wc.Resources.CpuShares = cpuShares
  72. if !isolatedByHyperv {
  73. // The processor resource controls are mutually exclusive on
  74. // Windows Server Containers, the order of precedence is
  75. // CPUCount first, then CPUShares, and CPUMaximum last.
  76. if wc.Resources.CpuCount > 0 {
  77. if wc.Resources.CpuShares > 0 {
  78. wc.Resources.CpuShares = 0
  79. klog.Warningf("Mutually exclusive options: CPUCount priority > CPUShares priority on Windows Server Containers. CPUShares should be ignored")
  80. }
  81. if wc.Resources.CpuMaximum > 0 {
  82. wc.Resources.CpuMaximum = 0
  83. klog.Warningf("Mutually exclusive options: CPUCount priority > CPUMaximum priority on Windows Server Containers. CPUMaximum should be ignored")
  84. }
  85. } else if wc.Resources.CpuShares > 0 {
  86. if wc.Resources.CpuMaximum > 0 {
  87. wc.Resources.CpuMaximum = 0
  88. klog.Warningf("Mutually exclusive options: CPUShares priority > CPUMaximum priority on Windows Server Containers. CPUMaximum should be ignored")
  89. }
  90. }
  91. }
  92. memoryLimit := container.Resources.Limits.Memory().Value()
  93. if memoryLimit != 0 {
  94. wc.Resources.MemoryLimitInBytes = memoryLimit
  95. }
  96. // setup security context
  97. effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
  98. // RunAsUser only supports int64 from Kubernetes API, but Windows containers only support username.
  99. if effectiveSc.RunAsUser != nil {
  100. return nil, fmt.Errorf("run as uid (%d) is not supported on Windows", *effectiveSc.RunAsUser)
  101. }
  102. if username != "" {
  103. wc.SecurityContext.RunAsUsername = username
  104. }
  105. if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.WindowsGMSA) &&
  106. effectiveSc.WindowsOptions != nil &&
  107. effectiveSc.WindowsOptions.GMSACredentialSpec != nil {
  108. wc.SecurityContext.CredentialSpec = *effectiveSc.WindowsOptions.GMSACredentialSpec
  109. }
  110. // override with Windows options if present
  111. if effectiveSc.WindowsOptions != nil && effectiveSc.WindowsOptions.RunAsUserName != nil {
  112. wc.SecurityContext.RunAsUsername = *effectiveSc.WindowsOptions.RunAsUserName
  113. }
  114. return wc, nil
  115. }