Solomon Hykes há 12 anos atrás
pai
commit
2d5a1abf79
6 ficheiros alterados com 117 adições e 55 exclusões
  1. 9 0
      container.go
  2. 7 0
      docker_test.go
  3. 45 47
      dockerd/dockerd.go
  4. 12 8
      lxc_template.go
  5. 29 0
      sysinit.go
  6. 15 0
      utils.go

+ 9 - 0
container.go

@@ -16,6 +16,12 @@ import (
 	"time"
 )
 
+var sysInitPath string
+
+func init() {
+	sysInitPath = SelfPath()
+}
+
 type Container struct {
 	Id   string
 	Root string
@@ -29,6 +35,7 @@ type Container struct {
 	Filesystem *Filesystem
 	State      *State
 
+	SysInitPath   string
 	lxcConfigPath string
 	cmd           *exec.Cmd
 	stdout        *writeBroadcaster
@@ -58,6 +65,7 @@ func createContainer(id string, root string, command string, args []string, laye
 		Filesystem: newFilesystem(path.Join(root, "rootfs"), path.Join(root, "rw"), layers),
 		State:      newState(),
 
+		SysInitPath:   sysInitPath,
 		lxcConfigPath: path.Join(root, "config.lxc"),
 		stdout:        newWriteBroadcaster(),
 		stderr:        newWriteBroadcaster(),
@@ -261,6 +269,7 @@ func (container *Container) Start() error {
 		"-n", container.Id,
 		"-f", container.lxcConfigPath,
 		"--",
+		"/sbin/init",
 		container.Path,
 	}
 	params = append(params, container.Args...)

+ 7 - 0
docker_test.go

@@ -6,6 +6,13 @@ import (
 	"testing"
 )
 
+// Hack to run sys init during unit testing
+func init() {
+	if SelfPath() == "/sbin/init" {
+		SysInit()
+	}
+}
+
 func newTestDocker() (*Docker, error) {
 	root, err := ioutil.TempDir("", "docker-test")
 	if err != nil {

+ 45 - 47
dockerd/dockerd.go

@@ -1,26 +1,26 @@
 package main
 
 import (
-	"github.com/dotcloud/docker"
-	"github.com/dotcloud/docker/rcli"
-	"github.com/dotcloud/docker/image"
-	"github.com/dotcloud/docker/future"
 	"bufio"
+	"bytes"
+	"encoding/json"
 	"errors"
-	"log"
-	"io"
 	"flag"
 	"fmt"
-	"strings"
-	"text/tabwriter"
-	"os"
-	"time"
+	"github.com/dotcloud/docker"
+	"github.com/dotcloud/docker/future"
+	"github.com/dotcloud/docker/image"
+	"github.com/dotcloud/docker/rcli"
+	"io"
+	"log"
 	"net/http"
-	"encoding/json"
-	"bytes"
-	"sync"
 	"net/url"
+	"os"
 	"path"
+	"strings"
+	"sync"
+	"text/tabwriter"
+	"time"
 )
 
 const VERSION = "0.0.1"
@@ -176,7 +176,6 @@ func (srv *Server) CmdWrite(stdin io.ReadCloser, stdout io.Writer, args ...strin
 	return errors.New("No such container: " + name)
 }
 
-
 func (srv *Server) CmdLs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout, "ls", "[OPTIONS] CONTAINER PATH", "List the contents of a container's directory")
 	if err := cmd.Parse(args); err != nil {
@@ -268,7 +267,7 @@ func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string)
 			return errors.New("No such container: " + name)
 		}
 		if err := srv.containers.Destroy(container); err != nil {
-			fmt.Fprintln(stdout, "Error destroying container " + name + ": " + err.Error())
+			fmt.Fprintln(stdout, "Error destroying container "+name+": "+err.Error())
 		}
 	}
 	return nil
@@ -286,7 +285,7 @@ func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string
 			return errors.New("No such container: " + name)
 		}
 		if err := container.Kill(); err != nil {
-			fmt.Fprintln(stdout, "Error killing container " + name + ": " + err.Error())
+			fmt.Fprintln(stdout, "Error killing container "+name+": "+err.Error())
 		}
 	}
 	return nil
@@ -373,7 +372,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
 		nameFilter = cmd.Arg(0)
 	}
 	w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
-	if (!*quiet) {
+	if !*quiet {
 		fmt.Fprintf(w, "NAME\tID\tCREATED\tPARENT\n")
 	}
 	for _, name := range srv.images.Names() {
@@ -390,10 +389,10 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
 					id += "..."
 				}
 				for idx, field := range []string{
-					/* NAME */	name,
-					/* ID */	id,
-					/* CREATED */	future.HumanDuration(time.Now().Sub(img.Created)) + " ago",
-					/* PARENT */	img.Parent,
+					/* NAME */ name,
+					/* ID */ id,
+					/* CREATED */ future.HumanDuration(time.Now().Sub(img.Created)) + " ago",
+					/* PARENT */ img.Parent,
 				} {
 					if idx == 0 {
 						w.Write([]byte(field))
@@ -407,7 +406,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
 			}
 		}
 	}
