From 547e13b5852ed2e063af8b8c0d351eff517d2db5 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Tue, 12 Mar 2013 15:05:41 -0700 Subject: [PATCH 1/5] Removed interactive mode ('docker -i'). Cool UI experiment but seems more trouble than it's worth Upstream-commit: d2cba75d5f1e8ceea7f301ef146c571806252fa0 Component: engine --- components/engine/client/client.go | 73 ------------------------------ components/engine/docker/docker.go | 20 +------- 2 files changed, 2 insertions(+), 91 deletions(-) diff --git a/components/engine/client/client.go b/components/engine/client/client.go index 073fe02b0b..815e20a048 100644 --- a/components/engine/client/client.go +++ b/components/engine/client/client.go @@ -4,12 +4,8 @@ import ( "../future" "../rcli" "io" - "io/ioutil" "log" "os" - "os/exec" - "path" - "path/filepath" ) // Run docker in "simple mode": run a single command and return. @@ -55,72 +51,3 @@ func SimpleMode(args []string) error { } return nil } - -// Run docker in "interactive mode": run a bash-compatible shell capable of running docker commands. -func InteractiveMode(scripts ...string) error { - // Determine path of current docker binary - dockerPath, err := exec.LookPath(os.Args[0]) - if err != nil { - return err - } - dockerPath, err = filepath.Abs(dockerPath) - if err != nil { - return err - } - - // Create a temp directory - tmp, err := ioutil.TempDir("", "docker-shell") - if err != nil { - return err - } - defer os.RemoveAll(tmp) - - // For each command, create an alias in temp directory - // FIXME: generate this list dynamically with introspection of some sort - // It might make sense to merge docker and dockerd to keep that introspection - // within a single binary. - for _, cmd := range []string{ - "help", - "run", - "ps", - "pull", - "put", - "rm", - "kill", - "wait", - "stop", - "start", - "restart", - "logs", - "diff", - "commit", - "attach", - "info", - "tar", - "web", - "images", - "docker", - } { - if err := os.Symlink(dockerPath, path.Join(tmp, cmd)); err != nil { - return err - } - } - - // Run $SHELL with PATH set to temp directory - rcfile, err := ioutil.TempFile("", "docker-shell-rc") - if err != nil { - return err - } - defer os.Remove(rcfile.Name()) - io.WriteString(rcfile, "enable -n help\n") - os.Setenv("PATH", tmp+":"+os.Getenv("PATH")) - os.Setenv("PS1", "\\h docker> ") - shell := exec.Command("/bin/bash", append([]string{"--rcfile", rcfile.Name()}, scripts...)...) - shell.Stdin = os.Stdin - shell.Stdout = os.Stdout - shell.Stderr = os.Stderr - if err := shell.Run(); err != nil { - return err - } - return nil -} diff --git a/components/engine/docker/docker.go b/components/engine/docker/docker.go index df8a094430..b43d5b1053 100644 --- a/components/engine/docker/docker.go +++ b/components/engine/docker/docker.go @@ -2,28 +2,12 @@ package main import ( "../client" - "flag" "log" "os" - "path" ) func main() { - if cmd := path.Base(os.Args[0]); cmd == "docker" { - fl_shell := flag.Bool("i", false, "Interactive mode") - flag.Parse() - if *fl_shell { - if err := client.InteractiveMode(flag.Args()...); err != nil { - log.Fatal(err) - } - } else { - if err := client.SimpleMode(os.Args[1:]); err != nil { - log.Fatal(err) - } - } - } else { - if err := client.SimpleMode(append([]string{cmd}, os.Args[1:]...)); err != nil { - log.Fatal(err) - } + if err := client.SimpleMode(os.Args[1:]); err != nil { + log.Fatal(err) } } From 621d110d7f4f2814f4281f3a2aa0bb921d887b72 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Wed, 13 Mar 2013 00:29:40 -0700 Subject: [PATCH 2/5] Merge dockerd into docker. 'docker -d' runs in daemon mode. For all other commands, docker auto-detects whether to run standalone or to remote-control the daemon Upstream-commit: 745edc49cdcf0dc02fe714b0772f146fc8a66d23 Component: engine --- components/engine/.gitignore | 1 - components/engine/client/client.go | 53 ------------ .../server.go => commands/commands.go} | 11 +-- components/engine/docker/docker.go | 86 ++++++++++++++++++- components/engine/dockerd/dockerd.go | 24 ------ components/engine/rcli/types.go | 5 ++ components/engine/{client => term}/term.go | 2 +- .../engine/{client => term}/termios_darwin.go | 2 +- .../engine/{client => term}/termios_linux.go | 2 +- 9 files changed, 92 insertions(+), 94 deletions(-) delete mode 100644 components/engine/client/client.go rename components/engine/{server/server.go => commands/commands.go} (98%) delete mode 100644 components/engine/dockerd/dockerd.go rename components/engine/{client => term}/term.go (99%) rename components/engine/{client => term}/termios_darwin.go (85%) rename components/engine/{client => term}/termios_linux.go (85%) diff --git a/components/engine/.gitignore b/components/engine/.gitignore index d557404214..686ac83428 100644 --- a/components/engine/.gitignore +++ b/components/engine/.gitignore @@ -1,6 +1,5 @@ .vagrant docker/docker -dockerd/dockerd .*.swp a.out *.orig diff --git a/components/engine/client/client.go b/components/engine/client/client.go deleted file mode 100644 index 30d741f8bd..0000000000 --- a/components/engine/client/client.go +++ /dev/null @@ -1,53 +0,0 @@ -package client - -import ( - "github.com/dotcloud/docker/future" - "github.com/dotcloud/docker/rcli" - "io" - "log" - "os" -) - -// Run docker in "simple mode": run a single command and return. -func SimpleMode(args []string) error { - var oldState *State - var err error - if IsTerminal(0) && os.Getenv("NORAW") == "" { - oldState, err = MakeRaw(0) - if err != nil { - return err - } - defer Restore(0, oldState) - } - // FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose - // CloseWrite(), which we need to cleanly signal that stdin is closed without - // closing the connection. - // See http://code.google.com/p/go/issues/detail?id=3345 - conn, err := rcli.Call("tcp", "127.0.0.1:4242", args...) - if err != nil { - return err - } - receive_stdout := future.Go(func() error { - _, err := io.Copy(os.Stdout, conn) - return err - }) - send_stdin := future.Go(func() error { - _, err := io.Copy(conn, os.Stdin) - if err := conn.CloseWrite(); err != nil { - log.Printf("Couldn't send EOF: " + err.Error()) - } - return err - }) - if err := <-receive_stdout; err != nil { - return err - } - if oldState != nil { - Restore(0, oldState) - } - if !IsTerminal(0) { - if err := <-send_stdin; err != nil { - return err - } - } - return nil -} diff --git a/components/engine/server/server.go b/components/engine/commands/commands.go similarity index 98% rename from components/engine/server/server.go rename to components/engine/commands/commands.go index 18dc578190..14649cad1f 100644 --- a/components/engine/server/server.go +++ b/components/engine/commands/commands.go @@ -1,4 +1,4 @@ -package server +package commands import ( "bufio" @@ -24,15 +24,6 @@ import ( const VERSION = "0.0.1" -func (srv *Server) ListenAndServe() error { - go rcli.ListenAndServeHTTP("127.0.0.1:8080", srv) - // FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose - // CloseWrite(), which we need to cleanly signal that stdin is closed without - // closing the connection. - // See http://code.google.com/p/go/issues/detail?id=3345 - return rcli.ListenAndServe("tcp", "127.0.0.1:4242", srv) -} - func (srv *Server) Name() string { return "docker" } diff --git a/components/engine/docker/docker.go b/components/engine/docker/docker.go index 29a550c7b4..ad121a8f60 100644 --- a/components/engine/docker/docker.go +++ b/components/engine/docker/docker.go @@ -1,13 +1,93 @@ package main import ( - "github.com/dotcloud/docker/client" + "flag" + "github.com/dotcloud/docker" + "github.com/dotcloud/docker/commands" + "github.com/dotcloud/docker/future" + "github.com/dotcloud/docker/rcli" + "github.com/dotcloud/docker/term" + "io" "log" "os" ) func main() { - if err := client.SimpleMode(os.Args[1:]); err != nil { - log.Fatal(err) + if docker.SelfPath() == "/sbin/init" { + // Running in init mode + docker.SysInit() + return + } + fl_daemon := flag.Bool("d", false, "Daemon mode") + flag.Parse() + if *fl_daemon { + if flag.NArg() != 0 { + flag.Usage() + return + } + if err := daemon(); err != nil { + log.Fatal(err) + } + } else { + if err := runCommand(flag.Args()); err != nil { + log.Fatal(err) + } } } + +func daemon() error { + service, err := commands.New() + if err != nil { + return err + } + return rcli.ListenAndServe("tcp", "127.0.0.1:4242", service) +} + +func runCommand(args []string) error { + var oldState *term.State + var err error + if term.IsTerminal(0) && os.Getenv("NORAW") == "" { + oldState, err = term.MakeRaw(0) + if err != nil { + return err + } + defer term.Restore(0, oldState) + } + // FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose + // CloseWrite(), which we need to cleanly signal that stdin is closed without + // closing the connection. + // See http://code.google.com/p/go/issues/detail?id=3345 + if conn, err := rcli.Call("tcp", "127.0.0.1:4242", args...); err == nil { + receive_stdout := future.Go(func() error { + _, err := io.Copy(os.Stdout, conn) + return err + }) + send_stdin := future.Go(func() error { + _, err := io.Copy(conn, os.Stdin) + if err := conn.CloseWrite(); err != nil { + log.Printf("Couldn't send EOF: " + err.Error()) + } + return err + }) + if err := <-receive_stdout; err != nil { + return err + } + if !term.IsTerminal(0) { + if err := <-send_stdin; err != nil { + return err + } + } + } else { + service, err := commands.New() + if err != nil { + return err + } + if err := rcli.LocalCall(service, os.Stdin, os.Stdout, args...); err != nil { + return err + } + } + if oldState != nil { + term.Restore(0, oldState) + } + return nil +} diff --git a/components/engine/dockerd/dockerd.go b/components/engine/dockerd/dockerd.go deleted file mode 100644 index b2337d342c..0000000000 --- a/components/engine/dockerd/dockerd.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "flag" - "github.com/dotcloud/docker" - "github.com/dotcloud/docker/server" - "log" -) - -func main() { - if docker.SelfPath() == "/sbin/init" { - // Running in init mode - docker.SysInit() - return - } - flag.Parse() - d, err := server.New() - if err != nil { - log.Fatal(err) - } - if err := d.ListenAndServe(); err != nil { - log.Fatal(err) - } -} diff --git a/components/engine/rcli/types.go b/components/engine/rcli/types.go index 52079291b6..2600fe240d 100644 --- a/components/engine/rcli/types.go +++ b/components/engine/rcli/types.go @@ -25,7 +25,12 @@ type Service interface { type Cmd func(io.ReadCloser, io.Writer, ...string) error type CmdMethod func(Service, io.ReadCloser, io.Writer, ...string) error +// FIXME: For reverse compatibility func call(service Service, stdin io.ReadCloser, stdout io.Writer, args ...string) error { + return LocalCall(service, stdin, stdout, args...) +} + +func LocalCall(service Service, stdin io.ReadCloser, stdout io.Writer, args ...string) error { if len(args) == 0 { args = []string{"help"} } diff --git a/components/engine/client/term.go b/components/engine/term/term.go similarity index 99% rename from components/engine/client/term.go rename to components/engine/term/term.go index a988d0d796..fdbe3b9984 100644 --- a/components/engine/client/term.go +++ b/components/engine/term/term.go @@ -1,4 +1,4 @@ -package client +package term import ( "syscall" diff --git a/components/engine/client/termios_darwin.go b/components/engine/term/termios_darwin.go similarity index 85% rename from components/engine/client/termios_darwin.go rename to components/engine/term/termios_darwin.go index 185687920c..26d17b3bb8 100644 --- a/components/engine/client/termios_darwin.go +++ b/components/engine/term/termios_darwin.go @@ -1,4 +1,4 @@ -package client +package term import "syscall" diff --git a/components/engine/client/termios_linux.go b/components/engine/term/termios_linux.go similarity index 85% rename from components/engine/client/termios_linux.go rename to components/engine/term/termios_linux.go index 36957c44a1..1ea26fa5c4 100644 --- a/components/engine/client/termios_linux.go +++ b/components/engine/term/termios_linux.go @@ -1,4 +1,4 @@ -package client +package term import "syscall" From bea2df9aa00b0cea121cd7912ee61954ee8c69ee Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Wed, 13 Mar 2013 11:46:09 -0700 Subject: [PATCH 3/5] Updated README Upstream-commit: baf6988d872be24130fc2923bef227f5365cbf1b Component: engine --- components/engine/README.md | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/components/engine/README.md b/components/engine/README.md index 8a4a78b1e3..49a418bae9 100644 --- a/components/engine/README.md +++ b/components/engine/README.md @@ -50,11 +50,31 @@ Under the hood, Docker is built on the following components: * [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to simplify the creation of linux containers. -Setup instructions +Install instructions ================== -Requirements ------------- +Installing on Ubuntu 12.04 and 12.10 +------------------------------------ + +1. Install dependencies: + + sudo apt-get install lxc wget bsdtar curl + +2. Install the latest docker binary: + + wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz + tar -xf docker-master.tgz + +3. Run your first container! + + cd docker-master + sudo ./docker import base + sudo ./docker run -a -i -t base /bin/bash + +Consider adding docker to your `PATH` for simplicity. + +Installing on other Linux distributions +--------------------------------------- Right now, the officially supported distributions are: @@ -64,26 +84,6 @@ Right now, the officially supported distributions are: Docker probably works on other distributions featuring a recent kernel, the AUFS patch, and up-to-date lxc. However this has not been tested. -Installation ---------------- - -1. Set up your host of choice on a physical / virtual machine -2. Assume root identity on your newly installed environment (`sudo -s`) -3. Type the following commands: - - apt-get update - apt-get install lxc wget bsdtar curl - -4. Download the latest docker binaries: `wget http://docker.io.s3.amazonaws.com/builds/$(uname -s)/$(uname -m)/docker-master.tgz` ([Or get the Linux/x86_64 binaries here](http://docker.io.s3.amazonaws.com/builds/Linux/x86_64/docker-master.tgz) ) -5. Extract the contents of the tar file `tar -xf docker-master.tar.gz` -6. Launch the docker daemon in the background `./dockerd &` -7. Download a base image `./docker pull base` -8. Run your first container! `./docker run -i -a -t base /bin/bash` -9. Start exploring `./docker --help` - -Consider adding docker and dockerd to your `PATH` for simplicity. - - What is a Standard Container? ----------------------------- From 1c95edd498fe64226fe6e0640986d2c05338cc57 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Wed, 13 Mar 2013 11:58:15 -0700 Subject: [PATCH 4/5] Added usage exmaples to the README Upstream-commit: d614e91b62339d1960cf171c2436404bb1fa8806 Component: engine --- components/engine/README.md | 62 ++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/components/engine/README.md b/components/engine/README.md index 49a418bae9..103410e799 100644 --- a/components/engine/README.md +++ b/components/engine/README.md @@ -84,8 +84,68 @@ Right now, the officially supported distributions are: Docker probably works on other distributions featuring a recent kernel, the AUFS patch, and up-to-date lxc. However this has not been tested. +Usage examples +============== + +Running an interactive shell +---------------------------- + +```bash + # Download a base image + docker import base + + # Run an interactive shell in the base image, + # allocate a tty, attach stdin and stdout + docker run -a -i -t base /bin/bash +``` + + +Starting a long-running worker process +-------------------------------------- + +```bash + # Run docker in daemon mode + (docker -d || echo "Docker daemon already running") & + + # Start a very useful long-running process + JOB=$(docker run /bin/sh -c "while true; do echo Hello world!; sleep 1; done") + + # Collect the output of the job so far + docker logs $JOB + + # Kill the job + docker kill $JOB +``` + + +Listing all running containers +------------------------------ + +```bash + docker ps +``` + + +Expose a service on a TCP port +------------------------------ + +```bash + # Expose port 4444 of this container, and tell netcat to listen on it + JOB=$(docker run -p 4444 base /bin/nc -l -p 4444) + + # Which public port is NATed to my container? + PORT=$(docker port $JOB 4444) + + # Connect to the public port via the host's public address + echo hello world | nc $(hostname) $PORT + + # Verify that the network connection worked + echo "Daemon received: $(docker logs $JOB)" +``` + + What is a Standard Container? ------------------------------ +============================= Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in a format that is self-describing and portable, so that any compliant runtime can run it without extra dependency, regardless of the underlying machine and the contents of the container. From 8e04b25bbd33103b88c71d26a675480c99afbdca Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Wed, 13 Mar 2013 12:00:13 -0700 Subject: [PATCH 5/5] Fixed formatting in README Upstream-commit: 8d5f683dc47795f6797eb14b498149c612398bd2 Component: engine --- components/engine/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/engine/README.md b/components/engine/README.md index 103410e799..07449fa3fa 100644 --- a/components/engine/README.md +++ b/components/engine/README.md @@ -58,18 +58,24 @@ Installing on Ubuntu 12.04 and 12.10 1. Install dependencies: +```bash sudo apt-get install lxc wget bsdtar curl +``` 2. Install the latest docker binary: +```bash wget http://get.docker.io/builds/$(uname -s)/$(uname -m)/docker-master.tgz tar -xf docker-master.tgz +``` 3. Run your first container! +```bash cd docker-master sudo ./docker import base sudo ./docker run -a -i -t base /bin/bash +``` Consider adding docker to your `PATH` for simplicity.