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