driver_unix.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // +build !windows
  2. package execdriver
  3. import (
  4. "encoding/json"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/docker/docker/daemon/execdriver/native/template"
  12. "github.com/docker/docker/pkg/mount"
  13. "github.com/docker/docker/pkg/ulimit"
  14. "github.com/opencontainers/runc/libcontainer"
  15. "github.com/opencontainers/runc/libcontainer/cgroups/fs"
  16. "github.com/opencontainers/runc/libcontainer/configs"
  17. )
  18. // Mount contains information for a mount operation.
  19. type Mount struct {
  20. Source string `json:"source"`
  21. Destination string `json:"destination"`
  22. Writable bool `json:"writable"`
  23. Private bool `json:"private"`
  24. Slave bool `json:"slave"`
  25. }
  26. // Resources contains all resource configs for a driver.
  27. // Currently these are all for cgroup configs.
  28. type Resources struct {
  29. CommonResources
  30. // Fields below here are platform specific
  31. MemorySwap int64 `json:"memory_swap"`
  32. KernelMemory int64 `json:"kernel_memory"`
  33. CPUQuota int64 `json:"cpu_quota"`
  34. CpusetCpus string `json:"cpuset_cpus"`
  35. CpusetMems string `json:"cpuset_mems"`
  36. CPUPeriod int64 `json:"cpu_period"`
  37. Rlimits []*ulimit.Rlimit `json:"rlimits"`
  38. OomKillDisable bool `json:"oom_kill_disable"`
  39. MemorySwappiness int64 `json:"memory_swappiness"`
  40. }
  41. // Network settings of the container
  42. type Network struct {
  43. Mtu int `json:"mtu"`
  44. ContainerID string `json:"container_id"` // id of the container to join network.
  45. NamespacePath string `json:"namespace_path"`
  46. HostNetworking bool `json:"host_networking"`
  47. }
  48. // InitContainer is the initialization of a container config.
  49. // It returns the initial configs for a container. It's mostly
  50. // defined by the default template.
  51. func InitContainer(c *Command) *configs.Config {
  52. container := template.New()
  53. container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
  54. container.Cgroups.Name = c.ID
  55. container.Cgroups.AllowedDevices = c.AllowedDevices
  56. container.Devices = c.AutoCreatedDevices
  57. container.Rootfs = c.Rootfs
  58. container.Readonlyfs = c.ReadonlyRootfs
  59. container.RootPropagation = mount.RPRIVATE
  60. // check to see if we are running in ramdisk to disable pivot root
  61. container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
  62. // Default parent cgroup is "docker". Override if required.
  63. if c.CgroupParent != "" {
  64. container.Cgroups.Parent = c.CgroupParent
  65. }
  66. return container
  67. }
  68. func getEnv(key string, env []string) string {
  69. for _, pair := range env {
  70. parts := strings.SplitN(pair, "=", 2)
  71. if parts[0] == key {
  72. return parts[1]
  73. }
  74. }
  75. return ""
  76. }
  77. // SetupCgroups setups cgroup resources for a container.
  78. func SetupCgroups(container *configs.Config, c *Command) error {
  79. if c.Resources != nil {
  80. container.Cgroups.CpuShares = c.Resources.CPUShares
  81. container.Cgroups.Memory = c.Resources.Memory
  82. container.Cgroups.MemoryReservation = c.Resources.MemoryReservation
  83. container.Cgroups.MemorySwap = c.Resources.MemorySwap
  84. container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
  85. container.Cgroups.CpusetMems = c.Resources.CpusetMems
  86. container.Cgroups.CpuPeriod = c.Resources.CPUPeriod
  87. container.Cgroups.CpuQuota = c.Resources.CPUQuota
  88. container.Cgroups.BlkioWeight = c.Resources.BlkioWeight
  89. container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
  90. container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness
  91. }
  92. return nil
  93. }
  94. // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
  95. func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) {
  96. out := &libcontainer.NetworkInterface{Name: interfaceName}
  97. // This can happen if the network runtime information is missing - possible if the
  98. // container was created by an old version of libcontainer.
  99. if interfaceName == "" {
  100. return out, nil
  101. }
  102. type netStatsPair struct {
  103. // Where to write the output.
  104. Out *uint64
  105. // The network stats file to read.
  106. File string
  107. }
  108. // 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.
  109. netStats := []netStatsPair{
  110. {Out: &out.RxBytes, File: "tx_bytes"},
  111. {Out: &out.RxPackets, File: "tx_packets"},
  112. {Out: &out.RxErrors, File: "tx_errors"},
  113. {Out: &out.RxDropped, File: "tx_dropped"},
  114. {Out: &out.TxBytes, File: "rx_bytes"},
  115. {Out: &out.TxPackets, File: "rx_packets"},
  116. {Out: &out.TxErrors, File: "rx_errors"},
  117. {Out: &out.TxDropped, File: "rx_dropped"},
  118. }
  119. for _, netStat := range netStats {
  120. data, err := readSysfsNetworkStats(interfaceName, netStat.File)
  121. if err != nil {
  122. return nil, err
  123. }
  124. *(netStat.Out) = data
  125. }
  126. return out, nil
  127. }
  128. // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
  129. func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
  130. data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
  131. if err != nil {
  132. return 0, err
  133. }
  134. return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
  135. }
  136. // Stats collects all the resource usage information from a container.
  137. func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) {
  138. f, err := os.Open(filepath.Join(containerDir, "state.json"))
  139. if err != nil {
  140. return nil, err
  141. }
  142. defer f.Close()
  143. type network struct {
  144. Type string
  145. HostInterfaceName string
  146. }
  147. state := struct {
  148. CgroupPaths map[string]string `json:"cgroup_paths"`
  149. Networks []network
  150. }{}
  151. if err := json.NewDecoder(f).Decode(&state); err != nil {
  152. return nil, err
  153. }
  154. now := time.Now()
  155. mgr := fs.Manager{Paths: state.CgroupPaths}
  156. cstats, err := mgr.GetStats()
  157. if err != nil {
  158. return nil, err
  159. }
  160. stats := &libcontainer.Stats{CgroupStats: cstats}
  161. // if the container does not have any memory limit specified set the
  162. // limit to the machines memory
  163. memoryLimit := containerMemoryLimit
  164. if memoryLimit == 0 {
  165. memoryLimit = machineMemory
  166. }
  167. for _, iface := range state.Networks {
  168. switch iface.Type {
  169. case "veth":
  170. istats, err := getNetworkInterfaceStats(iface.HostInterfaceName)
  171. if err != nil {
  172. return nil, err
  173. }
  174. stats.Interfaces = append(stats.Interfaces, istats)
  175. }
  176. }
  177. return &ResourceStats{
  178. Stats: stats,
  179. Read: now,
  180. MemoryLimit: memoryLimit,
  181. }, nil
  182. }