浏览代码

Merge branch 'master' into 32-aufs_delete_fix

creack 12 年之前
父节点
当前提交
77272bea9c
共有 11 个文件被更改,包括 218 次插入223 次删除
  1. 0 1
      .gitignore
  2. 84 18
      README.md
  3. 0 126
      client/client.go
  4. 31 38
      commands/commands.go
  5. 77 13
      docker/docker.go
  6. 0 24
      dockerd/dockerd.go
  7. 18 0
      fs/store.go
  8. 5 0
      rcli/types.go
  9. 1 1
      term/term.go
  10. 1 1
      term/termios_darwin.go
  11. 1 1
      term/termios_linux.go

+ 0 - 1
.gitignore

@@ -1,6 +1,5 @@
 .vagrant
 docker/docker
-dockerd/dockerd
 .*.swp
 a.out
 *.orig

+ 84 - 18
README.md

@@ -50,11 +50,37 @@ 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:
+
+```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.
+
+Installing on other Linux distributions
+---------------------------------------
 
 Right now, the officially supported distributions are:
 
@@ -64,28 +90,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.
 
 
-Installation
----------------
+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
+------------------------------
 
-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:
+```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)
 
-        apt-get update
-        apt-get install lxc wget bsdtar curl
+	# Which public port is NATed to my container?
+	PORT=$(docker port $JOB 4444)
 
-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`
+	# Connect to the public port via the host's public address
+	echo hello world | nc $(hostname) $PORT
 
-Consider adding docker and dockerd to your `PATH` for simplicity.
+	# 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.

+ 0 - 126
client/client.go

@@ -1,126 +0,0 @@
-package client
-
-import (
-	"github.com/dotcloud/docker/future"
-	"github.com/dotcloud/docker/rcli"
-	"io"
-	"io/ioutil"
-	"log"
-	"os"
-	"os/exec"
-	"path"
-	"path/filepath"
-)
-
-// 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
-}
-
-// 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
-}

+ 31 - 38
server/server.go → 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"
 }
@@ -360,34 +351,36 @@ func (srv *Server) CmdPort(stdin io.ReadCloser, stdout io.Writer, args ...string
 }
 
 // 'docker rmi NAME' removes all images with the name NAME
-// func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
-// 	cmd := rcli.Subcmd(stdout, "rmimage", "[OPTIONS] IMAGE", "Remove an image")
-// 	fl_regexp := cmd.Bool("r", false, "Use IMAGE as a regular expression instead of an exact name")
-// 	if err := cmd.Parse(args); err != nil {
-// 		cmd.Usage()
-// 		return nil
-// 	}
-// 	if cmd.NArg() < 1 {
-// 		cmd.Usage()
-// 		return nil
-// 	}
-// 	for _, name := range cmd.Args() {
-// 		var err error
-// 		if *fl_regexp {
-// 			err = srv.images.DeleteMatch(name)
-// 		} else {
-// 			image := srv.images.Find(name)
-// 			if image == nil {
-// 				return errors.New("No such image: " + name)
-// 			}
-// 			err = srv.images.Delete(name)
-// 		}
-// 		if err != nil {
-// 			return err
-// 		}
-// 	}
-// 	return nil
-// }
+func (srv *Server) CmdRmi(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
+	cmd := rcli.Subcmd(stdout, "rmimage", "[OPTIONS] IMAGE", "Remove an image")
+	fl_all := cmd.Bool("a", false, "Use IMAGE as a path and remove ALL images in this path")
+	if err := cmd.Parse(args); err != nil {
+		cmd.Usage()
+		return nil
+	}
+	if cmd.NArg() < 1 {
+		cmd.Usage()
+		return nil
+	}
+	for _, name := range cmd.Args() {
+		var err error
+		if *fl_all {
+			err = srv.images.RemoveInPath(name)
+		} else {
+			image, err := srv.images.Get(name)
+			if err != nil {
+				return err
+			} else if image == nil {
+				return errors.New("No such image: " + name)
+			}
+			err = srv.images.Remove(image)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
 
 func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout, "rm", "[OPTIONS] CONTAINER", "Remove a container")

+ 77 - 13
docker/docker.go

@@ -2,28 +2,92 @@ package main
 
 import (
 	"flag"
-	"github.com/dotcloud/docker/client"
+	"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"
-	"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)
+	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())
 			}
-		} else {
-			if err := client.SimpleMode(os.Args[1:]); err != nil {
-				log.Fatal(err)
+			return err
+		})
+		if err := <-receive_stdout; err != nil {
+			return err
+		}
+		if !term.IsTerminal(0) {
+			if err := <-send_stdin; err != nil {
+				return err
 			}
 		}
 	} else {
-		if err := client.SimpleMode(append([]string{cmd}, os.Args[1:]...)); err != nil {
-			log.Fatal(err)
+		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
 }

+ 0 - 24
dockerd/dockerd.go

@@ -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)
-	}
-}

+ 18 - 0
fs/store.go

@@ -91,6 +91,24 @@ func (store *Store) Paths() ([]string, error) {
 	return paths, nil
 }
 
+func (store *Store) RemoveInPath(pth string) error {
+	images, err := store.List(pth)
+	if err != nil {
+		return err
+	}
+	for _, img := range images {
+		if err = store.Remove(img); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (store *Store) Remove(img *Image) error {
+	_, err := store.orm.Delete(img)
+	return err
+}
+
 func (store *Store) List(pth string) ([]*Image, error) {
 	pth = path.Clean(pth)
 	images, err := store.orm.Select(Image{}, "select images.* from images, paths where Path=? and paths.Image=images.Id", pth)

+ 5 - 0
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"}
 	}

+ 1 - 1
client/term.go → term/term.go

@@ -1,4 +1,4 @@
-package client
+package term
 
 import (
 	"syscall"

+ 1 - 1
client/termios_darwin.go → term/termios_darwin.go

@@ -1,4 +1,4 @@
-package client
+package term
 
 import "syscall"
 

+ 1 - 1
client/termios_linux.go → term/termios_linux.go

@@ -1,4 +1,4 @@
-package client
+package term
 
 import "syscall"