github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/daemon/execdriver/driver_unix.go (about) 1 // +build !windows 2 3 package execdriver 4 5 import ( 6 "encoding/json" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/docker/docker/daemon/execdriver/native/template" 15 "github.com/docker/docker/pkg/idtools" 16 "github.com/docker/docker/pkg/mount" 17 "github.com/docker/docker/pkg/ulimit" 18 "github.com/opencontainers/runc/libcontainer" 19 "github.com/opencontainers/runc/libcontainer/cgroups/fs" 20 "github.com/opencontainers/runc/libcontainer/configs" 21 blkiodev "github.com/opencontainers/runc/libcontainer/configs" 22 ) 23 24 // Mount contains information for a mount operation. 25 type Mount struct { 26 Source string `json:"source"` 27 Destination string `json:"destination"` 28 Writable bool `json:"writable"` 29 Data string `json:"data"` 30 Propagation string `json:"mountpropagation"` 31 } 32 33 // Resources contains all resource configs for a driver. 34 // Currently these are all for cgroup configs. 35 type Resources struct { 36 CommonResources 37 38 // Fields below here are platform specific 39 40 BlkioWeightDevice []*blkiodev.WeightDevice `json:"blkio_weight_device"` 41 BlkioThrottleReadBpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"` 42 BlkioThrottleWriteBpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"` 43 MemorySwap int64 `json:"memory_swap"` 44 KernelMemory int64 `json:"kernel_memory"` 45 CPUQuota int64 `json:"cpu_quota"` 46 CpusetCpus string `json:"cpuset_cpus"` 47 CpusetMems string `json:"cpuset_mems"` 48 CPUPeriod int64 `json:"cpu_period"` 49 Rlimits []*ulimit.Rlimit `json:"rlimits"` 50 OomKillDisable bool `json:"oom_kill_disable"` 51 MemorySwappiness int64 `json:"memory_swappiness"` 52 } 53 54 // ProcessConfig is the platform specific structure that describes a process 55 // that will be run inside a container. 56 type ProcessConfig struct { 57 CommonProcessConfig 58 59 // Fields below here are platform specific 60 Privileged bool `json:"privileged"` 61 User string `json:"user"` 62 Console string `json:"-"` // dev/console path 63 } 64 65 // Ipc settings of the container 66 // It is for IPC namespace setting. Usually different containers 67 // have their own IPC namespace, however this specifies to use 68 // an existing IPC namespace. 69 // You can join the host's or a container's IPC namespace. 70 type Ipc struct { 71 ContainerID string `json:"container_id"` // id of the container to join ipc. 72 HostIpc bool `json:"host_ipc"` 73 } 74 75 // Pid settings of the container 76 // It is for PID namespace setting. Usually different containers 77 // have their own PID namespace, however this specifies to use 78 // an existing PID namespace. 79 // Joining the host's PID namespace is currently the only supported 80 // option. 81 type Pid struct { 82 HostPid bool `json:"host_pid"` 83 } 84 85 // UTS settings of the container 86 // It is for UTS namespace setting. Usually different containers 87 // have their own UTS namespace, however this specifies to use 88 // an existing UTS namespace. 89 // Joining the host's UTS namespace is currently the only supported 90 // option. 91 type UTS struct { 92 HostUTS bool `json:"host_uts"` 93 } 94 95 // Network settings of the container 96 type Network struct { 97 Mtu int `json:"mtu"` 98 ContainerID string `json:"container_id"` // id of the container to join network. 99 NamespacePath string `json:"namespace_path"` 100 HostNetworking bool `json:"host_networking"` 101 } 102 103 // Command wraps an os/exec.Cmd to add more metadata 104 type Command struct { 105 CommonCommand 106 107 // Fields below here are platform specific 108 109 AllowedDevices []*configs.Device `json:"allowed_devices"` 110 AppArmorProfile string `json:"apparmor_profile"` 111 AutoCreatedDevices []*configs.Device `json:"autocreated_devices"` 112 CapAdd []string `json:"cap_add"` 113 CapDrop []string `json:"cap_drop"` 114 CgroupParent string `json:"cgroup_parent"` // The parent cgroup for this command. 115 GIDMapping []idtools.IDMap `json:"gidmapping"` 116 GroupAdd []string `json:"group_add"` 117 Ipc *Ipc `json:"ipc"` 118 OomScoreAdj int `json:"oom_score_adj"` 119 Pid *Pid `json:"pid"` 120 ReadonlyRootfs bool `json:"readonly_rootfs"` 121 RemappedRoot *User `json:"remap_root"` 122 SeccompProfile string `json:"seccomp_profile"` 123 UIDMapping []idtools.IDMap `json:"uidmapping"` 124 UTS *UTS `json:"uts"` 125 } 126 127 // SetRootPropagation sets the root mount propagation mode. 128 func SetRootPropagation(config *configs.Config, propagation int) { 129 config.RootPropagation = propagation 130 } 131 132 // InitContainer is the initialization of a container config. 133 // It returns the initial configs for a container. It's mostly 134 // defined by the default template. 135 func InitContainer(c *Command) *configs.Config { 136 container := template.New() 137 138 container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env) 139 container.Cgroups.Name = c.ID 140 container.Cgroups.AllowedDevices = c.AllowedDevices 141 container.Devices = c.AutoCreatedDevices 142 container.Rootfs = c.Rootfs 143 container.Readonlyfs = c.ReadonlyRootfs 144 // This can be overridden later by driver during mount setup based 145 // on volume options 146 SetRootPropagation(container, mount.RPRIVATE) 147 148 // check to see if we are running in ramdisk to disable pivot root 149 container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != "" 150 151 // Default parent cgroup is "docker". Override if required. 152 if c.CgroupParent != "" { 153 container.Cgroups.Parent = c.CgroupParent 154 } 155 return container 156 } 157 158 func getEnv(key string, env []string) string { 159 for _, pair := range env { 160 parts := strings.SplitN(pair, "=", 2) 161 if parts[0] == key { 162 return parts[1] 163 } 164 } 165 return "" 166 } 167 168 // SetupCgroups setups cgroup resources for a container. 169 func SetupCgroups(container *configs.Config, c *Command) error { 170 if c.Resources != nil { 171 container.Cgroups.CpuShares = c.Resources.CPUShares 172 container.Cgroups.Memory = c.Resources.Memory 173 container.Cgroups.MemoryReservation = c.Resources.MemoryReservation 174 container.Cgroups.MemorySwap = c.Resources.MemorySwap 175 container.Cgroups.KernelMemory = c.Resources.KernelMemory 176 container.Cgroups.CpusetCpus = c.Resources.CpusetCpus 177 container.Cgroups.CpusetMems = c.Resources.CpusetMems 178 container.Cgroups.CpuPeriod = c.Resources.CPUPeriod 179 container.Cgroups.CpuQuota = c.Resources.CPUQuota 180 container.Cgroups.BlkioWeight = c.Resources.BlkioWeight 181 container.Cgroups.BlkioWeightDevice = c.Resources.BlkioWeightDevice 182 container.Cgroups.BlkioThrottleReadBpsDevice = c.Resources.BlkioThrottleReadBpsDevice 183 container.Cgroups.BlkioThrottleWriteBpsDevice = c.Resources.BlkioThrottleWriteBpsDevice 184 container.Cgroups.OomKillDisable = c.Resources.OomKillDisable 185 container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness 186 } 187 188 return nil 189 } 190 191 // Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. 192 func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) { 193 out := &libcontainer.NetworkInterface{Name: interfaceName} 194 // This can happen if the network runtime information is missing - possible if the 195 // container was created by an old version of libcontainer. 196 if interfaceName == "" { 197 return out, nil 198 } 199 type netStatsPair struct { 200 // Where to write the output. 201 Out *uint64 202 // The network stats file to read. 203 File string 204 } 205 // 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. 206 netStats := []netStatsPair{ 207 {Out: &out.RxBytes, File: "tx_bytes"}, 208 {Out: &out.RxPackets, File: "tx_packets"}, 209 {Out: &out.RxErrors, File: "tx_errors"}, 210 {Out: &out.RxDropped, File: "tx_dropped"}, 211 212 {Out: &out.TxBytes, File: "rx_bytes"}, 213 {Out: &out.TxPackets, File: "rx_packets"}, 214 {Out: &out.TxErrors, File: "rx_errors"}, 215 {Out: &out.TxDropped, File: "rx_dropped"}, 216 } 217 for _, netStat := range netStats { 218 data, err := readSysfsNetworkStats(interfaceName, netStat.File) 219 if err != nil { 220 return nil, err 221 } 222 *(netStat.Out) = data 223 } 224 return out, nil 225 } 226 227 // Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics 228 func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { 229 data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) 230 if err != nil { 231 return 0, err 232 } 233 return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) 234 } 235 236 // Stats collects all the resource usage information from a container. 237 func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) { 238 f, err := os.Open(filepath.Join(containerDir, "state.json")) 239 if err != nil { 240 return nil, err 241 } 242 defer f.Close() 243 244 type network struct { 245 Type string 246 HostInterfaceName string 247 } 248 249 state := struct { 250 CgroupPaths map[string]string `json:"cgroup_paths"` 251 Networks []network 252 }{} 253 254 if err := json.NewDecoder(f).Decode(&state); err != nil { 255 return nil, err 256 } 257 now := time.Now() 258 259 mgr := fs.Manager{Paths: state.CgroupPaths} 260 cstats, err := mgr.GetStats() 261 if err != nil { 262 return nil, err 263 } 264 stats := &libcontainer.Stats{CgroupStats: cstats} 265 // if the container does not have any memory limit specified set the 266 // limit to the machines memory 267 memoryLimit := containerMemoryLimit 268 if memoryLimit == 0 { 269 memoryLimit = machineMemory 270 } 271 for _, iface := range state.Networks { 272 switch iface.Type { 273 case "veth": 274 istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) 275 if err != nil { 276 return nil, err 277 } 278 stats.Interfaces = append(stats.Interfaces, istats) 279 } 280 } 281 return &ResourceStats{ 282 Stats: stats, 283 Read: now, 284 MemoryLimit: memoryLimit, 285 }, nil 286 } 287 288 // User contains the uid and gid representing a Unix user 289 type User struct { 290 UID int `json:"root_uid"` 291 GID int `json:"root_gid"` 292 } 293 294 // ExitStatus provides exit reasons for a container. 295 type ExitStatus struct { 296 // The exit code with which the container exited. 297 ExitCode int 298 299 // Whether the container encountered an OOM. 300 OOMKilled bool 301 }