driver_linux.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package execdriver
  2. import (
  3. "encoding/json"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "github.com/docker/docker/daemon/execdriver/native/template"
  11. "github.com/docker/libcontainer"
  12. "github.com/docker/libcontainer/cgroups/fs"
  13. "github.com/docker/libcontainer/configs"
  14. )
  15. func InitContainer(c *Command) *configs.Config {
  16. container := template.New()
  17. container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
  18. container.Cgroups.Name = c.ID
  19. container.Cgroups.AllowedDevices = c.AllowedDevices
  20. container.Devices = c.AutoCreatedDevices
  21. container.Rootfs = c.Rootfs
  22. container.Readonlyfs = c.ReadonlyRootfs
  23. container.Privatefs = true
  24. // check to see if we are running in ramdisk to disable pivot root
  25. container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
  26. // Default parent cgroup is "docker". Override if required.
  27. if c.CgroupParent != "" {
  28. container.Cgroups.Parent = c.CgroupParent
  29. }
  30. return container
  31. }
  32. func getEnv(key string, env []string) string {
  33. for _, pair := range env {
  34. parts := strings.SplitN(pair, "=", 2)
  35. if parts[0] == key {
  36. return parts[1]
  37. }
  38. }
  39. return ""
  40. }
  41. func SetupCgroups(container *configs.Config, c *Command) error {
  42. if c.Resources != nil {
  43. container.Cgroups.CpuShares = c.Resources.CpuShares
  44. container.Cgroups.Memory = c.Resources.Memory
  45. container.Cgroups.MemoryReservation = c.Resources.Memory
  46. container.Cgroups.MemorySwap = c.Resources.MemorySwap
  47. container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
  48. container.Cgroups.CpusetMems = c.Resources.CpusetMems
  49. container.Cgroups.CpuPeriod = c.Resources.CpuPeriod
  50. container.Cgroups.CpuQuota = c.Resources.CpuQuota
  51. container.Cgroups.BlkioWeight = c.Resources.BlkioWeight
  52. container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
  53. container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness
  54. }
  55. return nil
  56. }
  57. // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
  58. func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) {
  59. out := &libcontainer.NetworkInterface{Name: interfaceName}
  60. // This can happen if the network runtime information is missing - possible if the
  61. // container was created by an old version of libcontainer.
  62. if interfaceName == "" {
  63. return out, nil
  64. }
  65. type netStatsPair struct {
  66. // Where to write the output.
  67. Out *uint64
  68. // The network stats file to read.
  69. File string
  70. }
  71. // Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container.
  72. netStats := []netStatsPair{
  73. {Out: &out.RxBytes, File: "tx_bytes"},
  74. {Out: &out.RxPackets, File: "tx_packets"},
  75. {Out: &out.RxErrors, File: "tx_errors"},
  76. {Out: &out.RxDropped, File: "tx_dropped"},
  77. {Out: &out.TxBytes, File: "rx_bytes"},
  78. {Out: &out.TxPackets, File: "rx_packets"},
  79. {Out: &out.TxErrors, File: "rx_errors"},
  80. {Out: &out.TxDropped, File: "rx_dropped"},
  81. }
  82. for _, netStat := range netStats {
  83. data, err := readSysfsNetworkStats(interfaceName, netStat.File)
  84. if err != nil {
  85. return nil, err
  86. }
  87. *(netStat.Out) = data
  88. }
  89. return out, nil
  90. }
  91. // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
  92. func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
  93. data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
  94. if err != nil {
  95. return 0, err
  96. }
  97. return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
  98. }
  99. func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) {
  100. f, err := os.Open(filepath.Join(containerDir, "state.json"))
  101. if err != nil {
  102. return nil, err
  103. }
  104. defer f.Close()
  105. type network struct {
  106. Type string
  107. HostInterfaceName string
  108. }
  109. state := struct {
  110. CgroupPaths map[string]string `json:"cgroup_paths"`
  111. Networks []network
  112. }{}
  113. if err := json.NewDecoder(f).Decode(&state); err != nil {
  114. return nil, err
  115. }
  116. now := time.Now()
  117. mgr := fs.Manager{Paths: state.CgroupPaths}
  118. cstats, err := mgr.GetStats()
  119. if err != nil {
  120. return nil, err
  121. }
  122. stats := &libcontainer.Stats{CgroupStats: cstats}
  123. // if the container does not have any memory limit specified set the
  124. // limit to the machines memory
  125. memoryLimit := containerMemoryLimit
  126. if memoryLimit == 0 {
  127. memoryLimit = machineMemory
  128. }
  129. for _, iface := range state.Networks {
  130. switch iface.Type {
  131. case "veth":
  132. istats, err := getNetworkInterfaceStats(iface.HostInterfaceName)
  133. if err != nil {
  134. return nil, err
  135. }
  136. stats.Interfaces = append(stats.Interfaces, istats)
  137. }
  138. }
  139. return &ResourceStats{
  140. Stats: stats,
  141. Read: now,
  142. MemoryLimit: memoryLimit,
  143. }, nil
  144. }