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