-	if (!*quiet) {
+	if !*quiet {
 		w.Flush()
 	}
 	return nil
@@ -424,7 +423,7 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
 		return nil
 	}
 	w := tabwriter.NewWriter(stdout, 12, 1, 3, ' ', 0)
-	if (!*quiet) {
+	if !*quiet {
 		fmt.Fprintf(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT\n")
 	}
 	for _, container := range srv.containers.List() {
@@ -437,13 +436,13 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
 			if !*fl_full {
 				command = docker.Trunc(command, 20)
 			}
-			for idx, field := range[]string {
-				/* ID */	container.Id,
-				/* IMAGE */	container.GetUserData("image"),
-				/* COMMAND */	command,
-				/* CREATED */	future.HumanDuration(time.Now().Sub(container.Created)) + " ago",
-				/* STATUS */	container.State.String(),
-				/* COMMENT */	comment,
+			for idx, field := range []string{
+				/* ID */ container.Id,
+				/* IMAGE */ container.GetUserData("image"),
+				/* COMMAND */ command,
+				/* CREATED */ future.HumanDuration(time.Now().Sub(container.Created)) + " ago",
+				/* STATUS */ container.State.String(),
+				/* COMMENT */ comment,
 			} {
 				if idx == 0 {
 					w.Write([]byte(field))
@@ -456,7 +455,7 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
 			stdout.Write([]byte(container.Id + "\n"))
 		}
 	}
-	if (!*quiet) {
+	if !*quiet {
 		w.Flush()
 	}
 	return nil
@@ -475,7 +474,6 @@ func (srv *Server) CmdLayers(stdin io.ReadCloser, stdout io.Writer, args ...stri
 	return nil
 }
 
-
 func (srv *Server) CmdCp(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout,
 		"cp", "[OPTIONS] IMAGE NAME",
@@ -521,7 +519,6 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
 	return errors.New("No such container: " + containerName)
 }
 
-
 func (srv *Server) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout,
 		"tar", "CONTAINER",
@@ -592,7 +589,6 @@ func (srv *Server) CmdReset(stdin io.ReadCloser, stdout io.Writer, args ...strin
 	return nil
 }
 
-
 func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout, "logs", "[OPTIONS] CONTAINER", "Fetch the logs of a container")
 	if err := cmd.Parse(args); err != nil {
@@ -615,7 +611,6 @@ func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string
 	return errors.New("No such container: " + cmd.Arg(0))
 }
 
-
 func (srv *Server) CreateContainer(img *image.Image, tty bool, openStdin bool, comment string, cmd string, args ...string) (*docker.Container, error) {
 	id := future.RandomId()[:8]
 	container, err := srv.containers.Create(id, cmd, args, img.Layers,
@@ -658,7 +653,7 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
 			return err
 		}
 		wg.Add(1)
-		go func() { io.Copy(c_stdin, stdin); wg.Add(-1); }()
+		go func() { io.Copy(c_stdin, stdin); wg.Add(-1) }()
 	}
 	if *fl_o {
 		c_stdout, err := container.StdoutPipe()
@@ -666,7 +661,7 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
 			return err
 		}
 		wg.Add(1)
-		go func() { io.Copy(stdout, c_stdout); wg.Add(-1); }()
+		go func() { io.Copy(stdout, c_stdout); wg.Add(-1) }()
 	}
 	if *fl_e {
 		c_stderr, err := container.StderrPipe()
@@ -674,7 +669,7 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
 			return err
 		}
 		wg.Add(1)
-		go func() { io.Copy(stdout, c_stderr); wg.Add(-1); }()
+		go func() { io.Copy(stdout, c_stderr); wg.Add(-1) }()
 	}
 	wg.Wait()
 	return nil
@@ -690,7 +685,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 		return nil
 	}
 	name := cmd.Arg(0)
-	var cmdline[]string
+	var cmdline []string
 	if len(cmd.Args()) >= 2 {
 		cmdline = cmd.Args()[1:]
 	}
@@ -723,7 +718,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 		if *fl_attach {
 			future.Go(func() error {
 				log.Printf("CmdRun(): start receiving stdin\n")
-				_, err := io.Copy(cmd_stdin, stdin);
+				_, err := io.Copy(cmd_stdin, stdin)
 				log.Printf("CmdRun(): done receiving stdin\n")
 				cmd_stdin.Close()
 				return err
@@ -744,11 +739,11 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 			return err
 		}
 		sending_stdout := future.Go(func() error {
-			_, err := io.Copy(stdout, cmd_stdout);
+			_, err := io.Copy(stdout, cmd_stdout)
 			return err
 		})
 		sending_stderr := future.Go(func() error {
-			_, err := io.Copy(stdout, cmd_stderr);
+			_, err := io.Copy(stdout, cmd_stderr)
 			return err
 		})
 		err_sending_stdout := <-sending_stdout
@@ -770,6 +765,11 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 }
 
 func main() {
+	if docker.SelfPath() == "/sbin/init" {
+		// Running in init mode
+		docker.SysInit()
+		return
+	}
 	future.Seed()
 	flag.Parse()
 	d, err := New()
@@ -800,7 +800,7 @@ func New() (*Server, error) {
 		return nil, err
 	}
 	srv := &Server{
-		images: images,
+		images:     images,
 		containers: containers,
 	}
 	return srv, nil
@@ -845,9 +845,7 @@ func (srv *Server) CmdWeb(stdin io.ReadCloser, stdout io.Writer, args ...string)
 	return nil
 }
 
-
 type Server struct {
-	containers	*docker.Docker
-	images		*image.Store
+	containers *docker.Docker
+	images     *image.Store
 }
-

+ 12 - 8
lxc_template.go

@@ -22,7 +22,8 @@ lxc.utsname = {{.Id}}
 #lxc.network.ipv4 = {ip_address}/{ip_prefix_len}
 
 # root filesystem
-lxc.rootfs = {{.Filesystem.RootFS}}
+{{$ROOTFS := .Filesystem.RootFS}}
+lxc.rootfs = {{$ROOTFS}}
 
 # use a dedicated pts for the container (and limit the number of pseudo terminal
 # available)
@@ -66,15 +67,18 @@ lxc.cgroup.devices.allow = c 10:200 rwm
 
 
 # standard mount point
-lxc.mount.entry = proc {{.Filesystem.RootFS}}/proc proc nosuid,nodev,noexec 0 0
-lxc.mount.entry = sysfs {{.Filesystem.RootFS}}/sys sysfs nosuid,nodev,noexec 0 0
-lxc.mount.entry = devpts {{.Filesystem.RootFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
-#lxc.mount.entry = varrun {{.Filesystem.RootFS}}/var/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0
-#lxc.mount.entry = varlock {{.Filesystem.RootFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
-#lxc.mount.entry = shm {{.Filesystem.RootFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
+lxc.mount.entry = proc {{$ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
+lxc.mount.entry = sysfs {{$ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
+lxc.mount.entry = devpts {{$ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
+#lxc.mount.entry = varrun {{$ROOTFS}}/var/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0
+#lxc.mount.entry = varlock {{$ROOTFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
+#lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
+
+# Inject docker-init
+lxc.mount.entry = {{.SysInitPath}} {{$ROOTFS}}/sbin/init none bind,ro 0 0
 
 # In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
-lxc.mount.entry = /etc/resolv.conf {{.Filesystem.RootFS}}/etc/resolv.conf none bind,ro 0 0
+lxc.mount.entry = /etc/resolv.conf {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
 
 
 # drop linux capabilities (apply mainly to the user root in the container)

+ 29 - 0
sysinit.go

@@ -0,0 +1,29 @@
+package docker
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"syscall"
+)
+
+// Sys Init code
+// This code is run INSIDE the container and is responsible for setting
+// up the environment before running the actual process
+func SysInit() {
+	if len(os.Args) <= 1 {
+		fmt.Println("You should not invoke docker-init manually")
+		os.Exit(1)
+	}
+
+	path, err := exec.LookPath(os.Args[1])
+	if err != nil {
+		log.Printf("Unable to locate %v", os.Args[1])
+		os.Exit(127)
+	}
+
+	if err := syscall.Exec(path, os.Args[1:], os.Environ()); err != nil {
+		panic(err)
+	}
+}

+ 15 - 0
utils.go

@@ -4,7 +4,9 @@ import (
 	"bytes"
 	"container/list"
 	"io"
+	"os"
 	"os/exec"
+	"path/filepath"
 	"sync"
 )
 
@@ -34,6 +36,19 @@ func Tar(path string) (io.Reader, error) {
 	return output, nil
 }
 
+// Figure out the absolute path of our own binary
+func SelfPath() string {
+	path, err := exec.LookPath(os.Args[0])
+	if err != nil {
+		panic(err)
+	}
+	path, err = filepath.Abs(path)
+	if err != nil {
+		panic(err)
+	}
+	return path
+}
+
 type nopWriteCloser struct {
 	io.Writer
 }