diff --git a/.travis.yml b/.travis.yml index 56f1910c93..e7d18f1c6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ sudo: false # Disable the normal go build. install: - export DOCKER_BUILDTAGS='exclude_graphdriver_btrfs exclude_graphdriver_devicemapper' # btrfs and devicemapper fail to compile thanks to a couple missing headers (which we can't install thanks to "sudo: false") + - export AUTO_GOPATH=1 before_script: - env | sort @@ -23,6 +24,7 @@ before_script: script: - hack/make.sh validate-dco - hack/make.sh validate-gofmt - - AUTO_GOPATH=1 ./hack/make.sh dynbinary + - ./hack/make.sh dynbinary + - DOCKER_CLIENTONLY=1 ./hack/make.sh dynbinary # vim:set sw=2 ts=2: diff --git a/docker/client.go b/docker/client.go new file mode 100644 index 0000000000..4565d6d6a1 --- /dev/null +++ b/docker/client.go @@ -0,0 +1,17 @@ +// +build !daemon + +package main + +import ( + "log" +) + +const CanDaemon = false + +func mainSysinit() { + log.Fatal("This is a client-only binary - running it as 'dockerinit' is not supported.") +} + +func mainDaemon() { + log.Fatal("This is a client-only binary - running the Docker daemon is not supported.") +} diff --git a/docker/daemon.go b/docker/daemon.go new file mode 100644 index 0000000000..4b994e9629 --- /dev/null +++ b/docker/daemon.go @@ -0,0 +1,112 @@ +// +build daemon + +package main + +import ( + "log" + "net" + + "github.com/docker/docker/builtins" + "github.com/docker/docker/dockerversion" + "github.com/docker/docker/engine" + flag "github.com/docker/docker/pkg/mflag" + "github.com/docker/docker/sysinit" +) + +const CanDaemon = true + +func mainSysinit() { + // Running in init mode + sysinit.SysInit() +} + +func mainDaemon() { + if flag.NArg() != 0 { + flag.Usage() + return + } + + if *bridgeName != "" && *bridgeIp != "" { + log.Fatal("You specified -b & --bip, mutually exclusive options. Please specify only one.") + } + + if !*flEnableIptables && !*flInterContainerComm { + log.Fatal("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.") + } + + if net.ParseIP(*flDefaultIp) == nil { + log.Fatalf("Specified --ip=%s is not in correct format \"0.0.0.0\".", *flDefaultIp) + } + + eng := engine.New() + // Load builtins + if err := builtins.Register(eng); err != nil { + log.Fatal(err) + } + + // handle the pidfile early. https://github.com/docker/docker/issues/6973 + if len(*pidfile) > 0 { + job := eng.Job("initserverpidfile", *pidfile) + if err := job.Run(); err != nil { + log.Fatal(err) + } + } + + // load the daemon in the background so we can immediately start + // the http api so that connections don't fail while the daemon + // is booting + go func() { + // Load plugin: httpapi + job := eng.Job("initserver") + // include the variable here too, for the server config + job.Setenv("Pidfile", *pidfile) + job.Setenv("Root", *flRoot) + job.SetenvBool("AutoRestart", *flAutoRestart) + job.SetenvList("Dns", flDns.GetAll()) + job.SetenvList("DnsSearch", flDnsSearch.GetAll()) + job.SetenvBool("EnableIptables", *flEnableIptables) + job.SetenvBool("EnableIpForward", *flEnableIpForward) + job.Setenv("BridgeIface", *bridgeName) + job.Setenv("BridgeIP", *bridgeIp) + job.Setenv("DefaultIp", *flDefaultIp) + job.SetenvBool("InterContainerCommunication", *flInterContainerComm) + job.Setenv("GraphDriver", *flGraphDriver) + job.SetenvList("GraphOptions", flGraphOpts.GetAll()) + job.Setenv("ExecDriver", *flExecDriver) + job.SetenvInt("Mtu", *flMtu) + job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled) + job.SetenvList("Sockets", flHosts.GetAll()) + if err := job.Run(); err != nil { + log.Fatal(err) + } + // after the daemon is done setting up we can tell the api to start + // accepting connections + if err := eng.Job("acceptconnections").Run(); err != nil { + log.Fatal(err) + } + }() + + // TODO actually have a resolved graphdriver to show? + log.Printf("docker daemon: %s %s; execdriver: %s; graphdriver: %s", + dockerversion.VERSION, + dockerversion.GITCOMMIT, + *flExecDriver, + *flGraphDriver) + + // Serve api + job := eng.Job("serveapi", flHosts.GetAll()...) + job.SetenvBool("Logging", true) + job.SetenvBool("EnableCors", *flEnableCors) + job.Setenv("Version", dockerversion.VERSION) + job.Setenv("SocketGroup", *flSocketGroup) + + job.SetenvBool("Tls", *flTls) + job.SetenvBool("TlsVerify", *flTlsVerify) + job.Setenv("TlsCa", *flCa) + job.Setenv("TlsCert", *flCert) + job.Setenv("TlsKey", *flKey) + job.SetenvBool("BufferRequests", true) + if err := job.Run(); err != nil { + log.Fatal(err) + } +} diff --git a/docker/docker.go b/docker/docker.go index 679c91b462..38a4da0d44 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -6,19 +6,13 @@ import ( "fmt" "io/ioutil" "log" - "net" "os" - "path/filepath" "strings" "github.com/docker/docker/api" "github.com/docker/docker/api/client" - "github.com/docker/docker/builtins" "github.com/docker/docker/dockerversion" - "github.com/docker/docker/engine" - "github.com/docker/docker/opts" flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/sysinit" "github.com/docker/docker/utils" ) @@ -28,63 +22,24 @@ const ( defaultCertFile = "cert.pem" ) -var ( - dockerConfDir = os.Getenv("DOCKER_CONFIG") -) - func main() { - if len(dockerConfDir) == 0 { - dockerConfDir = filepath.Join(os.Getenv("HOME"), ".docker") - } if selfPath := utils.SelfPath(); strings.Contains(selfPath, ".dockerinit") { - // Running in init mode - sysinit.SysInit() + mainSysinit() return } - var ( - flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit") - flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode") - flGraphOpts opts.ListOpts - flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode") - flAutoRestart = flag.Bool([]string{"r", "-restart"}, true, "Restart previously running containers") - bridgeName = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking") - bridgeIp = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b") - pidfile = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file") - flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime") - flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group") - flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") - flDns = opts.NewListOpts(opts.ValidateIPAddress) - flDnsSearch = opts.NewListOpts(opts.ValidateDnsSearch) - flEnableIptables = flag.Bool([]string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules") - flEnableIpForward = flag.Bool([]string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward") - flDefaultIp = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports") - flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication") - flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver") - flExecDriver = flag.String([]string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver") - flHosts = opts.NewListOpts(api.ValidateHost) - flMtu = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available") - flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags") - flTlsVerify = flag.Bool([]string{"-tlsverify"}, false, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)") - flCa = flag.String([]string{"-tlscacert"}, filepath.Join(dockerConfDir, defaultCaFile), "Trust only remotes providing a certificate signed by the CA given here") - flCert = flag.String([]string{"-tlscert"}, filepath.Join(dockerConfDir, defaultCertFile), "Path to TLS certificate file") - flKey = flag.String([]string{"-tlskey"}, filepath.Join(dockerConfDir, defaultKeyFile), "Path to TLS key file") - flSelinuxEnabled = flag.Bool([]string{"-selinux-enabled"}, false, "Enable selinux support. SELinux does not presently support the BTRFS storage driver") - ) - flag.Var(&flDns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers") - flag.Var(&flDnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains") - flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode\nspecified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.") - flag.Var(&flGraphOpts, []string{"-storage-opt"}, "Set storage driver options") - flag.Parse() if *flVersion { showVersion() return } + if *flDebug { + os.Setenv("DEBUG", "1") + } + if flHosts.Len() == 0 { defaultHost := os.Getenv("DOCKER_HOST") - if defaultHost == "" || *flDaemon { // If we do not have a host, default to unix socket defaultHost = fmt.Sprintf("unix://%s", api.DEFAULTUNIXSOCKET) @@ -95,152 +50,63 @@ func main() { flHosts.Set(defaultHost) } - if *bridgeName != "" && *bridgeIp != "" { - log.Fatal("You specified -b & --bip, mutually exclusive options. Please specify only one.") - } - - if !*flEnableIptables && !*flInterContainerComm { - log.Fatal("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.") - } - - if net.ParseIP(*flDefaultIp) == nil { - log.Fatalf("Specified --ip=%s is not in correct format \"0.0.0.0\".", *flDefaultIp) - } - - if *flDebug { - os.Setenv("DEBUG", "1") - } - if *flDaemon { - if flag.NArg() != 0 { - flag.Usage() - return - } - eng := engine.New() - // Load builtins - if err := builtins.Register(eng); err != nil { - log.Fatal(err) + mainDaemon() + return + } + + if flHosts.Len() > 1 { + log.Fatal("Please specify only one -H") + } + protoAddrParts := strings.SplitN(flHosts.GetAll()[0], "://", 2) + + var ( + cli *client.DockerCli + tlsConfig tls.Config + ) + tlsConfig.InsecureSkipVerify = true + + // If we should verify the server, we need to load a trusted ca + if *flTlsVerify { + *flTls = true + certPool := x509.NewCertPool() + file, err := ioutil.ReadFile(*flCa) + if err != nil { + log.Fatalf("Couldn't read ca cert %s: %s", *flCa, err) } + certPool.AppendCertsFromPEM(file) + tlsConfig.RootCAs = certPool + tlsConfig.InsecureSkipVerify = false + } - // handle the pidfile early. https://github.com/docker/docker/issues/6973 - if len(*pidfile) > 0 { - job := eng.Job("initserverpidfile", *pidfile) - if err := job.Run(); err != nil { - log.Fatal(err) - } - } - - // load the daemon in the background so we can immediately start - // the http api so that connections don't fail while the daemon - // is booting - go func() { - // Load plugin: httpapi - job := eng.Job("initserver") - // include the variable here too, for the server config - job.Setenv("Pidfile", *pidfile) - job.Setenv("Root", *flRoot) - job.SetenvBool("AutoRestart", *flAutoRestart) - job.SetenvList("Dns", flDns.GetAll()) - job.SetenvList("DnsSearch", flDnsSearch.GetAll()) - job.SetenvBool("EnableIptables", *flEnableIptables) - job.SetenvBool("EnableIpForward", *flEnableIpForward) - job.Setenv("BridgeIface", *bridgeName) - job.Setenv("BridgeIP", *bridgeIp) - job.Setenv("DefaultIp", *flDefaultIp) - job.SetenvBool("InterContainerCommunication", *flInterContainerComm) - job.Setenv("GraphDriver", *flGraphDriver) - job.SetenvList("GraphOptions", flGraphOpts.GetAll()) - job.Setenv("ExecDriver", *flExecDriver) - job.SetenvInt("Mtu", *flMtu) - job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled) - job.SetenvList("Sockets", flHosts.GetAll()) - if err := job.Run(); err != nil { - log.Fatal(err) - } - // after the daemon is done setting up we can tell the api to start - // accepting connections - if err := eng.Job("acceptconnections").Run(); err != nil { - log.Fatal(err) - } - }() - - // TODO actually have a resolved graphdriver to show? - log.Printf("docker daemon: %s %s; execdriver: %s; graphdriver: %s", - dockerversion.VERSION, - dockerversion.GITCOMMIT, - *flExecDriver, - *flGraphDriver) - - // Serve api - job := eng.Job("serveapi", flHosts.GetAll()...) - job.SetenvBool("Logging", true) - job.SetenvBool("EnableCors", *flEnableCors) - job.Setenv("Version", dockerversion.VERSION) - job.Setenv("SocketGroup", *flSocketGroup) - - job.SetenvBool("Tls", *flTls) - job.SetenvBool("TlsVerify", *flTlsVerify) - job.Setenv("TlsCa", *flCa) - job.Setenv("TlsCert", *flCert) - job.Setenv("TlsKey", *flKey) - job.SetenvBool("BufferRequests", true) - if err := job.Run(); err != nil { - log.Fatal(err) - } - } else { - if flHosts.Len() > 1 { - log.Fatal("Please specify only one -H") - } - protoAddrParts := strings.SplitN(flHosts.GetAll()[0], "://", 2) - - var ( - cli *client.DockerCli - tlsConfig tls.Config - ) - tlsConfig.InsecureSkipVerify = true - - // If we should verify the server, we need to load a trusted ca - if *flTlsVerify { + // If tls is enabled, try to load and send client certificates + if *flTls || *flTlsVerify { + _, errCert := os.Stat(*flCert) + _, errKey := os.Stat(*flKey) + if errCert == nil && errKey == nil { *flTls = true - certPool := x509.NewCertPool() - file, err := ioutil.ReadFile(*flCa) + cert, err := tls.LoadX509KeyPair(*flCert, *flKey) if err != nil { - log.Fatalf("Couldn't read ca cert %s: %s", *flCa, err) + log.Fatalf("Couldn't load X509 key pair: %s. Key encrypted?", err) } - certPool.AppendCertsFromPEM(file) - tlsConfig.RootCAs = certPool - tlsConfig.InsecureSkipVerify = false + tlsConfig.Certificates = []tls.Certificate{cert} } + } - // If tls is enabled, try to load and send client certificates - if *flTls || *flTlsVerify { - _, errCert := os.Stat(*flCert) - _, errKey := os.Stat(*flKey) - if errCert == nil && errKey == nil { - *flTls = true - cert, err := tls.LoadX509KeyPair(*flCert, *flKey) - if err != nil { - log.Fatalf("Couldn't load X509 key pair: %s. Key encrypted?", err) - } - tlsConfig.Certificates = []tls.Certificate{cert} + if *flTls || *flTlsVerify { + cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], &tlsConfig) + } else { + cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], nil) + } + + if err := cli.ParseCommands(flag.Args()...); err != nil { + if sterr, ok := err.(*utils.StatusError); ok { + if sterr.Status != "" { + log.Println(sterr.Status) } + os.Exit(sterr.StatusCode) } - - if *flTls || *flTlsVerify { - cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], &tlsConfig) - } else { - cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], nil) - } - - if err := cli.ParseCommands(flag.Args()...); err != nil { - if sterr, ok := err.(*utils.StatusError); ok { - if sterr.Status != "" { - log.Println(sterr.Status) - } - os.Exit(sterr.StatusCode) - } - log.Fatal(err) - } + log.Fatal(err) } } diff --git a/docker/flags.go b/docker/flags.go new file mode 100644 index 0000000000..17b23d9391 --- /dev/null +++ b/docker/flags.go @@ -0,0 +1,63 @@ +package main + +import ( + "os" + "path/filepath" + + "github.com/docker/docker/api" + "github.com/docker/docker/opts" + flag "github.com/docker/docker/pkg/mflag" +) + +var ( + dockerConfDir = os.Getenv("DOCKER_CONFIG") +) + +func init() { + if dockerConfDir == "" { + dockerConfDir = filepath.Join(os.Getenv("HOME"), ".docker") + } +} + +var ( + flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit") + flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode") + flGraphOpts opts.ListOpts + flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode") + flAutoRestart = flag.Bool([]string{"r", "-restart"}, true, "Restart previously running containers") + bridgeName = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking") + bridgeIp = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b") + pidfile = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file") + flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime") + flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group") + flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") + flDns = opts.NewListOpts(opts.ValidateIPAddress) + flDnsSearch = opts.NewListOpts(opts.ValidateDnsSearch) + flEnableIptables = flag.Bool([]string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules") + flEnableIpForward = flag.Bool([]string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward") + flDefaultIp = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports") + flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication") + flGraphDriver = flag.String([]string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver") + flExecDriver = flag.String([]string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver") + flHosts = opts.NewListOpts(api.ValidateHost) + flMtu = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available") + flTls = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags") + flTlsVerify = flag.Bool([]string{"-tlsverify"}, false, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)") + flSelinuxEnabled = flag.Bool([]string{"-selinux-enabled"}, false, "Enable selinux support. SELinux does not presently support the BTRFS storage driver") + + // these are initialized in init() below since their default values depend on dockerConfDir which isn't fully initialized until init() runs + flCa *string + flCert *string + flKey *string +) + +func init() { + flCa = flag.String([]string{"-tlscacert"}, filepath.Join(dockerConfDir, defaultCaFile), "Trust only remotes providing a certificate signed by the CA given here") + flCert = flag.String([]string{"-tlscert"}, filepath.Join(dockerConfDir, defaultCertFile), "Path to TLS certificate file") + flKey = flag.String([]string{"-tlskey"}, filepath.Join(dockerConfDir, defaultKeyFile), "Path to TLS key file") + + flag.Var(&flDns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers") + flag.Var(&flDnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains") + flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode\nspecified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.") + flag.Var(&flGraphOpts, []string{"-storage-opt"}, "Set storage driver options") +} diff --git a/hack/make.sh b/hack/make.sh index 2d883cd883..05e3310889 100755 --- a/hack/make.sh +++ b/hack/make.sh @@ -90,6 +90,10 @@ if [ ! "$GOPATH" ]; then exit 1 fi +if [ -z "$DOCKER_CLIENTONLY" ]; then + DOCKER_BUILDTAGS+=" daemon" +fi + # Use these flags when compiling the tests and final binary LDFLAGS=' -w