2013-01-20 00:07:19 +00:00
package main
import (
2014-02-27 12:47:59 +00:00
"crypto/tls"
"crypto/x509"
2013-04-10 10:24:15 +00:00
"fmt"
2014-02-27 12:47:59 +00:00
"io/ioutil"
2014-02-01 11:38:39 +00:00
"log"
2014-06-27 13:55:20 +00:00
"net"
2014-02-01 11:38:39 +00:00
"os"
2014-03-14 23:53:43 +00:00
"runtime"
2014-02-01 11:38:39 +00:00
"strings"
2014-01-29 19:26:54 +00:00
"github.com/dotcloud/docker/api"
2014-03-28 22:59:29 +00:00
"github.com/dotcloud/docker/api/client"
2014-02-19 23:27:57 +00:00
"github.com/dotcloud/docker/builtins"
2014-02-12 00:05:45 +00:00
"github.com/dotcloud/docker/dockerversion"
2013-11-07 20:19:24 +00:00
"github.com/dotcloud/docker/engine"
2014-03-10 21:10:23 +00:00
"github.com/dotcloud/docker/opts"
2013-12-23 19:43:54 +00:00
flag "github.com/dotcloud/docker/pkg/mflag"
2013-10-10 08:53:38 +00:00
"github.com/dotcloud/docker/sysinit"
2013-05-14 22:37:35 +00:00
"github.com/dotcloud/docker/utils"
2013-01-24 07:14:46 +00:00
)
2014-02-27 12:47:59 +00:00
const (
defaultCaFile = "ca.pem"
defaultKeyFile = "key.pem"
defaultCertFile = "cert.pem"
)
var (
dockerConfDir = os . Getenv ( "HOME" ) + "/.docker/"
)
2013-01-20 00:07:19 +00:00
func main ( ) {
2014-02-25 18:54:41 +00:00
if selfPath := utils . SelfPath ( ) ; strings . Contains ( selfPath , ".dockerinit" ) {
2013-03-13 07:29:40 +00:00
// Running in init mode
2013-10-10 08:53:38 +00:00
sysinit . SysInit ( )
2013-03-13 07:29:40 +00:00
return
2013-01-25 19:26:18 +00:00
}
2013-11-26 17:46:06 +00:00
2013-11-26 17:47:58 +00:00
var (
2013-12-23 19:43:54 +00:00
flVersion = flag . Bool ( [ ] string { "v" , "-version" } , false , "Print version information and quit" )
flDaemon = flag . Bool ( [ ] string { "d" , "-daemon" } , false , "Enable daemon mode" )
2014-06-05 08:34:20 +00:00
flGraphOpts opts . ListOpts
2013-12-23 19:43:54 +00:00
flDebug = flag . Bool ( [ ] string { "D" , "-debug" } , false , "Enable debug mode" )
flAutoRestart = flag . Bool ( [ ] string { "r" , "-restart" } , true , "Restart previously running containers" )
2014-05-06 17:51:20 +00:00
bridgeName = flag . String ( [ ] string { "b" , "-bridge" } , "" , "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking" )
2013-12-23 19:43:54 +00:00
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" )
2014-06-19 08:29:40 +00:00
flRoot = flag . String ( [ ] string { "g" , "-graph" } , "/var/lib/docker" , "Path to use as the root of the Docker runtime" )
2014-05-06 17:51:20 +00:00
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" )
2013-12-23 19:43:54 +00:00
flEnableCors = flag . Bool ( [ ] string { "#api-enable-cors" , "-api-enable-cors" } , false , "Enable CORS headers in the remote API" )
2014-02-12 02:46:55 +00:00
flDns = opts . NewListOpts ( opts . ValidateIp4Address )
2014-02-07 16:48:14 +00:00
flDnsSearch = opts . NewListOpts ( opts . ValidateDomain )
2014-03-12 04:44:01 +00:00
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" )
2013-12-23 19:43:54 +00:00
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" )
2014-06-19 08:29:40 +00:00
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" )
2014-02-12 02:46:55 +00:00
flHosts = opts . NewListOpts ( api . ValidateHost )
2014-05-06 17:51:20 +00:00
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" )
2014-02-27 12:47:59 +00:00
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" } , dockerConfDir + defaultCaFile , "Trust only remotes providing a certificate signed by the CA given here" )
flCert = flag . String ( [ ] string { "-tlscert" } , dockerConfDir + defaultCertFile , "Path to TLS certificate file" )
flKey = flag . String ( [ ] string { "-tlskey" } , dockerConfDir + defaultKeyFile , "Path to TLS key file" )
2014-04-17 23:47:27 +00:00
flSelinuxEnabled = flag . Bool ( [ ] string { "-selinux-enabled" } , false , "Enable selinux support" )
2013-11-26 17:47:58 +00:00
)
2014-06-19 08:29:40 +00:00
flag . Var ( & flDns , [ ] string { "#dns" , "-dns" } , "Force Docker to use specific DNS servers" )
2014-02-07 16:48:14 +00:00
flag . Var ( & flDnsSearch , [ ] string { "-dns-search" } , "Force Docker to use specific DNS search domains" )
2014-05-06 17:51:20 +00:00
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." )
2014-06-05 08:34:20 +00:00
flag . Var ( & flGraphOpts , [ ] string { "-storage-opt" } , "Set storage driver options" )
2013-10-05 02:25:15 +00:00
2013-03-13 07:29:40 +00:00
flag . Parse ( )
2013-10-05 02:25:15 +00:00
2013-08-07 03:51:12 +00:00
if * flVersion {
showVersion ( )
return
}
2013-11-26 17:50:43 +00:00
if flHosts . Len ( ) == 0 {
2013-12-21 00:30:41 +00:00
defaultHost := os . Getenv ( "DOCKER_HOST" )
if defaultHost == "" || * flDaemon {
// If we do not have a host, default to unix socket
2014-01-29 19:26:54 +00:00
defaultHost = fmt . Sprintf ( "unix://%s" , api . DEFAULTUNIXSOCKET )
2013-12-21 00:30:41 +00:00
}
2014-02-17 19:35:26 +00:00
if _ , err := api . ValidateHost ( defaultHost ) ; err != nil {
log . Fatal ( err )
}
2013-12-21 00:30:41 +00:00
flHosts . Set ( defaultHost )
2013-06-19 12:31:54 +00:00
}
2013-12-13 15:47:19 +00:00
if * bridgeName != "" && * bridgeIp != "" {
2013-12-23 19:43:54 +00:00
log . Fatal ( "You specified -b & --bip, mutually exclusive options. Please specify only one." )
2013-12-13 15:47:19 +00:00
}
2014-06-24 18:57:35 +00:00
if ! * flEnableIptables && ! * flInterContainerComm {
log . Fatal ( "You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true." )
}
2014-06-27 13:55:20 +00:00
if net . ParseIP ( * flDefaultIp ) == nil {
log . Fatalf ( "Specified --ip=%s is not in correct format \"0.0.0.0\"." , * flDefaultIp )
}
2013-04-02 17:58:16 +00:00
if * flDebug {
os . Setenv ( "DEBUG" , "1" )
}
2014-02-27 12:47:59 +00:00
2013-03-29 00:12:23 +00:00
if * flDaemon {
2014-05-13 02:50:31 +00:00
if runtime . GOOS != "linux" {
log . Fatalf ( "The Docker daemon is only supported on linux" )
}
2014-04-30 11:13:39 +00:00
if os . Geteuid ( ) != 0 {
log . Fatalf ( "The Docker daemon needs to be run as root" )
}
2013-03-13 07:29:40 +00:00
if flag . NArg ( ) != 0 {
flag . Usage ( )
return
}
2013-12-18 18:15:09 +00:00
2014-02-24 21:10:06 +00:00
// set up the TempDir to use a canonical path
tmp := os . TempDir ( )
realTmp , err := utils . ReadSymlinkedDirectory ( tmp )
if err != nil {
log . Fatalf ( "Unable to get the full path to the TempDir (%s): %s" , tmp , err )
}
os . Setenv ( "TMPDIR" , realTmp )
// get the canonical path to the Docker root directory
root := * flRoot
var realRoot string
if _ , err := os . Stat ( root ) ; err != nil && os . IsNotExist ( err ) {
realRoot = root
} else {
realRoot , err = utils . ReadSymlinkedDirectory ( root )
if err != nil {
log . Fatalf ( "Unable to get the full path to root (%s): %s" , root , err )
}
}
2014-03-14 23:53:43 +00:00
if err := checkKernelAndArch ( ) ; err != nil {
log . Fatal ( err )
}
2014-04-23 18:54:35 +00:00
eng := engine . New ( )
2014-02-19 23:27:57 +00:00
// Load builtins
2014-05-03 00:54:52 +00:00
if err := builtins . Register ( eng ) ; err != nil {
log . Fatal ( err )
}
2014-02-16 04:49:50 +00:00
// 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" )
job . Setenv ( "Pidfile" , * pidfile )
2014-02-24 21:10:06 +00:00
job . Setenv ( "Root" , realRoot )
2014-02-16 04:49:50 +00:00
job . SetenvBool ( "AutoRestart" , * flAutoRestart )
job . SetenvList ( "Dns" , flDns . GetAll ( ) )
2014-02-07 16:48:14 +00:00
job . SetenvList ( "DnsSearch" , flDnsSearch . GetAll ( ) )
2014-02-16 04:49:50 +00:00
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 )
2014-06-05 08:34:20 +00:00
job . SetenvList ( "GraphOptions" , flGraphOpts . GetAll ( ) )
2014-02-17 21:54:36 +00:00
job . Setenv ( "ExecDriver" , * flExecDriver )
2014-02-16 04:49:50 +00:00
job . SetenvInt ( "Mtu" , * flMtu )
2014-04-21 21:09:26 +00:00
job . SetenvBool ( "EnableSelinuxSupport" , * flSelinuxEnabled )
2014-04-26 10:22:05 +00:00
job . SetenvList ( "Sockets" , flHosts . GetAll ( ) )
2014-02-16 04:49:50 +00:00
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 )
}
} ( )
2014-04-03 14:54:54 +00:00
// TODO actually have a resolved graphdriver to show?
log . Printf ( "docker daemon: %s %s; execdriver: %s; graphdriver: %s" ,
dockerversion . VERSION ,
dockerversion . GITCOMMIT ,
* flExecDriver ,
* flGraphDriver )
2013-10-27 00:19:35 +00:00
// Serve api
2014-02-16 04:49:50 +00:00
job := eng . Job ( "serveapi" , flHosts . GetAll ( ) ... )
2013-11-05 19:57:40 +00:00
job . SetenvBool ( "Logging" , true )
2014-01-29 00:20:51 +00:00
job . SetenvBool ( "EnableCors" , * flEnableCors )
2014-02-12 00:05:45 +00:00
job . Setenv ( "Version" , dockerversion . VERSION )
2014-01-25 00:18:02 +00:00
job . Setenv ( "SocketGroup" , * flSocketGroup )
2014-02-27 12:47:59 +00:00
job . SetenvBool ( "Tls" , * flTls )
job . SetenvBool ( "TlsVerify" , * flTlsVerify )
job . Setenv ( "TlsCa" , * flCa )
job . Setenv ( "TlsCert" , * flCert )
job . Setenv ( "TlsKey" , * flKey )
2014-05-03 00:11:20 +00:00
job . SetenvBool ( "BufferRequests" , true )
2013-10-27 07:06:43 +00:00
if err := job . Run ( ) ; err != nil {
2013-10-27 00:19:35 +00:00
log . Fatal ( err )
}
2013-03-13 07:29:40 +00:00
} else {
2013-11-26 17:46:06 +00:00
if flHosts . Len ( ) > 1 {
2013-06-19 12:31:54 +00:00
log . Fatal ( "Please specify only one -H" )
}
2013-11-26 17:46:06 +00:00
protoAddrParts := strings . SplitN ( flHosts . GetAll ( ) [ 0 ] , "://" , 2 )
2014-02-27 12:47:59 +00:00
var (
2014-03-28 22:59:29 +00:00
cli * client . DockerCli
2014-02-27 12:47:59 +00:00
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
}
// 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 {
2014-03-28 22:59:29 +00:00
cli = client . NewDockerCli ( os . Stdin , os . Stdout , os . Stderr , protoAddrParts [ 0 ] , protoAddrParts [ 1 ] , & tlsConfig )
2014-02-27 12:47:59 +00:00
} else {
2014-03-28 22:59:29 +00:00
cli = client . NewDockerCli ( os . Stdin , os . Stdout , os . Stderr , protoAddrParts [ 0 ] , protoAddrParts [ 1 ] , nil )
2014-02-27 12:47:59 +00:00
}
2014-03-19 22:03:11 +00:00
2014-03-14 00:47:13 +00:00
if err := cli . ParseCommands ( flag . Args ( ) ... ) ; err != nil {
2013-09-09 21:26:35 +00:00
if sterr , ok := err . ( * utils . StatusError ) ; ok {
2013-10-12 12:14:52 +00:00
if sterr . Status != "" {
log . Println ( sterr . Status )
}
os . Exit ( sterr . StatusCode )
2013-09-09 21:26:35 +00:00
}
2013-03-13 07:29:40 +00:00
log . Fatal ( err )
}
}
}
2013-08-07 03:51:12 +00:00
func showVersion ( ) {
2014-02-12 00:05:45 +00:00
fmt . Printf ( "Docker version %s, build %s\n" , dockerversion . VERSION , dockerversion . GITCOMMIT )
2013-08-07 03:51:12 +00:00
}
2014-03-14 23:53:43 +00:00
func checkKernelAndArch ( ) error {
// Check for unsupported architectures
if runtime . GOARCH != "amd64" {
2014-06-19 08:29:40 +00:00
return fmt . Errorf ( "The Docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting." , runtime . GOARCH )
2014-03-14 23:53:43 +00:00
}
// Check for unsupported kernel versions
// FIXME: it would be cleaner to not test for specific versions, but rather
// test for specific functionalities.
// Unfortunately we can't test for the feature "does not cause a kernel panic"
// without actually causing a kernel panic, so we need this workaround until
// the circumstances of pre-3.8 crashes are clearer.
// For details see http://github.com/dotcloud/docker/issues/407
if k , err := utils . GetKernelVersion ( ) ; err != nil {
log . Printf ( "WARNING: %s\n" , err )
} else {
if utils . CompareKernelVersion ( k , & utils . KernelVersionInfo { Kernel : 3 , Major : 8 , Minor : 0 } ) < 0 {
if os . Getenv ( "DOCKER_NOWARN_KERNEL_VERSION" ) == "" {
log . Printf ( "WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0." , k . String ( ) )
}
}
}
return nil
}