container_manager_linux.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // +build linux
  2. /*
  3. Copyright 2016 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 cm
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "regexp"
  19. "strconv"
  20. "time"
  21. "github.com/opencontainers/runc/libcontainer/cgroups/fs"
  22. "github.com/opencontainers/runc/libcontainer/configs"
  23. utilversion "k8s.io/apimachinery/pkg/util/version"
  24. "k8s.io/apimachinery/pkg/util/wait"
  25. "k8s.io/klog"
  26. kubecm "k8s.io/kubernetes/pkg/kubelet/cm"
  27. "k8s.io/kubernetes/pkg/kubelet/qos"
  28. "k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
  29. )
  30. const (
  31. // The percent of the machine memory capacity.
  32. dockerMemoryLimitThresholdPercent = kubecm.DockerMemoryLimitThresholdPercent
  33. // The minimum memory limit allocated to docker container.
  34. minDockerMemoryLimit = kubecm.MinDockerMemoryLimit
  35. // The Docker OOM score adjustment.
  36. dockerOOMScoreAdj = qos.DockerOOMScoreAdj
  37. )
  38. var (
  39. memoryCapacityRegexp = regexp.MustCompile(`MemTotal:\s*([0-9]+) kB`)
  40. )
  41. // NewContainerManager creates a new instance of ContainerManager
  42. func NewContainerManager(cgroupsName string, client libdocker.Interface) ContainerManager {
  43. return &containerManager{
  44. cgroupsName: cgroupsName,
  45. client: client,
  46. }
  47. }
  48. type containerManager struct {
  49. // Docker client.
  50. client libdocker.Interface
  51. // Name of the cgroups.
  52. cgroupsName string
  53. // Manager for the cgroups.
  54. cgroupsManager *fs.Manager
  55. }
  56. func (m *containerManager) Start() error {
  57. // TODO: check if the required cgroups are mounted.
  58. if len(m.cgroupsName) != 0 {
  59. manager, err := createCgroupManager(m.cgroupsName)
  60. if err != nil {
  61. return err
  62. }
  63. m.cgroupsManager = manager
  64. }
  65. go wait.Until(m.doWork, 5*time.Minute, wait.NeverStop)
  66. return nil
  67. }
  68. func (m *containerManager) doWork() {
  69. v, err := m.client.Version()
  70. if err != nil {
  71. klog.Errorf("Unable to get docker version: %v", err)
  72. return
  73. }
  74. version, err := utilversion.ParseGeneric(v.APIVersion)
  75. if err != nil {
  76. klog.Errorf("Unable to parse docker version %q: %v", v.APIVersion, err)
  77. return
  78. }
  79. // EnsureDockerInContainer does two things.
  80. // 1. Ensure processes run in the cgroups if m.cgroupsManager is not nil.
  81. // 2. Ensure processes have the OOM score applied.
  82. if err := kubecm.EnsureDockerInContainer(version, dockerOOMScoreAdj, m.cgroupsManager); err != nil {
  83. klog.Errorf("Unable to ensure the docker processes run in the desired containers: %v", err)
  84. }
  85. }
  86. func createCgroupManager(name string) (*fs.Manager, error) {
  87. var memoryLimit uint64
  88. memoryCapacity, err := getMemoryCapacity()
  89. if err != nil {
  90. klog.Errorf("Failed to get the memory capacity on machine: %v", err)
  91. } else {
  92. memoryLimit = memoryCapacity * dockerMemoryLimitThresholdPercent / 100
  93. }
  94. if err != nil || memoryLimit < minDockerMemoryLimit {
  95. memoryLimit = minDockerMemoryLimit
  96. }
  97. klog.V(2).Infof("Configure resource-only container %q with memory limit: %d", name, memoryLimit)
  98. allowAllDevices := true
  99. cm := &fs.Manager{
  100. Cgroups: &configs.Cgroup{
  101. Parent: "/",
  102. Name: name,
  103. Resources: &configs.Resources{
  104. Memory: int64(memoryLimit),
  105. MemorySwap: -1,
  106. AllowAllDevices: &allowAllDevices,
  107. },
  108. },
  109. }
  110. return cm, nil
  111. }
  112. // getMemoryCapacity returns the memory capacity on the machine in bytes.
  113. func getMemoryCapacity() (uint64, error) {
  114. out, err := ioutil.ReadFile("/proc/meminfo")
  115. if err != nil {
  116. return 0, err
  117. }
  118. return parseCapacity(out, memoryCapacityRegexp)
  119. }
  120. // parseCapacity matches a Regexp in a []byte, returning the resulting value in bytes.
  121. // Assumes that the value matched by the Regexp is in KB.
  122. func parseCapacity(b []byte, r *regexp.Regexp) (uint64, error) {
  123. matches := r.FindSubmatch(b)
  124. if len(matches) != 2 {
  125. return 0, fmt.Errorf("failed to match regexp in output: %q", string(b))
  126. }
  127. m, err := strconv.ParseUint(string(matches[1]), 10, 64)
  128. if err != nil {
  129. return 0, err
  130. }
  131. // Convert to bytes.
  132. return m * 1024, err
  133. }