github.com/wulonghui/docker@v1.8.0-rc2/daemon/daemon_unix.go (about)

     1  // +build !windows
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"syscall"
    13  
    14  	"github.com/Sirupsen/logrus"
    15  	"github.com/docker/docker/autogen/dockerversion"
    16  	"github.com/docker/docker/daemon/graphdriver"
    17  	"github.com/docker/docker/pkg/archive"
    18  	"github.com/docker/docker/pkg/fileutils"
    19  	"github.com/docker/docker/pkg/nat"
    20  	"github.com/docker/docker/pkg/parsers"
    21  	"github.com/docker/docker/pkg/parsers/kernel"
    22  	"github.com/docker/docker/pkg/system"
    23  	"github.com/docker/docker/runconfig"
    24  	"github.com/docker/docker/utils"
    25  	volumedrivers "github.com/docker/docker/volume/drivers"
    26  	"github.com/docker/docker/volume/local"
    27  	"github.com/docker/libnetwork"
    28  	nwapi "github.com/docker/libnetwork/api"
    29  	nwconfig "github.com/docker/libnetwork/config"
    30  	"github.com/docker/libnetwork/netlabel"
    31  	"github.com/docker/libnetwork/options"
    32  	"github.com/opencontainers/runc/libcontainer/label"
    33  )
    34  
    35  func (daemon *Daemon) Changes(container *Container) ([]archive.Change, error) {
    36  	initID := fmt.Sprintf("%s-init", container.ID)
    37  	return daemon.driver.Changes(container.ID, initID)
    38  }
    39  
    40  func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) {
    41  	initID := fmt.Sprintf("%s-init", container.ID)
    42  	return daemon.driver.Diff(container.ID, initID)
    43  }
    44  
    45  func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error {
    46  	var (
    47  		labelOpts []string
    48  		err       error
    49  	)
    50  
    51  	for _, opt := range config.SecurityOpt {
    52  		con := strings.SplitN(opt, ":", 2)
    53  		if len(con) == 1 {
    54  			return fmt.Errorf("Invalid --security-opt: %q", opt)
    55  		}
    56  		switch con[0] {
    57  		case "label":
    58  			labelOpts = append(labelOpts, con[1])
    59  		case "apparmor":
    60  			container.AppArmorProfile = con[1]
    61  		default:
    62  			return fmt.Errorf("Invalid --security-opt: %q", opt)
    63  		}
    64  	}
    65  
    66  	container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
    67  	return err
    68  }
    69  
    70  func (daemon *Daemon) createRootfs(container *Container) error {
    71  	// Step 1: create the container directory.
    72  	// This doubles as a barrier to avoid race conditions.
    73  	if err := os.Mkdir(container.root, 0700); err != nil {
    74  		return err
    75  	}
    76  	initID := fmt.Sprintf("%s-init", container.ID)
    77  	if err := daemon.driver.Create(initID, container.ImageID); err != nil {
    78  		return err
    79  	}
    80  	initPath, err := daemon.driver.Get(initID, "")
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	if err := setupInitLayer(initPath); err != nil {
    86  		daemon.driver.Put(initID)
    87  		return err
    88  	}
    89  
    90  	// We want to unmount init layer before we take snapshot of it
    91  	// for the actual container.
    92  	daemon.driver.Put(initID)
    93  
    94  	if err := daemon.driver.Create(container.ID, initID); err != nil {
    95  		return err
    96  	}
    97  	return nil
    98  }
    99  
   100  func checkKernel() error {
   101  	// Check for unsupported kernel versions
   102  	// FIXME: it would be cleaner to not test for specific versions, but rather
   103  	// test for specific functionalities.
   104  	// Unfortunately we can't test for the feature "does not cause a kernel panic"
   105  	// without actually causing a kernel panic, so we need this workaround until
   106  	// the circumstances of pre-3.10 crashes are clearer.
   107  	// For details see https://github.com/docker/docker/issues/407
   108  	if k, err := kernel.GetKernelVersion(); err != nil {
   109  		logrus.Warnf("%s", err)
   110  	} else {
   111  		if kernel.CompareKernelVersion(k, &kernel.KernelVersionInfo{Kernel: 3, Major: 10, Minor: 0}) < 0 {
   112  			if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
   113  				logrus.Warnf("You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.10.0.", k.String())
   114  			}
   115  		}
   116  	}
   117  	return nil
   118  }
   119  
   120  func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
   121  	var warnings []string
   122  
   123  	if config != nil {
   124  		// The check for a valid workdir path is made on the server rather than in the
   125  		// client. This is because we don't know the type of path (Linux or Windows)
   126  		// to validate on the client.
   127  		if config.WorkingDir != "" && !filepath.IsAbs(config.WorkingDir) {
   128  			return warnings, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir)
   129  		}
   130  	}
   131  
   132  	if hostConfig == nil {
   133  		return warnings, nil
   134  	}
   135  
   136  	for port := range hostConfig.PortBindings {
   137  		_, portStr := nat.SplitProtoPort(string(port))
   138  		if _, err := nat.ParsePort(portStr); err != nil {
   139  			return warnings, fmt.Errorf("Invalid port specification: %q", portStr)
   140  		}
   141  		for _, pb := range hostConfig.PortBindings[port] {
   142  			_, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort))
   143  			if err != nil {
   144  				return warnings, fmt.Errorf("Invalid port specification: %q", pb.HostPort)
   145  			}
   146  		}
   147  	}
   148  	if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
   149  		return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
   150  	}
   151  	if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
   152  		return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
   153  	}
   154  	if hostConfig.Memory > 0 && !daemon.SystemConfig().MemoryLimit {
   155  		warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
   156  		logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.")
   157  		hostConfig.Memory = 0
   158  	}
   159  	if hostConfig.Memory > 0 && hostConfig.MemorySwap != -1 && !daemon.SystemConfig().SwapLimit {
   160  		warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.")
   161  		logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.")
   162  		hostConfig.MemorySwap = -1
   163  	}
   164  	if hostConfig.Memory > 0 && hostConfig.MemorySwap > 0 && hostConfig.MemorySwap < hostConfig.Memory {
   165  		return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.")
   166  	}
   167  	if hostConfig.Memory == 0 && hostConfig.MemorySwap > 0 {
   168  		return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.")
   169  	}
   170  	if hostConfig.MemorySwappiness != nil && !daemon.SystemConfig().MemorySwappiness {
   171  		warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
   172  		logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
   173  		hostConfig.MemorySwappiness = nil
   174  	}
   175  	if hostConfig.MemorySwappiness != nil {
   176  		swappiness := *hostConfig.MemorySwappiness
   177  		if swappiness < -1 || swappiness > 100 {
   178  			return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100.", swappiness)
   179  		}
   180  	}
   181  	if hostConfig.CpuPeriod > 0 && !daemon.SystemConfig().CpuCfsPeriod {
   182  		warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.")
   183  		logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.")
   184  		hostConfig.CpuPeriod = 0
   185  	}
   186  	if hostConfig.CpuQuota > 0 && !daemon.SystemConfig().CpuCfsQuota {
   187  		warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.")
   188  		logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.")
   189  		hostConfig.CpuQuota = 0
   190  	}
   191  	if hostConfig.BlkioWeight > 0 && (hostConfig.BlkioWeight < 10 || hostConfig.BlkioWeight > 1000) {
   192  		return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000.")
   193  	}
   194  	if hostConfig.OomKillDisable && !daemon.SystemConfig().OomKillDisable {
   195  		hostConfig.OomKillDisable = false
   196  		return warnings, fmt.Errorf("Your kernel does not support oom kill disable.")
   197  	}
   198  	if daemon.SystemConfig().IPv4ForwardingDisabled {
   199  		warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
   200  		logrus.Warnf("IPv4 forwarding is disabled. Networking will not work")
   201  	}
   202  	return warnings, nil
   203  }
   204  
   205  // checkConfigOptions checks for mutually incompatible config options
   206  func checkConfigOptions(config *Config) error {
   207  	// Check for mutually incompatible config options
   208  	if config.Bridge.Iface != "" && config.Bridge.IP != "" {
   209  		return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
   210  	}
   211  	if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
   212  		return fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
   213  	}
   214  	if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
   215  		config.Bridge.EnableIPMasq = false
   216  	}
   217  	return nil
   218  }
   219  
   220  // checkSystem validates platform-specific requirements
   221  func checkSystem() error {
   222  	if os.Geteuid() != 0 {
   223  		return fmt.Errorf("The Docker daemon needs to be run as root")
   224  	}
   225  	if err := checkKernel(); err != nil {
   226  		return err
   227  	}
   228  	return nil
   229  }
   230  
   231  // configureKernelSecuritySupport configures and validate security support for the kernel
   232  func configureKernelSecuritySupport(config *Config, driverName string) error {
   233  	if config.EnableSelinuxSupport {
   234  		if selinuxEnabled() {
   235  			// As Docker on btrfs and SELinux are incompatible at present, error on both being enabled
   236  			if driverName == "btrfs" {
   237  				return fmt.Errorf("SELinux is not supported with the BTRFS graph driver")
   238  			}
   239  			logrus.Debug("SELinux enabled successfully")
   240  		} else {
   241  			logrus.Warn("Docker could not enable SELinux on the host system")
   242  		}
   243  	} else {
   244  		selinuxSetDisabled()
   245  	}
   246  	return nil
   247  }
   248  
   249  // MigrateIfDownlevel is a wrapper for AUFS migration for downlevel
   250  func migrateIfDownlevel(driver graphdriver.Driver, root string) error {
   251  	return migrateIfAufs(driver, root)
   252  }
   253  
   254  func configureVolumes(config *Config) error {
   255  	volumesDriver, err := local.New(config.Root)
   256  	if err != nil {
   257  		return err
   258  	}
   259  	volumedrivers.Register(volumesDriver, volumesDriver.Name())
   260  	return nil
   261  }
   262  
   263  func configureSysInit(config *Config) (string, error) {
   264  	localCopy := filepath.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
   265  	sysInitPath := utils.DockerInitPath(localCopy)
   266  	if sysInitPath == "" {
   267  		return "", fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See https://docs.docker.com/contributing/devenvironment for official build instructions.")
   268  	}
   269  
   270  	if sysInitPath != localCopy {
   271  		// When we find a suitable dockerinit binary (even if it's our local binary), we copy it into config.Root at localCopy for future use (so that the original can go away without that being a problem, for example during a package upgrade).
   272  		if err := os.Mkdir(filepath.Dir(localCopy), 0700); err != nil && !os.IsExist(err) {
   273  			return "", err
   274  		}
   275  		if _, err := fileutils.CopyFile(sysInitPath, localCopy); err != nil {
   276  			return "", err
   277  		}
   278  		if err := os.Chmod(localCopy, 0700); err != nil {
   279  			return "", err
   280  		}
   281  		sysInitPath = localCopy
   282  	}
   283  	return sysInitPath, nil
   284  }
   285  
   286  func isBridgeNetworkDisabled(config *Config) bool {
   287  	return config.Bridge.Iface == disableNetworkBridge
   288  }
   289  
   290  func networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
   291  	options := []nwconfig.Option{}
   292  	if dconfig == nil {
   293  		return options, nil
   294  	}
   295  	if strings.TrimSpace(dconfig.DefaultNetwork) != "" {
   296  		dn := strings.Split(dconfig.DefaultNetwork, ":")
   297  		if len(dn) < 2 {
   298  			return nil, fmt.Errorf("default network daemon config must be of the form NETWORKDRIVER:NETWORKNAME")
   299  		}
   300  		options = append(options, nwconfig.OptionDefaultDriver(dn[0]))
   301  		options = append(options, nwconfig.OptionDefaultNetwork(strings.Join(dn[1:], ":")))
   302  	} else {
   303  		dd := runconfig.DefaultDaemonNetworkMode()
   304  		dn := runconfig.DefaultDaemonNetworkMode().NetworkName()
   305  		options = append(options, nwconfig.OptionDefaultDriver(string(dd)))
   306  		options = append(options, nwconfig.OptionDefaultNetwork(dn))
   307  	}
   308  
   309  	if strings.TrimSpace(dconfig.NetworkKVStore) != "" {
   310  		kv := strings.Split(dconfig.NetworkKVStore, ":")
   311  		if len(kv) < 2 {
   312  			return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER:KV-URL")
   313  		}
   314  		options = append(options, nwconfig.OptionKVProvider(kv[0]))
   315  		options = append(options, nwconfig.OptionKVProviderURL(strings.Join(kv[1:], ":")))
   316  	}
   317  
   318  	options = append(options, nwconfig.OptionLabels(dconfig.Labels))
   319  	return options, nil
   320  }
   321  
   322  func initNetworkController(config *Config) (libnetwork.NetworkController, error) {
   323  	netOptions, err := networkOptions(config)
   324  	if err != nil {
   325  		return nil, err
   326  	}
   327  
   328  	controller, err := libnetwork.New(netOptions...)
   329  	if err != nil {
   330  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   331  	}
   332  
   333  	// Initialize default driver "null"
   334  
   335  	if err := controller.ConfigureNetworkDriver("null", options.Generic{}); err != nil {
   336  		return nil, fmt.Errorf("Error initializing null driver: %v", err)
   337  	}
   338  
   339  	// Initialize default network on "null"
   340  	if _, err := controller.NewNetwork("null", "none"); err != nil {
   341  		return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
   342  	}
   343  
   344  	// Initialize default driver "host"
   345  	if err := controller.ConfigureNetworkDriver("host", options.Generic{}); err != nil {
   346  		return nil, fmt.Errorf("Error initializing host driver: %v", err)
   347  	}
   348  
   349  	// Initialize default network on "host"
   350  	if _, err := controller.NewNetwork("host", "host"); err != nil {
   351  		return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
   352  	}
   353  
   354  	if !config.DisableBridge {
   355  		// Initialize default driver "bridge"
   356  		if err := initBridgeDriver(controller, config); err != nil {
   357  			return nil, err
   358  		}
   359  	}
   360  
   361  	return controller, nil
   362  }
   363  
   364  func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
   365  	option := options.Generic{
   366  		"EnableIPForwarding": config.Bridge.EnableIPForward}
   367  
   368  	if err := controller.ConfigureNetworkDriver("bridge", options.Generic{netlabel.GenericData: option}); err != nil {
   369  		return fmt.Errorf("Error initializing bridge driver: %v", err)
   370  	}
   371  
   372  	netOption := options.Generic{
   373  		"BridgeName":          config.Bridge.Iface,
   374  		"Mtu":                 config.Mtu,
   375  		"EnableIPTables":      config.Bridge.EnableIPTables,
   376  		"EnableIPMasquerade":  config.Bridge.EnableIPMasq,
   377  		"EnableICC":           config.Bridge.InterContainerCommunication,
   378  		"EnableUserlandProxy": config.Bridge.EnableUserlandProxy,
   379  	}
   380  
   381  	if config.Bridge.IP != "" {
   382  		ip, bipNet, err := net.ParseCIDR(config.Bridge.IP)
   383  		if err != nil {
   384  			return err
   385  		}
   386  
   387  		bipNet.IP = ip
   388  		netOption["AddressIPv4"] = bipNet
   389  	}
   390  
   391  	if config.Bridge.FixedCIDR != "" {
   392  		_, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR)
   393  		if err != nil {
   394  			return err
   395  		}
   396  
   397  		netOption["FixedCIDR"] = fCIDR
   398  	}
   399  
   400  	if config.Bridge.FixedCIDRv6 != "" {
   401  		_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
   402  		if err != nil {
   403  			return err
   404  		}
   405  
   406  		netOption["FixedCIDRv6"] = fCIDRv6
   407  	}
   408  
   409  	if config.Bridge.DefaultGatewayIPv4 != nil {
   410  		netOption["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4
   411  	}
   412  
   413  	if config.Bridge.DefaultGatewayIPv6 != nil {
   414  		netOption["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6
   415  	}
   416  
   417  	// --ip processing
   418  	if config.Bridge.DefaultIP != nil {
   419  		netOption["DefaultBindingIP"] = config.Bridge.DefaultIP
   420  	}
   421  
   422  	// Initialize default network on "bridge" with the same name
   423  	_, err := controller.NewNetwork("bridge", "bridge",
   424  		libnetwork.NetworkOptionGeneric(options.Generic{
   425  			netlabel.GenericData: netOption,
   426  			netlabel.EnableIPv6:  config.Bridge.EnableIPv6,
   427  		}))
   428  	if err != nil {
   429  		return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
   430  	}
   431  	return nil
   432  }
   433  
   434  // setupInitLayer populates a directory with mountpoints suitable
   435  // for bind-mounting dockerinit into the container. The mountpoint is simply an
   436  // empty file at /.dockerinit
   437  //
   438  // This extra layer is used by all containers as the top-most ro layer. It protects
   439  // the container from unwanted side-effects on the rw layer.
   440  func setupInitLayer(initLayer string) error {
   441  	for pth, typ := range map[string]string{
   442  		"/dev/pts":         "dir",
   443  		"/dev/shm":         "dir",
   444  		"/proc":            "dir",
   445  		"/sys":             "dir",
   446  		"/.dockerinit":     "file",
   447  		"/.dockerenv":      "file",
   448  		"/etc/resolv.conf": "file",
   449  		"/etc/hosts":       "file",
   450  		"/etc/hostname":    "file",
   451  		"/dev/console":     "file",
   452  		"/etc/mtab":        "/proc/mounts",
   453  	} {
   454  		parts := strings.Split(pth, "/")
   455  		prev := "/"
   456  		for _, p := range parts[1:] {
   457  			prev = filepath.Join(prev, p)
   458  			syscall.Unlink(filepath.Join(initLayer, prev))
   459  		}
   460  
   461  		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
   462  			if os.IsNotExist(err) {
   463  				if err := system.MkdirAll(filepath.Join(initLayer, filepath.Dir(pth)), 0755); err != nil {
   464  					return err
   465  				}
   466  				switch typ {
   467  				case "dir":
   468  					if err := system.MkdirAll(filepath.Join(initLayer, pth), 0755); err != nil {
   469  						return err
   470  					}
   471  				case "file":
   472  					f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
   473  					if err != nil {
   474  						return err
   475  					}
   476  					f.Close()
   477  				default:
   478  					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
   479  						return err
   480  					}
   481  				}
   482  			} else {
   483  				return err
   484  			}
   485  		}
   486  	}
   487  
   488  	// Layer is ready to use, if it wasn't before.
   489  	return nil
   490  }
   491  
   492  func (daemon *Daemon) NetworkApiRouter() func(w http.ResponseWriter, req *http.Request) {
   493  	return nwapi.NewHTTPHandler(daemon.netController)
   494  }
   495  
   496  func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error {
   497  	if hostConfig == nil || hostConfig.Links == nil {
   498  		return nil
   499  	}
   500  
   501  	for _, l := range hostConfig.Links {
   502  		name, alias, err := parsers.ParseLink(l)
   503  		if err != nil {
   504  			return err
   505  		}
   506  		child, err := daemon.Get(name)
   507  		if err != nil {
   508  			//An error from daemon.Get() means this name could not be found
   509  			return fmt.Errorf("Could not get container for %s", name)
   510  		}
   511  		for child.hostConfig.NetworkMode.IsContainer() {
   512  			parts := strings.SplitN(string(child.hostConfig.NetworkMode), ":", 2)
   513  			child, err = daemon.Get(parts[1])
   514  			if err != nil {
   515  				return fmt.Errorf("Could not get container for %s", parts[1])
   516  			}
   517  		}
   518  		if child.hostConfig.NetworkMode.IsHost() {
   519  			return runconfig.ErrConflictHostNetworkAndLinks
   520  		}
   521  		if err := daemon.RegisterLink(container, child, alias); err != nil {
   522  			return err
   523  		}
   524  	}
   525  
   526  	// After we load all the links into the daemon
   527  	// set them to nil on the hostconfig
   528  	hostConfig.Links = nil
   529  	if err := container.WriteHostConfig(); err != nil {
   530  		return err
   531  	}
   532  
   533  	return nil
   534  }