github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/daemon/daemon_unix.go (about) 1 // +build linux freebsd 2 3 package daemon 4 5 import ( 6 "fmt" 7 "net" 8 "os" 9 "path/filepath" 10 "runtime" 11 "strconv" 12 "strings" 13 "syscall" 14 15 "github.com/Sirupsen/logrus" 16 "github.com/docker/docker/container" 17 derr "github.com/docker/docker/errors" 18 "github.com/docker/docker/image" 19 "github.com/docker/docker/layer" 20 "github.com/docker/docker/pkg/idtools" 21 "github.com/docker/docker/pkg/parsers/kernel" 22 "github.com/docker/docker/pkg/sysinfo" 23 "github.com/docker/docker/reference" 24 "github.com/docker/docker/runconfig" 25 runconfigopts "github.com/docker/docker/runconfig/opts" 26 pblkiodev "github.com/docker/engine-api/types/blkiodev" 27 containertypes "github.com/docker/engine-api/types/container" 28 "github.com/docker/libnetwork" 29 nwconfig "github.com/docker/libnetwork/config" 30 "github.com/docker/libnetwork/drivers/bridge" 31 "github.com/docker/libnetwork/ipamutils" 32 "github.com/docker/libnetwork/netlabel" 33 "github.com/docker/libnetwork/options" 34 "github.com/docker/libnetwork/types" 35 blkiodev "github.com/opencontainers/runc/libcontainer/configs" 36 "github.com/opencontainers/runc/libcontainer/label" 37 "github.com/opencontainers/runc/libcontainer/user" 38 ) 39 40 const ( 41 // See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269 42 linuxMinCPUShares = 2 43 linuxMaxCPUShares = 262144 44 platformSupported = true 45 // It's not kernel limit, we want this 4M limit to supply a reasonable functional container 46 linuxMinMemory = 4194304 47 // constants for remapped root settings 48 defaultIDSpecifier string = "default" 49 defaultRemappedID string = "dockremap" 50 ) 51 52 func getBlkioWeightDevices(config *containertypes.HostConfig) ([]*blkiodev.WeightDevice, error) { 53 var stat syscall.Stat_t 54 var blkioWeightDevices []*blkiodev.WeightDevice 55 56 for _, weightDevice := range config.BlkioWeightDevice { 57 if err := syscall.Stat(weightDevice.Path, &stat); err != nil { 58 return nil, err 59 } 60 weightDevice := blkiodev.NewWeightDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), weightDevice.Weight, 0) 61 blkioWeightDevices = append(blkioWeightDevices, weightDevice) 62 } 63 64 return blkioWeightDevices, nil 65 } 66 67 func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error { 68 var ( 69 labelOpts []string 70 err error 71 ) 72 73 for _, opt := range config.SecurityOpt { 74 con := strings.SplitN(opt, ":", 2) 75 if len(con) == 1 { 76 return fmt.Errorf("Invalid --security-opt: %q", opt) 77 } 78 switch con[0] { 79 case "label": 80 labelOpts = append(labelOpts, con[1]) 81 case "apparmor": 82 container.AppArmorProfile = con[1] 83 case "seccomp": 84 container.SeccompProfile = con[1] 85 default: 86 return fmt.Errorf("Invalid --security-opt: %q", opt) 87 } 88 } 89 90 container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts) 91 return err 92 } 93 94 func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) { 95 var blkioReadIOpsDevice []*blkiodev.ThrottleDevice 96 var stat syscall.Stat_t 97 98 for _, iopsDevice := range config.BlkioDeviceReadIOps { 99 if err := syscall.Stat(iopsDevice.Path, &stat); err != nil { 100 return nil, err 101 } 102 readIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate) 103 blkioReadIOpsDevice = append(blkioReadIOpsDevice, readIOpsDevice) 104 } 105 106 return blkioReadIOpsDevice, nil 107 } 108 109 func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) { 110 var blkioWriteIOpsDevice []*blkiodev.ThrottleDevice 111 var stat syscall.Stat_t 112 113 for _, iopsDevice := range config.BlkioDeviceWriteIOps { 114 if err := syscall.Stat(iopsDevice.Path, &stat); err != nil { 115 return nil, err 116 } 117 writeIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate) 118 blkioWriteIOpsDevice = append(blkioWriteIOpsDevice, writeIOpsDevice) 119 } 120 121 return blkioWriteIOpsDevice, nil 122 } 123 124 func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) { 125 var blkioReadBpsDevice []*blkiodev.ThrottleDevice 126 var stat syscall.Stat_t 127 128 for _, bpsDevice := range config.BlkioDeviceReadBps { 129 if err := syscall.Stat(bpsDevice.Path, &stat); err != nil { 130 return nil, err 131 } 132 readBpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), bpsDevice.Rate) 133 blkioReadBpsDevice = append(blkioReadBpsDevice, readBpsDevice) 134 } 135 136 return blkioReadBpsDevice, nil 137 } 138 139 func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) { 140 var blkioWriteBpsDevice []*blkiodev.ThrottleDevice 141 var stat syscall.Stat_t 142 143 for _, bpsDevice := range config.BlkioDeviceWriteBps { 144 if err := syscall.Stat(bpsDevice.Path, &stat); err != nil { 145 return nil, err 146 } 147 writeBpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), bpsDevice.Rate) 148 blkioWriteBpsDevice = append(blkioWriteBpsDevice, writeBpsDevice) 149 } 150 151 return blkioWriteBpsDevice, nil 152 } 153 154 func checkKernelVersion(k, major, minor int) bool { 155 if v, err := kernel.GetKernelVersion(); err != nil { 156 logrus.Warnf("%s", err) 157 } else { 158 if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 { 159 return false 160 } 161 } 162 return true 163 } 164 165 func checkKernel() error { 166 // Check for unsupported kernel versions 167 // FIXME: it would be cleaner to not test for specific versions, but rather 168 // test for specific functionalities. 169 // Unfortunately we can't test for the feature "does not cause a kernel panic" 170 // without actually causing a kernel panic, so we need this workaround until 171 // the circumstances of pre-3.10 crashes are clearer. 172 // For details see https://github.com/docker/docker/issues/407 173 if !checkKernelVersion(3, 10, 0) { 174 v, _ := kernel.GetKernelVersion() 175 if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" { 176 logrus.Warnf("Your Linux kernel version %s can be unstable running docker. Please upgrade your kernel to 3.10.0.", v.String()) 177 } 178 } 179 return nil 180 } 181 182 // adaptContainerSettings is called during container creation to modify any 183 // settings necessary in the HostConfig structure. 184 func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error { 185 if adjustCPUShares && hostConfig.CPUShares > 0 { 186 // Handle unsupported CPUShares 187 if hostConfig.CPUShares < linuxMinCPUShares { 188 logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares) 189 hostConfig.CPUShares = linuxMinCPUShares 190 } else if hostConfig.CPUShares > linuxMaxCPUShares { 191 logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares) 192 hostConfig.CPUShares = linuxMaxCPUShares 193 } 194 } 195 if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 { 196 // By default, MemorySwap is set to twice the size of Memory. 197 hostConfig.MemorySwap = hostConfig.Memory * 2 198 } 199 if hostConfig.ShmSize == 0 { 200 hostConfig.ShmSize = container.DefaultSHMSize 201 } 202 var err error 203 if hostConfig.SecurityOpt == nil { 204 hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode) 205 if err != nil { 206 return err 207 } 208 } 209 if hostConfig.MemorySwappiness == nil { 210 defaultSwappiness := int64(-1) 211 hostConfig.MemorySwappiness = &defaultSwappiness 212 } 213 if hostConfig.OomKillDisable == nil { 214 defaultOomKillDisable := false 215 hostConfig.OomKillDisable = &defaultOomKillDisable 216 } 217 218 return nil 219 } 220 221 func verifyContainerResources(resources *containertypes.Resources) ([]string, error) { 222 warnings := []string{} 223 sysInfo := sysinfo.New(true) 224 225 // memory subsystem checks and adjustments 226 if resources.Memory != 0 && resources.Memory < linuxMinMemory { 227 return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB") 228 } 229 if resources.Memory > 0 && !sysInfo.MemoryLimit { 230 warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.") 231 logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.") 232 resources.Memory = 0 233 resources.MemorySwap = -1 234 } 235 if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit { 236 warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.") 237 logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.") 238 resources.MemorySwap = -1 239 } 240 if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory { 241 return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.") 242 } 243 if resources.Memory == 0 && resources.MemorySwap > 0 { 244 return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.") 245 } 246 if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness { 247 warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.") 248 logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.") 249 resources.MemorySwappiness = nil 250 } 251 if resources.MemorySwappiness != nil { 252 swappiness := *resources.MemorySwappiness 253 if swappiness < -1 || swappiness > 100 { 254 return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100.", swappiness) 255 } 256 } 257 if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation { 258 warnings = append(warnings, "Your kernel does not support memory soft limit capabilities. Limitation discarded.") 259 logrus.Warnf("Your kernel does not support memory soft limit capabilities. Limitation discarded.") 260 resources.MemoryReservation = 0 261 } 262 if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation { 263 return warnings, fmt.Errorf("Minimum memory limit should be larger than memory reservation limit, see usage.") 264 } 265 if resources.KernelMemory > 0 && !sysInfo.KernelMemory { 266 warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.") 267 logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.") 268 resources.KernelMemory = 0 269 } 270 if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory { 271 return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB") 272 } 273 if resources.KernelMemory > 0 && !checkKernelVersion(4, 0, 0) { 274 warnings = append(warnings, "You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.") 275 logrus.Warnf("You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.") 276 } 277 if resources.OomKillDisable != nil && !sysInfo.OomKillDisable { 278 // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point 279 // warning the caller if they already wanted the feature to be off 280 if *resources.OomKillDisable { 281 warnings = append(warnings, "Your kernel does not support OomKillDisable, OomKillDisable discarded.") 282 logrus.Warnf("Your kernel does not support OomKillDisable, OomKillDisable discarded.") 283 } 284 resources.OomKillDisable = nil 285 } 286 287 // cpu subsystem checks and adjustments 288 if resources.CPUShares > 0 && !sysInfo.CPUShares { 289 warnings = append(warnings, "Your kernel does not support CPU shares. Shares discarded.") 290 logrus.Warnf("Your kernel does not support CPU shares. Shares discarded.") 291 resources.CPUShares = 0 292 } 293 if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod { 294 warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.") 295 logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.") 296 resources.CPUPeriod = 0 297 } 298 if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota { 299 warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.") 300 logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.") 301 resources.CPUQuota = 0 302 } 303 304 // cpuset subsystem checks and adjustments 305 if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset { 306 warnings = append(warnings, "Your kernel does not support cpuset. Cpuset discarded.") 307 logrus.Warnf("Your kernel does not support cpuset. Cpuset discarded.") 308 resources.CpusetCpus = "" 309 resources.CpusetMems = "" 310 } 311 cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus) 312 if err != nil { 313 return warnings, derr.ErrorCodeInvalidCpusetCpus.WithArgs(resources.CpusetCpus) 314 } 315 if !cpusAvailable { 316 return warnings, derr.ErrorCodeNotAvailableCpusetCpus.WithArgs(resources.CpusetCpus, sysInfo.Cpus) 317 } 318 memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems) 319 if err != nil { 320 return warnings, derr.ErrorCodeInvalidCpusetMems.WithArgs(resources.CpusetMems) 321 } 322 if !memsAvailable { 323 return warnings, derr.ErrorCodeNotAvailableCpusetMems.WithArgs(resources.CpusetMems, sysInfo.Mems) 324 } 325 326 // blkio subsystem checks and adjustments 327 if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight { 328 warnings = append(warnings, "Your kernel does not support Block I/O weight. Weight discarded.") 329 logrus.Warnf("Your kernel does not support Block I/O weight. Weight discarded.") 330 resources.BlkioWeight = 0 331 } 332 if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) { 333 return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000.") 334 } 335 if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice { 336 warnings = append(warnings, "Your kernel does not support Block I/O weight_device.") 337 logrus.Warnf("Your kernel does not support Block I/O weight_device. Weight-device discarded.") 338 resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{} 339 } 340 if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice { 341 warnings = append(warnings, "Your kernel does not support Block read limit in bytes per second.") 342 logrus.Warnf("Your kernel does not support Block I/O read limit in bytes per second. --device-read-bps discarded.") 343 resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{} 344 } 345 if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice { 346 warnings = append(warnings, "Your kernel does not support Block write limit in bytes per second.") 347 logrus.Warnf("Your kernel does not support Block I/O write limit in bytes per second. --device-write-bps discarded.") 348 resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{} 349 } 350 if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice { 351 warnings = append(warnings, "Your kernel does not support Block read limit in IO per second.") 352 logrus.Warnf("Your kernel does not support Block I/O read limit in IO per second. -device-read-iops discarded.") 353 resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{} 354 } 355 if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice { 356 warnings = append(warnings, "Your kernel does not support Block write limit in IO per second.") 357 logrus.Warnf("Your kernel does not support Block I/O write limit in IO per second. --device-write-iops discarded.") 358 resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{} 359 } 360 361 return warnings, nil 362 } 363 364 // verifyPlatformContainerSettings performs platform-specific validation of the 365 // hostconfig and config structures. 366 func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config) ([]string, error) { 367 warnings := []string{} 368 sysInfo := sysinfo.New(true) 369 370 warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config) 371 if err != nil { 372 return warnings, err 373 } 374 375 w, err := verifyContainerResources(&hostConfig.Resources) 376 if err != nil { 377 return warnings, err 378 } 379 warnings = append(warnings, w...) 380 381 if hostConfig.ShmSize < 0 { 382 return warnings, fmt.Errorf("SHM size must be greater then 0") 383 } 384 385 if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 { 386 return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj) 387 } 388 if sysInfo.IPv4ForwardingDisabled { 389 warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.") 390 logrus.Warnf("IPv4 forwarding is disabled. Networking will not work") 391 } 392 // check for various conflicting options with user namespaces 393 if daemon.configStore.RemappedRoot != "" { 394 if hostConfig.Privileged { 395 return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces.") 396 } 397 if hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsContainer() { 398 return warnings, fmt.Errorf("Cannot share the host or a container's network namespace when user namespaces are enabled.") 399 } 400 if hostConfig.PidMode.IsHost() { 401 return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled.") 402 } 403 if hostConfig.IpcMode.IsContainer() { 404 return warnings, fmt.Errorf("Cannot share a container's IPC namespace when user namespaces are enabled.") 405 } 406 if hostConfig.ReadonlyRootfs { 407 return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled.") 408 } 409 } 410 return warnings, nil 411 } 412 413 // checkConfigOptions checks for mutually incompatible config options 414 func checkConfigOptions(config *Config) error { 415 // Check for mutually incompatible config options 416 if config.Bridge.Iface != "" && config.Bridge.IP != "" { 417 return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.") 418 } 419 if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication { 420 return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true.") 421 } 422 if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq { 423 config.Bridge.EnableIPMasq = false 424 } 425 return nil 426 } 427 428 // checkSystem validates platform-specific requirements 429 func checkSystem() error { 430 if os.Geteuid() != 0 { 431 return fmt.Errorf("The Docker daemon needs to be run as root") 432 } 433 return checkKernel() 434 } 435 436 // configureKernelSecuritySupport configures and validate security support for the kernel 437 func configureKernelSecuritySupport(config *Config, driverName string) error { 438 if config.EnableSelinuxSupport { 439 if selinuxEnabled() { 440 // As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled 441 if driverName == "overlay" { 442 return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName) 443 } 444 logrus.Debug("SELinux enabled successfully") 445 } else { 446 logrus.Warn("Docker could not enable SELinux on the host system") 447 } 448 } else { 449 selinuxSetDisabled() 450 } 451 return nil 452 } 453 454 func isBridgeNetworkDisabled(config *Config) bool { 455 return config.Bridge.Iface == disableNetworkBridge 456 } 457 458 func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) { 459 options := []nwconfig.Option{} 460 if dconfig == nil { 461 return options, nil 462 } 463 464 options = append(options, nwconfig.OptionDataDir(dconfig.Root)) 465 466 dd := runconfig.DefaultDaemonNetworkMode() 467 dn := runconfig.DefaultDaemonNetworkMode().NetworkName() 468 options = append(options, nwconfig.OptionDefaultDriver(string(dd))) 469 options = append(options, nwconfig.OptionDefaultNetwork(dn)) 470 471 if strings.TrimSpace(dconfig.ClusterStore) != "" { 472 kv := strings.Split(dconfig.ClusterStore, "://") 473 if len(kv) != 2 { 474 return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL") 475 } 476 options = append(options, nwconfig.OptionKVProvider(kv[0])) 477 options = append(options, nwconfig.OptionKVProviderURL(kv[1])) 478 } 479 if len(dconfig.ClusterOpts) > 0 { 480 options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts)) 481 } 482 483 if daemon.discoveryWatcher != nil { 484 options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher)) 485 } 486 487 if dconfig.ClusterAdvertise != "" { 488 options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise)) 489 } 490 491 options = append(options, nwconfig.OptionLabels(dconfig.Labels)) 492 options = append(options, driverOptions(dconfig)...) 493 return options, nil 494 } 495 496 func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) { 497 netOptions, err := daemon.networkOptions(config) 498 if err != nil { 499 return nil, err 500 } 501 502 controller, err := libnetwork.New(netOptions...) 503 if err != nil { 504 return nil, fmt.Errorf("error obtaining controller instance: %v", err) 505 } 506 507 // Initialize default network on "null" 508 if _, err := controller.NewNetwork("null", "none", libnetwork.NetworkOptionPersist(false)); err != nil { 509 return nil, fmt.Errorf("Error creating default \"null\" network: %v", err) 510 } 511 512 // Initialize default network on "host" 513 if _, err := controller.NewNetwork("host", "host", libnetwork.NetworkOptionPersist(false)); err != nil { 514 return nil, fmt.Errorf("Error creating default \"host\" network: %v", err) 515 } 516 517 if !config.DisableBridge { 518 // Initialize default driver "bridge" 519 if err := initBridgeDriver(controller, config); err != nil { 520 return nil, err 521 } 522 } 523 524 return controller, nil 525 } 526 527 func driverOptions(config *Config) []nwconfig.Option { 528 bridgeConfig := options.Generic{ 529 "EnableIPForwarding": config.Bridge.EnableIPForward, 530 "EnableIPTables": config.Bridge.EnableIPTables, 531 "EnableUserlandProxy": config.Bridge.EnableUserlandProxy} 532 bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig} 533 534 dOptions := []nwconfig.Option{} 535 dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption)) 536 return dOptions 537 } 538 539 func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { 540 if n, err := controller.NetworkByName("bridge"); err == nil { 541 if err = n.Delete(); err != nil { 542 return fmt.Errorf("could not delete the default bridge network: %v", err) 543 } 544 } 545 546 bridgeName := bridge.DefaultBridgeName 547 if config.Bridge.Iface != "" { 548 bridgeName = config.Bridge.Iface 549 } 550 netOption := map[string]string{ 551 bridge.BridgeName: bridgeName, 552 bridge.DefaultBridge: strconv.FormatBool(true), 553 netlabel.DriverMTU: strconv.Itoa(config.Mtu), 554 bridge.EnableIPMasquerade: strconv.FormatBool(config.Bridge.EnableIPMasq), 555 bridge.EnableICC: strconv.FormatBool(config.Bridge.InterContainerCommunication), 556 } 557 558 // --ip processing 559 if config.Bridge.DefaultIP != nil { 560 netOption[bridge.DefaultBindingIP] = config.Bridge.DefaultIP.String() 561 } 562 563 var ( 564 ipamV4Conf *libnetwork.IpamConf 565 ipamV6Conf *libnetwork.IpamConf 566 ) 567 568 ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 569 570 nw, nw6List, err := ipamutils.ElectInterfaceAddresses(bridgeName) 571 if err == nil { 572 ipamV4Conf.PreferredPool = types.GetIPNetCanonical(nw).String() 573 hip, _ := types.GetHostPartIP(nw.IP, nw.Mask) 574 if hip.IsGlobalUnicast() { 575 ipamV4Conf.Gateway = nw.IP.String() 576 } 577 } 578 579 if config.Bridge.IP != "" { 580 ipamV4Conf.PreferredPool = config.Bridge.IP 581 ip, _, err := net.ParseCIDR(config.Bridge.IP) 582 if err != nil { 583 return err 584 } 585 ipamV4Conf.Gateway = ip.String() 586 } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { 587 logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) 588 } 589 590 if config.Bridge.FixedCIDR != "" { 591 _, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR) 592 if err != nil { 593 return err 594 } 595 596 ipamV4Conf.SubPool = fCIDR.String() 597 } 598 599 if config.Bridge.DefaultGatewayIPv4 != nil { 600 ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String() 601 } 602 603 var deferIPv6Alloc bool 604 if config.Bridge.FixedCIDRv6 != "" { 605 _, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6) 606 if err != nil { 607 return err 608 } 609 610 // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has 611 // at least 48 host bits, we need to guarantee the current behavior where the containers' 612 // IPv6 addresses will be constructed based on the containers' interface MAC address. 613 // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints 614 // on this network until after the driver has created the endpoint and returned the 615 // constructed address. Libnetwork will then reserve this address with the ipam driver. 616 ones, _ := fCIDRv6.Mask.Size() 617 deferIPv6Alloc = ones <= 80 618 619 if ipamV6Conf == nil { 620 ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 621 } 622 ipamV6Conf.PreferredPool = fCIDRv6.String() 623 624 // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6 625 // address belongs to the same network, we need to inform libnetwork about it, so 626 // that it can be reserved with IPAM and it will not be given away to somebody else 627 for _, nw6 := range nw6List { 628 if fCIDRv6.Contains(nw6.IP) { 629 ipamV6Conf.Gateway = nw6.IP.String() 630 break 631 } 632 } 633 } 634 635 if config.Bridge.DefaultGatewayIPv6 != nil { 636 if ipamV6Conf == nil { 637 ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} 638 } 639 ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6.String() 640 } 641 642 v4Conf := []*libnetwork.IpamConf{ipamV4Conf} 643 v6Conf := []*libnetwork.IpamConf{} 644 if ipamV6Conf != nil { 645 v6Conf = append(v6Conf, ipamV6Conf) 646 } 647 // Initialize default network on "bridge" with the same name 648 _, err = controller.NewNetwork("bridge", "bridge", 649 libnetwork.NetworkOptionGeneric(options.Generic{ 650 netlabel.GenericData: netOption, 651 netlabel.EnableIPv6: config.Bridge.EnableIPv6, 652 }), 653 libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), 654 libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) 655 if err != nil { 656 return fmt.Errorf("Error creating default \"bridge\" network: %v", err) 657 } 658 return nil 659 } 660 661 // setupInitLayer populates a directory with mountpoints suitable 662 // for bind-mounting dockerinit into the container. The mountpoint is simply an 663 // empty file at /.dockerinit 664 // 665 // This extra layer is used by all containers as the top-most ro layer. It protects 666 // the container from unwanted side-effects on the rw layer. 667 func setupInitLayer(initLayer string, rootUID, rootGID int) error { 668 for pth, typ := range map[string]string{ 669 "/dev/pts": "dir", 670 "/dev/shm": "dir", 671 "/proc": "dir", 672 "/sys": "dir", 673 "/.dockerinit": "file", 674 "/.dockerenv": "file", 675 "/etc/resolv.conf": "file", 676 "/etc/hosts": "file", 677 "/etc/hostname": "file", 678 "/dev/console": "file", 679 "/etc/mtab": "/proc/mounts", 680 } { 681 parts := strings.Split(pth, "/") 682 prev := "/" 683 for _, p := range parts[1:] { 684 prev = filepath.Join(prev, p) 685 syscall.Unlink(filepath.Join(initLayer, prev)) 686 } 687 688 if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil { 689 if os.IsNotExist(err) { 690 if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil { 691 return err 692 } 693 switch typ { 694 case "dir": 695 if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil { 696 return err 697 } 698 case "file": 699 f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755) 700 if err != nil { 701 return err 702 } 703 f.Chown(rootUID, rootGID) 704 f.Close() 705 default: 706 if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil { 707 return err 708 } 709 } 710 } else { 711 return err 712 } 713 } 714 } 715 716 // Layer is ready to use, if it wasn't before. 717 return nil 718 } 719 720 // Parse the remapped root (user namespace) option, which can be one of: 721 // username - valid username from /etc/passwd 722 // username:groupname - valid username; valid groupname from /etc/group 723 // uid - 32-bit unsigned int valid Linux UID value 724 // uid:gid - uid value; 32-bit unsigned int Linux GID value 725 // 726 // If no groupname is specified, and a username is specified, an attempt 727 // will be made to lookup a gid for that username as a groupname 728 // 729 // If names are used, they are verified to exist in passwd/group 730 func parseRemappedRoot(usergrp string) (string, string, error) { 731 732 var ( 733 userID, groupID int 734 username, groupname string 735 ) 736 737 idparts := strings.Split(usergrp, ":") 738 if len(idparts) > 2 { 739 return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp) 740 } 741 742 if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil { 743 // must be a uid; take it as valid 744 userID = int(uid) 745 luser, err := user.LookupUid(userID) 746 if err != nil { 747 return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err) 748 } 749 username = luser.Name 750 if len(idparts) == 1 { 751 // if the uid was numeric and no gid was specified, take the uid as the gid 752 groupID = userID 753 lgrp, err := user.LookupGid(groupID) 754 if err != nil { 755 return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err) 756 } 757 groupname = lgrp.Name 758 } 759 } else { 760 lookupName := idparts[0] 761 // special case: if the user specified "default", they want Docker to create or 762 // use (after creation) the "dockremap" user/group for root remapping 763 if lookupName == defaultIDSpecifier { 764 lookupName = defaultRemappedID 765 } 766 luser, err := user.LookupUser(lookupName) 767 if err != nil && idparts[0] != defaultIDSpecifier { 768 // error if the name requested isn't the special "dockremap" ID 769 return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err) 770 } else if err != nil { 771 // special case-- if the username == "default", then we have been asked 772 // to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid} 773 // ranges will be used for the user and group mappings in user namespaced containers 774 _, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID) 775 if err == nil { 776 return defaultRemappedID, defaultRemappedID, nil 777 } 778 return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err) 779 } 780 userID = luser.Uid 781 username = luser.Name 782 if len(idparts) == 1 { 783 // we only have a string username, and no group specified; look up gid from username as group 784 group, err := user.LookupGroup(lookupName) 785 if err != nil { 786 return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err) 787 } 788 groupID = group.Gid 789 groupname = group.Name 790 } 791 } 792 793 if len(idparts) == 2 { 794 // groupname or gid is separately specified and must be resolved 795 // to a unsigned 32-bit gid 796 if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil { 797 // must be a gid, take it as valid 798 groupID = int(gid) 799 lgrp, err := user.LookupGid(groupID) 800 if err != nil { 801 return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err) 802 } 803 groupname = lgrp.Name 804 } else { 805 // not a number; attempt a lookup 806 group, err := user.LookupGroup(idparts[1]) 807 if err != nil { 808 return "", "", fmt.Errorf("Error during gid lookup for %q: %v", idparts[1], err) 809 } 810 groupID = group.Gid 811 groupname = idparts[1] 812 } 813 } 814 return username, groupname, nil 815 } 816 817 func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) { 818 if runtime.GOOS != "linux" && config.RemappedRoot != "" { 819 return nil, nil, fmt.Errorf("User namespaces are only supported on Linux") 820 } 821 822 // if the daemon was started with remapped root option, parse 823 // the config option to the int uid,gid values 824 var ( 825 uidMaps, gidMaps []idtools.IDMap 826 ) 827 if config.RemappedRoot != "" { 828 username, groupname, err := parseRemappedRoot(config.RemappedRoot) 829 if err != nil { 830 return nil, nil, err 831 } 832 if username == "root" { 833 // Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op 834 // effectively 835 logrus.Warnf("User namespaces: root cannot be remapped with itself; user namespaces are OFF") 836 return uidMaps, gidMaps, nil 837 } 838 logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname) 839 // update remapped root setting now that we have resolved them to actual names 840 config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname) 841 842 uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname) 843 if err != nil { 844 return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err) 845 } 846 } 847 return uidMaps, gidMaps, nil 848 } 849 850 func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error { 851 config.Root = rootDir 852 // the docker root metadata directory needs to have execute permissions for all users (o+x) 853 // so that syscalls executing as non-root, operating on subdirectories of the graph root 854 // (e.g. mounted layers of a container) can traverse this path. 855 // The user namespace support will create subdirectories for the remapped root host uid:gid 856 // pair owned by that same uid:gid pair for proper write access to those needed metadata and 857 // layer content subtrees. 858 if _, err := os.Stat(rootDir); err == nil { 859 // root current exists; verify the access bits are correct by setting them 860 if err = os.Chmod(rootDir, 0701); err != nil { 861 return err 862 } 863 } else if os.IsNotExist(err) { 864 // no root exists yet, create it 0701 with root:root ownership 865 if err := os.MkdirAll(rootDir, 0701); err != nil { 866 return err 867 } 868 } 869 870 // if user namespaces are enabled we will create a subtree underneath the specified root 871 // with any/all specified remapped root uid/gid options on the daemon creating 872 // a new subdirectory with ownership set to the remapped uid/gid (so as to allow 873 // `chdir()` to work for containers namespaced to that uid/gid) 874 if config.RemappedRoot != "" { 875 config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID)) 876 logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) 877 // Create the root directory if it doesn't exists 878 if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil { 879 return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) 880 } 881 } 882 return nil 883 } 884 885 // registerLinks writes the links to a file. 886 func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error { 887 if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() { 888 return nil 889 } 890 891 for _, l := range hostConfig.Links { 892 name, alias, err := runconfigopts.ParseLink(l) 893 if err != nil { 894 return err 895 } 896 child, err := daemon.GetContainer(name) 897 if err != nil { 898 //An error from daemon.GetContainer() means this name could not be found 899 return fmt.Errorf("Could not get container for %s", name) 900 } 901 for child.HostConfig.NetworkMode.IsContainer() { 902 parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2) 903 child, err = daemon.GetContainer(parts[1]) 904 if err != nil { 905 return fmt.Errorf("Could not get container for %s", parts[1]) 906 } 907 } 908 if child.HostConfig.NetworkMode.IsHost() { 909 return runconfig.ErrConflictHostNetworkAndLinks 910 } 911 if err := daemon.registerLink(container, child, alias); err != nil { 912 return err 913 } 914 } 915 916 // After we load all the links into the daemon 917 // set them to nil on the hostconfig 918 return container.WriteHostConfig() 919 } 920 921 // conditionalMountOnStart is a platform specific helper function during the 922 // container start to call mount. 923 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error { 924 return daemon.Mount(container) 925 } 926 927 // conditionalUnmountOnCleanup is a platform specific helper function called 928 // during the cleanup of a container to unmount. 929 func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) { 930 daemon.Unmount(container) 931 } 932 933 func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error { 934 // Unix has no custom images to register 935 return nil 936 }