driver_unix.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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/idtools"
  13. "github.com/docker/docker/pkg/mount"
  14. "github.com/docker/docker/pkg/ulimit"
  15. "github.com/opencontainers/runc/libcontainer"
  16. "github.com/opencontainers/runc/libcontainer/cgroups/fs"
  17. "github.com/opencontainers/runc/libcontainer/configs"
  18. )
  19. // Mount contains information for a mount operation.
  20. type Mount struct {
  21. Source string `json:"source"`
  22. Destination string `json:"destination"`
  23. Writable bool `json:"writable"`
  24. Private bool `json:"private"`
  25. Slave bool `json:"slave"`
  26. }
  27. // Resources contains all resource configs for a driver.
  28. // Currently these are all for cgroup configs.
  29. type Resources struct {
  30. CommonResources
  31. // Fields below here are platform specific
  32. MemorySwap int64 `json:"memory_swap"`
  33. KernelMemory int64 `json:"kernel_memory"`
  34. CPUQuota int64 `json:"cpu_quota"`
  35. CpusetCpus string `json:"cpuset_cpus"`
  36. CpusetMems string `json:"cpuset_mems"`
  37. CPUPeriod int64 `json:"cpu_period"`
  38. Rlimits []*ulimit.Rlimit `json:"rlimits"`
  39. OomKillDisable bool `json:"oom_kill_disable"`
  40. MemorySwappiness int64 `json:"memory_swappiness"`
  41. }
  42. // Ipc settings of the container
  43. // It is for IPC namespace setting. Usually different containers
  44. // have their own IPC namespace, however this specifies to use
  45. // an existing IPC namespace.
  46. // You can join the host's or a container's IPC namespace.
  47. type Ipc struct {
  48. ContainerID string `json:"container_id"` // id of the container to join ipc.
  49. HostIpc bool `json:"host_ipc"`
  50. }
  51. // Pid settings of the container
  52. // It is for PID namespace setting. Usually different containers
  53. // have their own PID namespace, however this specifies to use
  54. // an existing PID namespace.
  55. // Joining the host's PID namespace is currently the only supported
  56. // option.
  57. type Pid struct {
  58. HostPid bool `json:"host_pid"`
  59. }
  60. // UTS settings of the container
  61. // It is for UTS namespace setting. Usually different containers
  62. // have their own UTS namespace, however this specifies to use
  63. // an existing UTS namespace.
  64. // Joining the host's UTS namespace is currently the only supported
  65. // option.
  66. type UTS struct {
  67. HostUTS bool `json:"host_uts"`
  68. }
  69. // Network settings of the container
  70. type Network struct {
  71. Mtu int `json:"mtu"`
  72. ContainerID string `json:"container_id"` // id of the container to join network.
  73. NamespacePath string `json:"namespace_path"`
  74. HostNetworking bool `json:"host_networking"`
  75. }
  76. // Command wraps an os/exec.Cmd to add more metadata
  77. type Command struct {
  78. CommonCommand
  79. // Fields below here are platform specific
  80. AllowedDevices []*configs.Device `json:"allowed_devices"`
  81. AppArmorProfile string `json:"apparmor_profile"`
  82. AutoCreatedDevices []*configs.Device `json:"autocreated_devices"`
  83. CapAdd []string `json:"cap_add"`
  84. CapDrop []string `json:"cap_drop"`
  85. CgroupParent string `json:"cgroup_parent"` // The parent cgroup for this command.
  86. GIDMapping []idtools.IDMap `json:"gidmapping"`
  87. GroupAdd []string `json:"group_add"`
  88. Ipc *Ipc `json:"ipc"`
  89. Pid *Pid `json:"pid"`
  90. ReadonlyRootfs bool `json:"readonly_rootfs"`
  91. RemappedRoot *User `json:"remap_root"`
  92. UIDMapping []idtools.IDMap `json:"uidmapping"`
  93. UTS *UTS `json:"uts"`
  94. }
  95. // InitContainer is the initialization of a container config.
  96. // It returns the initial configs for a container. It's mostly
  97. // defined by the default template.
  98. func InitContainer(c *Command) *configs.Config {
  99. container := template.New()
  100. container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
  101. container.Cgroups.Name = c.ID
  102. container.Cgroups.AllowedDevices = c.AllowedDevices
  103. container.Devices = c.AutoCreatedDevices
  104. container.Rootfs = c.Rootfs
  105. container.Readonlyfs = c.ReadonlyRootfs
  106. container.RootPropagation = mount.RPRIVATE
  107. // check to see if we are running in ramdisk to disable pivot root
  108. container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
  109. // Default parent cgroup is "docker". Override if required.
  110. if c.CgroupParent != "" {
  111. container.Cgroups.Parent = c.CgroupParent
  112. }
  113. return container
  114. }
  115. func getEnv(key string, env []string) string {
  116. for _, pair := range env {
  117. parts := strings.SplitN(pair, "=", 2)
  118. if parts[0] == key {
  119. return parts[1]
  120. }
  121. }
  122. return ""
  123. }
  124. // SetupCgroups setups cgroup resources for a container.
  125. func SetupCgroups(container *configs.Config, c *Command) error {
  126. if c.Resources != nil {
  127. container.Cgroups.CpuShares = c.Resources.CPUShares
  128. container.Cgroups.Memory = c.Resources.Memory
  129. container.Cgroups.MemoryReservation = c.Resources.MemoryReservation
  130. container.Cgroups.MemorySwap = c.Resources.MemorySwap
  131. container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
  132. container.Cgroups.CpusetMems = c.Resources.CpusetMems
  133. container.Cgroups.CpuPeriod = c.Resources.CPUPeriod
  134. container.Cgroups.CpuQuota = c.Resources.CPUQuota
  135. container.Cgroups.BlkioWeight = c.Resources.BlkioWeight
  136. container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
  137. container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness
  138. }
  139. return nil
  140. }
  141. // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
  142. func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) {
  143. out := &libcontainer.NetworkInterface{Name: interfaceName}
  144. // This can happen if the network runtime information is missing - possible if the
  145. // container was created by an old version of libcontainer.
  146. if interfaceName == "" {
  147. return out, nil
  148. }
  149. type netStatsPair struct {
  150. // Where to write the output.
  151. Out *uint64
  152. // The network stats file to read.
  153. File string
  154. }
  155. // 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.
  156. netStats := []netStatsPair{
  157. {Out: &out.RxBytes, File: "tx_bytes"},
  158. {Out: &out.RxPackets, File: "tx_packets"},
  159. {Out: &out.RxErrors, File: "tx_errors"},
  160. {Out: &out.RxDropped, File: "tx_dropped"},
  161. {Out: &out.TxBytes, File: "rx_bytes"},
  162. {Out: &out.TxPackets, File: "rx_packets"},
  163. {Out: &out.TxErrors, File: "rx_errors"},
  164. {Out: &out.TxDropped, File: "rx_dropped"},
  165. }
  166. for _, netStat := range netStats {
  167. data, err := readSysfsNetworkStats(interfaceName, netStat.File)
  168. if err != nil {
  169. return nil, err
  170. }
  171. *(netStat.Out) = data
  172. }
  173. return out, nil
  174. }
  175. // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
  176. func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
  177. data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
  178. if err != nil {
  179. return 0, err
  180. }
  181. return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
  182. }
  183. // Stats collects all the resource usage information from a container.
  184. func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) {
  185. f, err := os.Open(filepath.Join(containerDir, "state.json"))
  186. if err != nil {
  187. return nil, err
  188. }
  189. defer f.Close()
  190. type network struct {
  191. Type string
  192. HostInterfaceName string
  193. }
  194. state := struct {
  195. CgroupPaths map[string]string `json:"cgroup_paths"`
  196. Networks []network
  197. }{}
  198. if err := json.NewDecoder(f).Decode(&state); err != nil {
  199. return nil, err
  200. }
  201. now := time.Now()
  202. mgr := fs.Manager{Paths: state.CgroupPaths}
  203. cstats, err := mgr.GetStats()
  204. if err != nil {
  205. return nil, err
  206. }
  207. stats := &libcontainer.Stats{CgroupStats: cstats}
  208. // if the container does not have any memory limit specified set the
  209. // limit to the machines memory
  210. memoryLimit := containerMemoryLimit
  211. if memoryLimit == 0 {
  212. memoryLimit = machineMemory
  213. }
  214. for _, iface := range state.Networks {
  215. switch iface.Type {
  216. case "veth":
  217. istats, err := getNetworkInterfaceStats(iface.HostInterfaceName)
  218. if err != nil {
  219. return nil, err
  220. }
  221. stats.Interfaces = append(stats.Interfaces, istats)
  222. }
  223. }
  224. return &ResourceStats{
  225. Stats: stats,
  226. Read: now,
  227. MemoryLimit: memoryLimit,
  228. }, nil
  229. }
  230. // User contains the uid and gid representing a Unix user
  231. type User struct {
  232. UID int `json:"root_uid"`
  233. GID int `json:"root_gid"`
  234. }