From a91b710961b74341543a81b9d16f66d65b1907f1 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 13 May 2013 15:10:26 +0200 Subject: [PATCH 01/93] add sizes in images and containers --- api_params.go | 16 ++++++++++------ api_test.go | 2 +- commands.go | 13 +++++++++---- container.go | 24 ++++++++++++++++++++++++ graph.go | 9 +++++++++ image.go | 24 ++++++++++++++++++++++++ server.go | 5 +++++ utils.go | 23 +++++++++++++++++++++++ 8 files changed, 105 insertions(+), 11 deletions(-) diff --git a/api_params.go b/api_params.go index c7c15585f9..c4942b50e1 100644 --- a/api_params.go +++ b/api_params.go @@ -11,6 +11,8 @@ type ApiImages struct { Tag string `json:",omitempty"` Id string Created int64 `json:",omitempty"` + Size int64 + ParentSize int64 } type ApiInfo struct { @@ -24,12 +26,14 @@ type ApiInfo struct { } type ApiContainers struct { - Id string - Image string `json:",omitempty"` - Command string `json:",omitempty"` - Created int64 `json:",omitempty"` - Status string `json:",omitempty"` - Ports string `json:",omitempty"` + Id string + Image string `json:",omitempty"` + Command string `json:",omitempty"` + Created int64 `json:",omitempty"` + Status string `json:",omitempty"` + Ports string `json:",omitempty"` + SizeRw int64 + SizeRootFs int64 } type ApiSearch struct { diff --git a/api_test.go b/api_test.go index 68e60adc21..2128f3ef35 100644 --- a/api_test.go +++ b/api_test.go @@ -1194,7 +1194,7 @@ func TestDeleteContainers(t *testing.T) { func TestDeleteImages(t *testing.T) { //FIXME: Implement this test - t.Skip("Test not implemented") + t.Log("Test not implemented") } // Mocked types for tests diff --git a/commands.go b/commands.go index dc3f8c4e87..736aee2f7a 100644 --- a/commands.go +++ b/commands.go @@ -728,12 +728,12 @@ func CmdImages(args ...string) error { w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) if !*quiet { - fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED") + fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED\tSIZE") } for _, out := range outs { if !*quiet { - fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\n", out.Repository, out.Tag, out.Id, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0)))) + fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s (virtual %s)\n", out.Repository, out.Tag, out.Id, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), HumanSize(out.Size), HumanSize(out.ParentSize)) } else { fmt.Fprintln(w, out.Id) } @@ -794,12 +794,17 @@ func CmdPs(args ...string) error { } w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) if !*quiet { - fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS") + fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tSIZE") } for _, out := range outs { if !*quiet { - fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", out.Id, out.Image, out.Command, out.Status, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\t", out.Id, out.Image, out.Command, out.Status, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports) + if out.SizeRootFs > 0 { + fmt.Fprintf(w, "%s (virtual %s)\n", HumanSize(out.SizeRw), HumanSize(out.SizeRootFs)) + } else { + fmt.Fprintf(w, "%s\n", HumanSize(out.SizeRw)) + } } else { fmt.Fprintln(w, out.Id) } diff --git a/container.go b/container.go index c49441e5da..8ccdfb2a43 100644 --- a/container.go +++ b/container.go @@ -11,6 +11,7 @@ import ( "os" "os/exec" "path" + "path/filepath" "sort" "strconv" "strings" @@ -879,3 +880,26 @@ func validateId(id string) error { } return nil } + +// GetSize, return real size, virtual size +func (container *Container) GetSize() (int64, int64) { + var sizeRw, sizeRootfs int64 + + filepath.Walk(container.rwPath(), func(path string, fileInfo os.FileInfo, err error) error { + if fileInfo != nil { + sizeRw += fileInfo.Size() + } + return nil + }) + + _, err := os.Stat(container.RootfsPath()) + if err == nil { + filepath.Walk(container.RootfsPath(), func(path string, fileInfo os.FileInfo, err error) error { + if fileInfo != nil { + sizeRootfs += fileInfo.Size() + } + return nil + }) + } + return sizeRw, sizeRootfs +} diff --git a/graph.go b/graph.go index d9b4f5ac5c..b4a0b57504 100644 --- a/graph.go +++ b/graph.go @@ -89,6 +89,15 @@ func (graph *Graph) Get(name string) (*Image, error) { if img.Id != id { return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id) } + if img.Size == 0 { + root, err := img.root() + if err != nil { + return nil, err + } + if err := StoreSize(img, root); err != nil { + return nil, err + } + } img.graph = graph graph.lockSumMap.Lock() defer graph.lockSumMap.Unlock() diff --git a/image.go b/image.go index 413d95673b..76ebdab33d 100644 --- a/image.go +++ b/image.go @@ -12,6 +12,7 @@ import ( "os" "os/exec" "path" + "path/filepath" "strings" "time" ) @@ -27,6 +28,8 @@ type Image struct { Author string `json:"author,omitempty"` Config *Config `json:"config,omitempty"` graph *Graph + Size int64 + ParentSize int64 } func LoadImage(root string) (*Image, error) { @@ -93,6 +96,18 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error { if err := Untar(layerData, layer); err != nil { return err } + + return StoreSize(img, root) +} + +func StoreSize(img *Image, root string) error { + layer := layerPath(root) + + filepath.Walk(layer, func(path string, fileInfo os.FileInfo, err error) error { + img.Size += fileInfo.Size() + return nil + }) + // Store the json ball jsonData, err := json.Marshal(img) if err != nil { @@ -359,3 +374,12 @@ func (img *Image) Checksum() (string, error) { return hash, nil } + +func (img *Image) getVirtualSize(size int64) int64 { + parentImage, err := img.GetParent() + if err != nil || parentImage == nil { + return size + } + size += parentImage.Size + return parentImage.getVirtualSize(size) +} diff --git a/server.go b/server.go index e96497bff3..cb030fcfa0 100644 --- a/server.go +++ b/server.go @@ -164,6 +164,8 @@ func (srv *Server) Images(all, only_ids bool, filter string) ([]ApiImages, error out.Tag = tag out.Id = TruncateId(id) out.Created = image.Created.Unix() + out.Size = image.Size + out.ParentSize = image.getVirtualSize(0) } else { out.Id = image.ShortId() } @@ -179,6 +181,8 @@ func (srv *Server) Images(all, only_ids bool, filter string) ([]ApiImages, error out.Tag = "" out.Id = TruncateId(id) out.Created = image.Created.Unix() + out.Size = image.Size + out.ParentSize = image.getVirtualSize(0) } else { out.Id = image.ShortId() } @@ -280,6 +284,7 @@ func (srv *Server) Containers(all, trunc_cmd, only_ids bool, n int, since, befor c.Created = container.Created.Unix() c.Status = container.State.String() c.Ports = container.NetworkSettings.PortMappingHuman() + c.SizeRw, c.SizeRootFs = container.GetSize() } retContainers = append(retContainers, c) } diff --git a/utils.go b/utils.go index 4b416cd1e6..5daf3a3c3d 100644 --- a/utils.go +++ b/utils.go @@ -16,6 +16,7 @@ import ( "os/signal" "path/filepath" "runtime" + _ "strconv" "strings" "sync" "time" @@ -133,6 +134,28 @@ func HumanDuration(d time.Duration) string { return fmt.Sprintf("%d years", d.Hours()/24/365) } +// HumanSize returns a human-readabla approximation of a size +// (eg. "44K", "17M") +func HumanSize(size int64) string { + i := 0 + var sizef float64 + sizef = float64(size) + units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} + for sizef > 1024.0 { + sizef = sizef / 1024.0 + i++ + } + return fmt.Sprintf("%.*f %s", i, sizef, units[i]) + // sprintf(buf, "%.*f %s", i, size, units[i]); + // if size/1024/1024 > 1000 { + // return strconv.FormatFloat((float64)(size/1024/1024), 'f', 2, 32) + "G" + // } + // if size/1024 > 1024 { + // return strconv.FormatInt(size/1024/1024, 10) + "M" + // } + // return strconv.FormatInt(size/1024, 10) + "K" +} + func Trunc(s string, maxlen int) string { if len(s) <= maxlen { return s From c75942c79da708a350c4a9cf32a5f06f8ca1ab7c Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 15 May 2013 02:41:19 +0200 Subject: [PATCH 02/93] add 4243 port forward --- Vagrantfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Vagrantfile b/Vagrantfile index 3d568266af..f5fca10f45 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,6 +10,7 @@ Vagrant::Config.run do |config| # Setup virtual machine box. This VM configuration code is always executed. config.vm.box = BOX_NAME config.vm.box_url = BOX_URI + config.vm.forward_port 4243, 4243 # Provision docker and new kernel if deployment was not done if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty? From 4489005cb2f11fe6e2dcdb181b4834791de3b73f Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Tue, 21 May 2013 12:53:05 +0000 Subject: [PATCH 03/93] add regexp check on repo's name --- commands.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commands.go b/commands.go index 5e459a1d94..98e665cd40 100644 --- a/commands.go +++ b/commands.go @@ -17,6 +17,7 @@ import ( "os" "path/filepath" "reflect" + "regexp" "strconv" "strings" "text/tabwriter" @@ -641,6 +642,10 @@ func (cli *DockerCli) CmdPush(args ...string) error { if len(strings.SplitN(name, "/", 2)) == 1 { return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", out.Username, name) } + validRepo := regexp.MustCompile(`^([a-z0-9]{4,30})/([a-z0-9-.]+)$`) + if !validRepo.MatchString(name) { + return fmt.Errorf("Invalid repository name, only alphanum, - and . are allowed") + } v := url.Values{} v.Set("registry", *registry) From ed56b6a905d5e9f443cb0c5c949965f848abbe8d Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 23 May 2013 09:35:20 +0000 Subject: [PATCH 04/93] fix typo --- utils/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/utils.go b/utils/utils.go index ec189cb002..360e4ec31b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -132,7 +132,7 @@ func HumanDuration(d time.Duration) string { return fmt.Sprintf("%d years", d.Hours()/24/365) } -// HumanSize returns a human-readabla approximation of a size +// HumanSize returns a human-readable approximation of a size // (eg. "44kB", "17MB") func HumanSize(size int64) string { i := 0 From b45143da9b275b5003c23667b0988ad93f383b11 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Thu, 23 May 2013 10:29:09 +0000 Subject: [PATCH 05/93] switch to SI standard and add test --- utils/utils.go | 9 ++++----- utils/utils_test.go | 13 +++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index 360e4ec31b..170d34dd7a 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -133,20 +133,19 @@ func HumanDuration(d time.Duration) string { } // HumanSize returns a human-readable approximation of a size -// (eg. "44kB", "17MB") +// using SI standard (eg. "44kB", "17MB") func HumanSize(size int64) string { i := 0 var sizef float64 sizef = float64(size) units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"} - for sizef > 1024.0 { - sizef = sizef / 1024.0 + for sizef >= 1000.0 { + sizef = sizef / 1000.0 i++ } - return fmt.Sprintf("%.*f %s", i, sizef, units[i]) + return fmt.Sprintf("%.4g %s", sizef, units[i]) } - func Trunc(s string, maxlen int) string { if len(s) <= maxlen { return s diff --git a/utils/utils_test.go b/utils/utils_test.go index 4413f44efc..eec06d5134 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -261,3 +261,16 @@ func TestCompareKernelVersion(t *testing.T) { &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"}, -1) } + +func TestHumanSize(t *testing.T) { + + size1000 := HumanSize(1000) + if size1000 != "1 kB" { + t.Errorf("1000 -> expected 1 kB, got %s", size1000) + } + + size1024 := HumanSize(1024) + if size1024 != "1.024 kB" { + t.Errorf("1024 -> expected 1.024 kB, got %s", size1024) + } +} From 1c946ef0038a27d134f497ed72352136c0a4bb9e Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 24 May 2013 13:03:09 +0000 Subject: [PATCH 06/93] fix: Can't lookup root of unregistered image --- graph.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph.go b/graph.go index 85a33a32a5..86c12b8f8b 100644 --- a/graph.go +++ b/graph.go @@ -89,6 +89,7 @@ func (graph *Graph) Get(name string) (*Image, error) { if img.Id != id { return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id) } + img.graph = graph if img.Size == 0 { root, err := img.root() if err != nil { @@ -98,7 +99,6 @@ func (graph *Graph) Get(name string) (*Image, error) { return nil, err } } - img.graph = graph graph.lockSumMap.Lock() defer graph.lockSumMap.Unlock() if _, exists := graph.checksumLock[img.Id]; !exists { From a55a0d370dfca169e0220a01c292c7d41ad0b557 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 3 Jun 2013 14:23:57 +0000 Subject: [PATCH 07/93] ([a-z0-9_]{4,30})/([a-zA-Z0-9-_.]+) --- commands.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/commands.go b/commands.go index 98e665cd40..1ab713ce5d 100644 --- a/commands.go +++ b/commands.go @@ -642,9 +642,14 @@ func (cli *DockerCli) CmdPush(args ...string) error { if len(strings.SplitN(name, "/", 2)) == 1 { return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", out.Username, name) } - validRepo := regexp.MustCompile(`^([a-z0-9]{4,30})/([a-z0-9-.]+)$`) - if !validRepo.MatchString(name) { - return fmt.Errorf("Invalid repository name, only alphanum, - and . are allowed") + nameParts := strings.SplitN(name, "/", 2) + validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`) + if !validNamespace.MatchString(nameParts[0]) { + return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", nameParts[0]) + } + validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`) + if !validRepo.MatchString(nameParts[1]) { + return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", nameParts[1]) } v := url.Values{} From 84d68007cb36b68e1b5c574a0d23fcf583e0d75c Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Wed, 5 Jun 2013 14:20:19 -0700 Subject: [PATCH 08/93] Add -dns to docker daemon --- builder.go | 12 ++++++++++-- docker/docker.go | 11 ++++++++--- runtime.go | 4 +++- server.go | 4 ++-- utils/utils.go | 14 +++++++------- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/builder.go b/builder.go index 808b7efcab..c43f8249fa 100644 --- a/builder.go +++ b/builder.go @@ -7,6 +7,8 @@ import ( "time" ) +var defaultDns = []string{"8.8.8.8", "8.8.4.4"} + type Builder struct { runtime *Runtime repositories *TagStore @@ -67,14 +69,20 @@ func (builder *Builder) Create(config *Config) (*Container, error) { } // If custom dns exists, then create a resolv.conf for the container - if len(config.Dns) > 0 { + if len(config.Dns) > 0 || len(builder.runtime.Dns) > 0 { + var dns []string + if len(config.Dns) > 0 { + dns = config.Dns + } else { + dns = builder.runtime.Dns + } container.ResolvConfPath = path.Join(container.root, "resolv.conf") f, err := os.Create(container.ResolvConfPath) if err != nil { return nil, err } defer f.Close() - for _, dns := range config.Dns { + for _, dns := range dns { if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil { return nil, err } diff --git a/docker/docker.go b/docker/docker.go index dada16e11e..5ddae40c41 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -33,6 +33,11 @@ func main() { bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge") pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to") + + flags := flag.NewFlagSet("docker", flag.ContinueOnError) + var flDns docker.ListOpts + flags.Var(&flDns, "dns", "Set custom dns servers") + flag.Parse() if *bridgeName != "" { docker.NetworkBridgeIface = *bridgeName @@ -65,7 +70,7 @@ func main() { flag.Usage() return } - if err := daemon(*pidfile, host, port, *flAutoRestart); err != nil { + if err := daemon(*pidfile, host, port, *flAutoRestart, flDns); err != nil { log.Fatal(err) os.Exit(-1) } @@ -104,7 +109,7 @@ func removePidFile(pidfile string) { } } -func daemon(pidfile, addr string, port int, autoRestart bool) error { +func daemon(pidfile, addr string, port int, autoRestart bool, flDns docker.ListOpts) error { if addr != "127.0.0.1" { log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") } @@ -122,7 +127,7 @@ func daemon(pidfile, addr string, port int, autoRestart bool) error { os.Exit(0) }() - server, err := docker.NewServer(autoRestart) + server, err := docker.NewServer(autoRestart, flDns) if err != nil { return err } diff --git a/runtime.go b/runtime.go index 1c22bd085c..c37e292d22 100644 --- a/runtime.go +++ b/runtime.go @@ -32,6 +32,7 @@ type Runtime struct { autoRestart bool volumes *Graph srv *Server + Dns []string } var sysInitPath string @@ -245,11 +246,12 @@ func (runtime *Runtime) UpdateCapabilities(quiet bool) { } // FIXME: harmonize with NewGraph() -func NewRuntime(autoRestart bool) (*Runtime, error) { +func NewRuntime(autoRestart bool, dns []string) (*Runtime, error) { runtime, err := NewRuntimeFromDirectory("/var/lib/docker", autoRestart) if err != nil { return nil, err } + runtime.Dns = dns if k, err := utils.GetKernelVersion(); err != nil { log.Printf("WARNING: %s\n", err) diff --git a/server.go b/server.go index 6666123658..31b6f6dfb4 100644 --- a/server.go +++ b/server.go @@ -869,11 +869,11 @@ func (srv *Server) ImageInspect(name string) (*Image, error) { return nil, fmt.Errorf("No such image: %s", name) } -func NewServer(autoRestart bool) (*Server, error) { +func NewServer(autoRestart bool, dns ListOpts) (*Server, error) { if runtime.GOARCH != "amd64" { log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) } - runtime, err := NewRuntime(autoRestart) + runtime, err := NewRuntime(autoRestart, dns) if err != nil { return nil, err } diff --git a/utils/utils.go b/utils/utils.go index c3f9e571d3..d91370c44a 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -70,7 +70,7 @@ type progressReader struct { readProgress int // How much has been read so far (bytes) lastUpdate int // How many bytes read at least update template string // Template to print. Default "%v/%v (%v)" - sf *StreamFormatter + sf *StreamFormatter } func (r *progressReader) Read(p []byte) (n int, err error) { @@ -103,7 +103,7 @@ func (r *progressReader) Close() error { return io.ReadCloser(r.reader).Close() } func ProgressReader(r io.ReadCloser, size int, output io.Writer, template []byte, sf *StreamFormatter) *progressReader { - tpl := string(template) + tpl := string(template) if tpl == "" { tpl = string(sf.FormatProgress("", "%v/%v (%v)")) } @@ -585,7 +585,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte sf.used = true str := fmt.Sprintf(format, a...) if sf.json { - b, err := json.Marshal(&JSONMessage{Status:str}); + b, err := json.Marshal(&JSONMessage{Status: str}) if err != nil { return sf.FormatError(err) } @@ -597,7 +597,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte func (sf *StreamFormatter) FormatError(err error) []byte { sf.used = true if sf.json { - if b, err := json.Marshal(&JSONMessage{Error:err.Error()}); err == nil { + if b, err := json.Marshal(&JSONMessage{Error: err.Error()}); err == nil { return b } return []byte("{\"error\":\"format error\"}") @@ -608,10 +608,10 @@ func (sf *StreamFormatter) FormatError(err error) []byte { func (sf *StreamFormatter) FormatProgress(action, str string) []byte { sf.used = true if sf.json { - b, err := json.Marshal(&JSONMessage{Status: action, Progress:str}) + b, err := json.Marshal(&JSONMessage{Status: action, Progress: str}) if err != nil { - return nil - } + return nil + } return b } return []byte(action + " " + str + "\r") From a3f6054f974909458c9e820842310987e225b767 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 6 Jun 2013 11:01:09 -0700 Subject: [PATCH 09/93] Check for local dns server and output a warning --- api.go | 13 ++++++++++--- builder.go | 6 ++++++ utils/utils.go | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/api.go b/api.go index 5a9bdbbe23..273a0edc3f 100644 --- a/api.go +++ b/api.go @@ -413,17 +413,23 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { config := &Config{} + out := &APIRun{} + if err := json.NewDecoder(r.Body).Decode(config); err != nil { return err } + + if len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns() { + out.Warnings = append(out.Warnings, fmt.Sprintf("WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns)) + config.Dns = defaultDns + } + id, err := srv.ContainerCreate(config) if err != nil { return err } + out.ID = id - out := &APIRun{ - ID: id, - } if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit { log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.") out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.") @@ -432,6 +438,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.") out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.") } + b, err := json.Marshal(out) if err != nil { return err diff --git a/builder.go b/builder.go index c43f8249fa..02c51fb557 100644 --- a/builder.go +++ b/builder.go @@ -2,6 +2,7 @@ package docker import ( "fmt" + "github.com/dotcloud/docker/utils" "os" "path" "time" @@ -68,6 +69,11 @@ func (builder *Builder) Create(config *Config) (*Container, error) { return nil, err } + if len(config.Dns) == 0 && len(builder.runtime.Dns) == 0 && utils.CheckLocalDns() { + //"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns + builder.runtime.Dns = defaultDns + } + // If custom dns exists, then create a resolv.conf for the container if len(config.Dns) > 0 || len(builder.runtime.Dns) > 0 { var dns []string diff --git a/utils/utils.go b/utils/utils.go index d91370c44a..1c4c62eaa3 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -620,3 +620,20 @@ func (sf *StreamFormatter) FormatProgress(action, str string) []byte { func (sf *StreamFormatter) Used() bool { return sf.used } + +func CheckLocalDns() bool { + resolv, err := ioutil.ReadFile("/etc/resolv.conf") + if err != nil { + Debugf("Error openning resolv.conf: %s", err) + return false + } + for _, ip := range []string{ + "127.0.0.1", + "127.0.1.1", + } { + if strings.Contains(string(resolv), ip) { + return true + } + } + return false +} From afd325a8845ad7c4846747fb9561df12ebf9963a Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 6 Jun 2013 11:01:29 -0700 Subject: [PATCH 10/93] Solve an issue with the -dns in daemon mode --- docker/docker.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docker/docker.go b/docker/docker.go index 5ddae40c41..ac7bb06823 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -33,10 +33,7 @@ func main() { bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge") pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to") - - flags := flag.NewFlagSet("docker", flag.ContinueOnError) - var flDns docker.ListOpts - flags.Var(&flDns, "dns", "Set custom dns servers") + flDns := flag.String("dns", "", "Set custom dns servers") flag.Parse() if *bridgeName != "" { @@ -70,7 +67,7 @@ func main() { flag.Usage() return } - if err := daemon(*pidfile, host, port, *flAutoRestart, flDns); err != nil { + if err := daemon(*pidfile, host, port, *flAutoRestart, *flDns); err != nil { log.Fatal(err) os.Exit(-1) } @@ -109,7 +106,7 @@ func removePidFile(pidfile string) { } } -func daemon(pidfile, addr string, port int, autoRestart bool, flDns docker.ListOpts) error { +func daemon(pidfile, addr string, port int, autoRestart bool, flDns string) error { if addr != "127.0.0.1" { log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") } @@ -126,8 +123,11 @@ func daemon(pidfile, addr string, port int, autoRestart bool, flDns docker.ListO removePidFile(pidfile) os.Exit(0) }() - - server, err := docker.NewServer(autoRestart, flDns) + var dns []string + if flDns != "" { + dns = []string{flDns} + } + server, err := docker.NewServer(autoRestart, dns) if err != nil { return err } From f355d33b5fe37ce7c0c25373255ea8afd931f4e7 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 6 Jun 2013 18:16:16 -0700 Subject: [PATCH 11/93] Make the progressbar take the image size into consideration --- registry/registry.go | 30 ++++++++++++++++++------------ server.go | 6 +++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index bd5c6b79c6..a2b43eeda1 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -12,6 +12,7 @@ import ( "io/ioutil" "net/http" "net/url" + "strconv" "strings" ) @@ -106,40 +107,45 @@ func (r *Registry) getImagesInRepository(repository string, authConfig *auth.Aut } // Retrieve an image from the Registry. -// Returns the Image object as well as the layer as an Archive (io.Reader) -func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([]byte, error) { +func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([]byte, int, error) { // Get the JSON req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil) if err != nil { - return nil, fmt.Errorf("Failed to download json: %s", err) + return nil, -1, fmt.Errorf("Failed to download json: %s", err) } req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) res, err := r.client.Do(req) if err != nil { - return nil, fmt.Errorf("Failed to download json: %s", err) + return nil, -1, fmt.Errorf("Failed to download json: %s", err) } defer res.Body.Close() if res.StatusCode != 200 { - return nil, fmt.Errorf("HTTP code %d", res.StatusCode) + return nil, -1, fmt.Errorf("HTTP code %d", res.StatusCode) } + + imageSize, err := strconv.Atoi(res.Header.Get("X-Docker-Size")) + if err != nil { + return nil, -1, err + } + jsonString, err := ioutil.ReadAll(res.Body) if err != nil { - return nil, fmt.Errorf("Failed to parse downloaded json: %s (%s)", err, jsonString) + return nil, -1, fmt.Errorf("Failed to parse downloaded json: %s (%s)", err, jsonString) } - return jsonString, nil + return jsonString, imageSize, nil } -func (r *Registry) GetRemoteImageLayer(imgId, registry string, token []string) (io.ReadCloser, int, error) { +func (r *Registry) GetRemoteImageLayer(imgId, registry string, token []string) (io.ReadCloser, error) { req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/layer", nil) if err != nil { - return nil, -1, fmt.Errorf("Error while getting from the server: %s\n", err) + return nil, fmt.Errorf("Error while getting from the server: %s\n", err) } req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) res, err := r.client.Do(req) if err != nil { - return nil, -1, err + return nil, err } - return res.Body, int(res.ContentLength), nil + return res.Body, nil } func (r *Registry) GetRemoteTags(registries []string, repository string, token []string) (map[string]string, error) { @@ -479,7 +485,7 @@ func NewRegistry(root string) *Registry { httpTransport := &http.Transport{ DisableKeepAlives: true, - Proxy: http.ProxyFromEnvironment, + Proxy: http.ProxyFromEnvironment, } r := &Registry{ diff --git a/server.go b/server.go index 6666123658..37a053abbb 100644 --- a/server.go +++ b/server.go @@ -305,7 +305,7 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin for _, id := range history { if !srv.runtime.graph.Exists(id) { out.Write(sf.FormatStatus("Pulling %s metadata", id)) - imgJSON, err := r.GetRemoteImageJSON(id, endpoint, token) + imgJSON, imgSize, err := r.GetRemoteImageJSON(id, endpoint, token) if err != nil { // FIXME: Keep goging in case of error? return err @@ -317,12 +317,12 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin // Get the layer out.Write(sf.FormatStatus("Pulling %s fs layer", id)) - layer, contentLength, err := r.GetRemoteImageLayer(img.ID, endpoint, token) + layer, err := r.GetRemoteImageLayer(img.ID, endpoint, token) if err != nil { return err } defer layer.Close() - if err := srv.runtime.graph.Register(utils.ProgressReader(layer, contentLength, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil { + if err := srv.runtime.graph.Register(utils.ProgressReader(layer, imgSize, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil { return err } } From 1e0738f63f55d489d3d96274f312c93cc5d69ffa Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 6 Jun 2013 18:42:52 -0700 Subject: [PATCH 12/93] Make the progressbar human readable --- utils/utils.go | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index c3f9e571d3..b92b30633c 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -70,7 +70,7 @@ type progressReader struct { readProgress int // How much has been read so far (bytes) lastUpdate int // How many bytes read at least update template string // Template to print. Default "%v/%v (%v)" - sf *StreamFormatter + sf *StreamFormatter } func (r *progressReader) Read(p []byte) (n int, err error) { @@ -86,7 +86,7 @@ func (r *progressReader) Read(p []byte) (n int, err error) { } if r.readProgress-r.lastUpdate > updateEvery || err != nil { if r.readTotal > 0 { - fmt.Fprintf(r.output, r.template, r.readProgress, r.readTotal, fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100)) + fmt.Fprintf(r.output, r.template, HumanSize(r.readProgress), HumanSize(r.readTotal), fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100)) } else { fmt.Fprintf(r.output, r.template, r.readProgress, "?", "n/a") } @@ -103,13 +103,25 @@ func (r *progressReader) Close() error { return io.ReadCloser(r.reader).Close() } func ProgressReader(r io.ReadCloser, size int, output io.Writer, template []byte, sf *StreamFormatter) *progressReader { - tpl := string(template) + tpl := string(template) if tpl == "" { tpl = string(sf.FormatProgress("", "%v/%v (%v)")) } return &progressReader{r, NewWriteFlusher(output), size, 0, 0, tpl, sf} } +func HumanSize(origSize int) string { + size := float64(origSize) + for _, unit := range []string{"b", "Kb", "Mb", "Gb", "Tb"} { + if int(size)/1024 == 0 { + return fmt.Sprintf("%.03f%s", size, unit) + } else { + size = size / 1024 + } + } + return strconv.Itoa(origSize) +} + // HumanDuration returns a human-readable approximation of a duration // (eg. "About a minute", "4 hours ago", etc.) func HumanDuration(d time.Duration) string { @@ -585,7 +597,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte sf.used = true str := fmt.Sprintf(format, a...) if sf.json { - b, err := json.Marshal(&JSONMessage{Status:str}); + b, err := json.Marshal(&JSONMessage{Status: str}) if err != nil { return sf.FormatError(err) } @@ -597,7 +609,7 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte func (sf *StreamFormatter) FormatError(err error) []byte { sf.used = true if sf.json { - if b, err := json.Marshal(&JSONMessage{Error:err.Error()}); err == nil { + if b, err := json.Marshal(&JSONMessage{Error: err.Error()}); err == nil { return b } return []byte("{\"error\":\"format error\"}") @@ -608,10 +620,10 @@ func (sf *StreamFormatter) FormatError(err error) []byte { func (sf *StreamFormatter) FormatProgress(action, str string) []byte { sf.used = true if sf.json { - b, err := json.Marshal(&JSONMessage{Status: action, Progress:str}) + b, err := json.Marshal(&JSONMessage{Status: action, Progress: str}) if err != nil { - return nil - } + return nil + } return b } return []byte(action + " " + str + "\r") From 302660e362ba36f9966b9a70b7d7284b94afb89d Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 7 Jun 2013 15:56:39 -0400 Subject: [PATCH 13/93] Add an option to forward all ports to the vagrant host that have been exported from docker containers --- Vagrantfile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Vagrantfile b/Vagrantfile index 3d568266af..1688bd5211 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -5,6 +5,7 @@ BOX_NAME = ENV['BOX_NAME'] || "ubuntu" BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64.box" AWS_REGION = ENV['AWS_REGION'] || "us-east-1" AWS_AMI = ENV['AWS_AMI'] || "ami-d0f89fb9" +FORWARD_DOCKER_PORTS = ENV['FORWARD_DOCKER_PORTS'] Vagrant::Config.run do |config| # Setup virtual machine box. This VM configuration code is always executed. @@ -70,3 +71,17 @@ Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config| config.vm.box_url = BOX_URI end end + +if !FORWARD_DOCKER_PORTS.nil? + Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config| + (49000..49900).each do |port| + config.vm.forward_port port, port + end + end + + Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config| + (49000..49900).each do |port| + config.vm.network :forwarded_port, :host => port, :guest => port + end + end +end From db3242e4bb1c31a7319e6273235a9ba6b29a61d4 Mon Sep 17 00:00:00 2001 From: shin- Date: Mon, 10 Jun 2013 11:21:56 -0700 Subject: [PATCH 14/93] Send X-Docker-Endpoints header when validating the images upload with the index at the end of a push --- registry/registry.go | 9 +++++++-- server.go | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index bd5c6b79c6..0ae37f7a9d 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -328,7 +328,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token return nil } -func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) { +func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) { imgListJSON, err := json.Marshal(imgList) if err != nil { return nil, err @@ -347,6 +347,9 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password) req.ContentLength = int64(len(imgListJSON)) req.Header.Set("X-Docker-Token", "true") + if validate { + req.Header["X-Docker-Endpoints"] = regs + } res, err := r.client.Do(req) if err != nil { @@ -364,7 +367,9 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password) req.ContentLength = int64(len(imgListJSON)) req.Header.Set("X-Docker-Token", "true") - + if validate { + req.Header["X-Docker-Endpoints"] = regs + } res, err = r.client.Do(req) if err != nil { return nil, err diff --git a/server.go b/server.go index 6666123658..7cac30ae35 100644 --- a/server.go +++ b/server.go @@ -489,7 +489,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri } out.Write(sf.FormatStatus("Sending image list")) - repoData, err := r.PushImageJSONIndex(name, imgList, false) + repoData, err := r.PushImageJSONIndex(name, imgList, false, nil) if err != nil { return err } @@ -513,7 +513,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri } } - if _, err := r.PushImageJSONIndex(name, imgList, true); err != nil { + if _, err := r.PushImageJSONIndex(name, imgList, true, repoData.Endpoints); err != nil { return err } return nil From 0425f65e6373dc38cd18a6d0f2a50671544ad4b2 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Thu, 13 Jun 2013 17:53:38 -0700 Subject: [PATCH 15/93] Remove bsdtar by checking magic --- archive.go | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/archive.go b/archive.go index 06466627a1..5686408179 100644 --- a/archive.go +++ b/archive.go @@ -1,8 +1,10 @@ package docker import ( + "bytes" "errors" "fmt" + "github.com/dotcloud/docker/utils" "io" "io/ioutil" "os" @@ -20,6 +22,37 @@ const ( Xz ) +func DetectCompression(source []byte) Compression { + for _, c := range source[:10] { + utils.Debugf("%x", c) + } + + sourceLen := len(source) + for compression, m := range map[Compression][]byte{ + Bzip2: {0x42, 0x5A, 0x68}, + Gzip: {0x1F, 0x8B, 0x08}, + Xz: {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, + } { + fail := false + if len(m) > sourceLen { + utils.Debugf("Len too short") + continue + } + i := 0 + for _, b := range m { + if b != source[i] { + fail = true + break + } + i++ + } + if !fail { + return compression + } + } + return Uncompressed +} + func (compression *Compression) Flag() string { switch *compression { case Bzip2: @@ -47,12 +80,21 @@ func (compression *Compression) Extension() string { } func Tar(path string, compression Compression) (io.Reader, error) { - cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-c"+compression.Flag(), ".") - return CmdStream(cmd) + return CmdStream(exec.Command("tar", "-f", "-", "-C", path, "-c"+compression.Flag(), ".")) } func Untar(archive io.Reader, path string) error { - cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x") + + buf := make([]byte, 10) + if _, err := archive.Read(buf); err != nil { + return err + } + compression := DetectCompression(buf) + archive = io.MultiReader(bytes.NewReader(buf), archive) + + utils.Debugf("Archive compression detected: %s", compression.Extension()) + + cmd := exec.Command("tar", "-f", "-", "-C", path, "-x"+compression.Flag()) cmd.Stdin = archive // Hardcode locale environment for predictable outcome regardless of host configuration. // (see https://github.com/dotcloud/docker/issues/355) From 3384943cd3bc5bb9fd79ccbda9d32a582ada69b3 Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Thu, 13 Jun 2013 22:14:29 -0700 Subject: [PATCH 16/93] Packaging, dockerbuilder: Automate pushing docker binary packages --- Makefile | 2 ++ hack/dockerbuilder/Dockerfile | 1 - hack/dockerbuilder/dockerbuilder | 13 +++++++------ hack/dockerbuilder/s3cfg | 3 --- 4 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 hack/dockerbuilder/s3cfg diff --git a/Makefile b/Makefile index 9527d3f750..eca409c967 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,7 @@ whichrelease: release: $(BINRELEASE) s3cmd -P put $(BINRELEASE) s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-$(RELEASE_VERSION).tgz + s3cmd -P put docker-latest.tgz s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-latest.tgz srcrelease: $(SRCRELEASE) deps: $(DOCKER_DIR) @@ -60,6 +61,7 @@ $(SRCRELEASE): $(BINRELEASE): $(SRCRELEASE) rm -f $(BINRELEASE) cd $(SRCRELEASE); make; cp -R bin docker-$(RELEASE_VERSION); tar -f ../$(BINRELEASE) -zv -c docker-$(RELEASE_VERSION) + cd $(SRCRELEASE); cp -R bin docker-latest; tar -f ../docker-latest.tgz -zv -c docker-latest clean: @rm -rf $(dir $(DOCKER_BIN)) diff --git a/hack/dockerbuilder/Dockerfile b/hack/dockerbuilder/Dockerfile index 5b2504d378..50993ed7b5 100644 --- a/hack/dockerbuilder/Dockerfile +++ b/hack/dockerbuilder/Dockerfile @@ -27,5 +27,4 @@ run apt-get install -y -q devscripts # Copy dockerbuilder files into the container add . /src run cp /src/dockerbuilder /usr/local/bin/ && chmod +x /usr/local/bin/dockerbuilder -run cp /src/s3cfg /.s3cfg cmd ["dockerbuilder"] diff --git a/hack/dockerbuilder/dockerbuilder b/hack/dockerbuilder/dockerbuilder index d2e4396550..9fa05ce11e 100644 --- a/hack/dockerbuilder/dockerbuilder +++ b/hack/dockerbuilder/dockerbuilder @@ -13,12 +13,10 @@ fi export REVISION=$1 -if [ -z "$AWS_ID" ]; then - echo "Warning: environment variable AWS_ID is not set. Won't upload to S3." -fi - -if [ -z "$AWS_KEY" ]; then - echo "Warning: environment variable AWS_KEY is not set. Won't upload to S3." +if [ -z "$AWS_ID" -o -z "$AWS_KEY" ]; then + echo "Warning: either AWS_ID or AWS_KEY environment variable not set. Won't upload to S3." +else + /bin/echo -e "[default]\naccess_key = $AWS_ID\nsecret_key = $AWS_KEY\n" > /.s3cfg fi if [ -z "$GPG_KEY" ]; then @@ -35,6 +33,9 @@ else make release RELEASE_VERSION=$REVISION fi +# Remove credentials from container +rm -f /.s3cfg + if [ -z "$NO_UBUNTU" ]; then export PATH=`echo $PATH | sed 's#/usr/local/go/bin:##g'` (cd packaging/ubuntu && make ubuntu) diff --git a/hack/dockerbuilder/s3cfg b/hack/dockerbuilder/s3cfg deleted file mode 100644 index 963af7d365..0000000000 --- a/hack/dockerbuilder/s3cfg +++ /dev/null @@ -1,3 +0,0 @@ -[default] -access_key = $AWS_ID -secret_key = $AWS_KEY From 00cf2a1fa264c167dff0dd50e296c93d4c59908f Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 14 Jun 2013 10:05:01 +0000 Subject: [PATCH 17/93] fix virtual size on images --- api_params.go | 23 +++++++++++------------ commands.go | 4 ++-- image.go | 5 ++--- server.go | 4 ++-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/api_params.go b/api_params.go index 96a731c98f..9a689a04c3 100644 --- a/api_params.go +++ b/api_params.go @@ -7,13 +7,12 @@ type APIHistory struct { } type APIImages struct { - Repository string `json:",omitempty"` - Tag string `json:",omitempty"` - ID string `json:"Id"` - Created int64 - Size int64 - ParentSize int64 - + Repository string `json:",omitempty"` + Tag string `json:",omitempty"` + ID string `json:"Id"` + Created int64 + Size int64 + VirtualSize int64 } type APIInfo struct { @@ -28,11 +27,11 @@ type APIInfo struct { type APIContainers struct { ID string `json:"Id"` - Image string - Command string - Created int64 - Status string - Ports string + Image string + Command string + Created int64 + Status string + Ports string SizeRw int64 SizeRootFs int64 } diff --git a/commands.go b/commands.go index 1278892117..326a436ce2 100644 --- a/commands.go +++ b/commands.go @@ -812,8 +812,8 @@ func (cli *DockerCli) CmdImages(args ...string) error { fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID)) } fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0)))) - if out.ParentSize > 0 { - fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.Size), utils.HumanSize(out.ParentSize)) + if out.VirtualSize > 0 { + fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.Size), utils.HumanSize(out.VirtualSize)) } else { fmt.Fprintf(w, "%s\n", utils.HumanSize(out.Size)) } diff --git a/image.go b/image.go index f19667e7ec..8d4c42e733 100644 --- a/image.go +++ b/image.go @@ -31,7 +31,6 @@ type Image struct { Architecture string `json:"architecture,omitempty"` graph *Graph Size int64 - ParentSize int64 } func LoadImage(root string) (*Image, error) { @@ -376,13 +375,13 @@ func (img *Image) Checksum() (string, error) { return hash, nil } -func (img *Image) getVirtualSize(size int64) int64 { +func (img *Image) getParentsSize(size int64) int64 { parentImage, err := img.GetParent() if err != nil || parentImage == nil { return size } size += parentImage.Size - return parentImage.getVirtualSize(size) + return parentImage.getParentsSize(size) } // Build an Image object from raw json data diff --git a/server.go b/server.go index efd2850079..5e1459a861 100644 --- a/server.go +++ b/server.go @@ -177,7 +177,7 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) { out.ID = image.ID out.Created = image.Created.Unix() out.Size = image.Size - out.ParentSize = image.getVirtualSize(0) + out.VirtualSize = image.getParentsSize(0) + image.Size outs = append(outs, out) } } @@ -188,7 +188,7 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) { out.ID = image.ID out.Created = image.Created.Unix() out.Size = image.Size - out.ParentSize = image.getVirtualSize(0) + out.VirtualSize = image.getParentsSize(0) + image.Size outs = append(outs, out) } } From e49f82b9e1a920c902c1cd813596dc1a78817e63 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 14 Jun 2013 10:10:26 +0000 Subject: [PATCH 18/93] update docs --- docs/sources/api/docker_remote_api_v1.2.rst | 31 ++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/sources/api/docker_remote_api_v1.2.rst b/docs/sources/api/docker_remote_api_v1.2.rst index 8354760e2f..fb69168120 100644 --- a/docs/sources/api/docker_remote_api_v1.2.rst +++ b/docs/sources/api/docker_remote_api_v1.2.rst @@ -47,28 +47,40 @@ List containers "Image": "base:latest", "Command": "echo 1", "Created": 1367854155, - "Status": "Exit 0" + "Status": "Exit 0", + "Ports":"", + "SizeRw":12288, + "SizeRootFs":0 }, { "Id": "9cd87474be90", "Image": "base:latest", "Command": "echo 222222", "Created": 1367854155, - "Status": "Exit 0" + "Status": "Exit 0", + "Ports":"", + "SizeRw":12288, + "SizeRootFs":0 }, { "Id": "3176a2479c92", "Image": "base:latest", "Command": "echo 3333333333333333", "Created": 1367854154, - "Status": "Exit 0" + "Status": "Exit 0", + "Ports":"", + "SizeRw":12288, + "SizeRootFs":0 }, { "Id": "4cb07b47f9fb", "Image": "base:latest", "Command": "echo 444444444444444444444444444444444", "Created": 1367854152, - "Status": "Exit 0" + "Status": "Exit 0", + "Ports":"", + "SizeRw":12288, + "SizeRootFs":0 } ] @@ -488,13 +500,17 @@ List Images "Repository":"base", "Tag":"ubuntu-12.10", "Id":"b750fe79269d", - "Created":1364102658 + "Created":1364102658, + "Size":24653, + "VirtualSize":180116135 }, { "Repository":"base", "Tag":"ubuntu-quantal", "Id":"b750fe79269d", - "Created":1364102658 + "Created":1364102658, + "Size":24653, + "VirtualSize":180116135 } ] @@ -643,7 +659,8 @@ Inspect an image "Image":"base", "Volumes":null, "VolumesFrom":"" - } + }, + "Size": 6824592 } :statuscode 200: no error From 9ee11161bf0c635a0b0164ae1dee806c6fcfe7b7 Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 14 Jun 2013 19:46:04 +0300 Subject: [PATCH 19/93] validate memory limits & error out if less than 512 KB --- server.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server.go b/server.go index 34d525a35a..330c9fbb89 100644 --- a/server.go +++ b/server.go @@ -652,6 +652,10 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write func (srv *Server) ContainerCreate(config *Config) (string, error) { + if config.Memory != 0 && config.Memory < 524288 { + return "", fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)") + } + if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit { config.Memory = 0 } From 6f7de49aa8771ef4bc35548f9aa07fee660f1844 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 14 Jun 2013 10:47:49 -0700 Subject: [PATCH 20/93] Add unit tests for tar/untar with multiple compression + detection --- archive_test.go | 51 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/archive_test.go b/archive_test.go index f583604497..bb4235ad5b 100644 --- a/archive_test.go +++ b/archive_test.go @@ -1,10 +1,13 @@ package docker import ( + "bytes" + "fmt" "io" "io/ioutil" "os" "os/exec" + "path" "testing" "time" ) @@ -58,20 +61,58 @@ func TestCmdStreamGood(t *testing.T) { } } -func TestTarUntar(t *testing.T) { - archive, err := Tar(".", Uncompressed) +func tarUntar(t *testing.T, origin string, compression Compression) error { + archive, err := Tar(origin, compression) if err != nil { t.Fatal(err) } + + buf := make([]byte, 10) + if _, err := archive.Read(buf); err != nil { + return err + } + archive = io.MultiReader(bytes.NewReader(buf), archive) + + detectedCompression := DetectCompression(buf) + if detectedCompression.Extension() != compression.Extension() { + return fmt.Errorf("Wrong compression detected. Actual compression: %s, found %s", compression.Extension(), detectedCompression.Extension()) + } + tmp, err := ioutil.TempDir("", "docker-test-untar") if err != nil { - t.Fatal(err) + return err } defer os.RemoveAll(tmp) if err := Untar(archive, tmp); err != nil { - t.Fatal(err) + return err } if _, err := os.Stat(tmp); err != nil { - t.Fatalf("Error stating %s: %s", tmp, err.Error()) + return err + } + return nil +} + +func TestTarUntar(t *testing.T) { + origin, err := ioutil.TempDir("", "docker-test-untar-origin") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(origin) + if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil { + t.Fatal(err) + } + + for _, c := range []Compression{ + Uncompressed, + Gzip, + Bzip2, + Xz, + } { + if err := tarUntar(t, origin, c); err != nil { + t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err) + } } } From 79fe864d9a117193b4dce8b7fe156a55bbadcce6 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 14 Jun 2013 10:58:16 -0700 Subject: [PATCH 21/93] Update docs --- README.md | 2 +- docs/sources/contributing/devenvironment.rst | 2 +- docs/sources/installation/binaries.rst | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1c909e5431..d15ee3cc41 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ Setting up a dev environment Instructions that have been verified to work on Ubuntu 12.10, ```bash -sudo apt-get -y install lxc wget bsdtar curl golang git +sudo apt-get -y install lxc curl xz-utils golang git export GOPATH=~/go/ export PATH=$GOPATH/bin:$PATH diff --git a/docs/sources/contributing/devenvironment.rst b/docs/sources/contributing/devenvironment.rst index 5d937c5a44..8b26688bcf 100644 --- a/docs/sources/contributing/devenvironment.rst +++ b/docs/sources/contributing/devenvironment.rst @@ -33,7 +33,7 @@ Installation sudo apt-get install python-software-properties sudo add-apt-repository ppa:gophers/go sudo apt-get update - sudo apt-get -y install lxc wget bsdtar curl golang-stable git + sudo apt-get -y install lxc xz-utils curl golang-stable git export GOPATH=~/go/ export PATH=$GOPATH/bin:$PATH diff --git a/docs/sources/installation/binaries.rst b/docs/sources/installation/binaries.rst index e7a07b6db1..6d87787752 100644 --- a/docs/sources/installation/binaries.rst +++ b/docs/sources/installation/binaries.rst @@ -30,8 +30,7 @@ Dependencies: * 3.8 Kernel (read more about :ref:`kernel`) * AUFS filesystem support * lxc -* bsdtar - +* xz-utils Get the docker binary: ---------------------- From 2f67a62b5b48862948b1ce92aeffbb83c3707ee0 Mon Sep 17 00:00:00 2001 From: unclejack Date: Tue, 4 Jun 2013 21:30:47 +0300 Subject: [PATCH 22/93] run auplink before unmounting aufs --- mount.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mount.go b/mount.go index bb1a40eddb..541c29c13a 100644 --- a/mount.go +++ b/mount.go @@ -2,13 +2,18 @@ package docker import ( "fmt" + "github.com/dotcloud/docker/utils" "os" + "os/exec" "path/filepath" "syscall" "time" ) func Unmount(target string) error { + if err := exec.Command("auplink", target, "flush").Run(); err != nil { + utils.Debugf("[warning]: couldn't run auplink before unmount: %s", err) + } if err := syscall.Unmount(target, 0); err != nil { return err } From e53721ef69b13365c18c9189145ae1fadb931f01 Mon Sep 17 00:00:00 2001 From: unclejack Date: Tue, 4 Jun 2013 21:35:41 +0300 Subject: [PATCH 23/93] add aufs-tools to lxc-docker dependencies --- packaging/debian/control | 2 +- packaging/ubuntu/control | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/debian/control b/packaging/debian/control index 35a2a28cd1..62a963f59e 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -10,7 +10,7 @@ Homepage: http://github.com/dotcloud/docker Package: lxc-docker Architecture: linux-any -Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, bsdtar +Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, bsdtar, aufs-tools Description: Linux container runtime Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and diff --git a/packaging/ubuntu/control b/packaging/ubuntu/control index b0560ebf70..404f38a16d 100644 --- a/packaging/ubuntu/control +++ b/packaging/ubuntu/control @@ -8,7 +8,7 @@ Homepage: http://github.com/dotcloud/docker Package: lxc-docker Architecture: linux-any -Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar +Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar,aufs-tools Conflicts: docker Description: lxc-docker is a Linux container runtime Docker complements LXC with a high-level API which operates at the process From fb7eaf67d1c01eea28fcbed61d6d8abd8117c965 Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 14 Jun 2013 15:07:43 +0300 Subject: [PATCH 24/93] add aufs-tools package to dev env docs page --- docs/sources/contributing/devenvironment.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/contributing/devenvironment.rst b/docs/sources/contributing/devenvironment.rst index 5d937c5a44..ce2ecd41e8 100644 --- a/docs/sources/contributing/devenvironment.rst +++ b/docs/sources/contributing/devenvironment.rst @@ -33,7 +33,7 @@ Installation sudo apt-get install python-software-properties sudo add-apt-repository ppa:gophers/go sudo apt-get update - sudo apt-get -y install lxc wget bsdtar curl golang-stable git + sudo apt-get -y install lxc wget bsdtar curl golang-stable git aufs-tools export GOPATH=~/go/ export PATH=$GOPATH/bin:$PATH From f1d16ea0035ee45341e5d4a143cdce5798847cb5 Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 14 Jun 2013 15:09:07 +0300 Subject: [PATCH 25/93] install aufs-tools when setting up the hack vagrant box --- hack/Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/Vagrantfile b/hack/Vagrantfile index 250731ef47..318f835f4f 100644 --- a/hack/Vagrantfile +++ b/hack/Vagrantfile @@ -22,7 +22,7 @@ Vagrant::Config.run do |config| pkg_cmd = "touch #{DOCKER_PATH}; " # Install docker dependencies pkg_cmd << "export DEBIAN_FRONTEND=noninteractive; apt-get -qq update; " \ - "apt-get install -q -y lxc bsdtar git golang make linux-image-extra-3.8.0-19-generic; " \ + "apt-get install -q -y lxc bsdtar git aufs-tools golang make linux-image-extra-3.8.0-19-generic; " \ "chown -R #{USER}.#{USER} #{GOPATH}; " \ "install -m 0664 #{CFG_PATH}/bash_profile /home/#{USER}/.bash_profile" config.vm.provision :shell, :inline => pkg_cmd From 822abab17e33a0f87ef1d785a9148d3ea11cbb60 Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 14 Jun 2013 15:13:27 +0300 Subject: [PATCH 26/93] install aufs-tools when setting up the testing vagrant box --- testing/Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/Vagrantfile b/testing/Vagrantfile index 7556b191ac..e304a8d087 100644 --- a/testing/Vagrantfile +++ b/testing/Vagrantfile @@ -30,7 +30,7 @@ Vagrant::Config.run do |config| # Install docker dependencies pkg_cmd << "apt-get install -q -y python-software-properties; " \ "add-apt-repository -y ppa:gophers/go/ubuntu; apt-get update -qq; " \ - "DEBIAN_FRONTEND=noninteractive apt-get install -q -y lxc bsdtar git golang-stable make; " + "DEBIAN_FRONTEND=noninteractive apt-get install -q -y lxc bsdtar git golang-stable aufs-tools make; " # Activate new kernel pkg_cmd << "shutdown -r +1; " config.vm.provision :shell, :inline => pkg_cmd From 7958f1f694ac411dcfeb8fbf0d702a7c552306ae Mon Sep 17 00:00:00 2001 From: Andy Rothfusz Date: Fri, 14 Jun 2013 13:42:59 -0600 Subject: [PATCH 27/93] Add examples for local import. --- docs/sources/commandline/command/import.rst | 29 ++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/sources/commandline/command/import.rst b/docs/sources/commandline/command/import.rst index 34a7138e07..66bcf5de52 100644 --- a/docs/sources/commandline/command/import.rst +++ b/docs/sources/commandline/command/import.rst @@ -8,6 +8,33 @@ :: - Usage: docker import [OPTIONS] URL|- [REPOSITORY [TAG]] + Usage: docker import URL|- [REPOSITORY [TAG]] Create a new filesystem image from the contents of a tarball + +At this time, the URL must start with ``http`` and point to a single file archive (.tar, .tar.gz, .bzip) +containing a root filesystem. If you would like to import from a local directory or archive, +you can use the ``-`` parameter to take the data from standard in. + +Examples +-------- + +Import from a remote location +............................. + +``$ docker import http://example.com/exampleimage.tgz exampleimagerepo`` + +Import from a local file +........................ + +Import to docker via pipe and standard in + +``$ cat exampleimage.tgz | docker import - exampleimagelocal`` + +Import from a local directory +............................. + +``$ sudo tar -c . | docker import - exampleimagedir`` + +Note the ``sudo`` in this example -- you must preserve the ownership of the files (especially root ownership) +during the archiving with tar. If you are not root (or sudo) when you tar, then the ownerships might not get preserved. From d3f83a6592e3d79768d9d3805edec80642b69c4b Mon Sep 17 00:00:00 2001 From: unclejack Date: Fri, 14 Jun 2013 22:55:00 +0300 Subject: [PATCH 28/93] add test: fail to create container if mem limit < 512KB --- server_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/server_test.go b/server_test.go index 532757c61e..7fdec18f61 100644 --- a/server_test.go +++ b/server_test.go @@ -147,3 +147,25 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) { } } + +func TestRunWithTooLowMemoryLimit(t *testing.T) { + runtime, err := newTestRuntime() + srv := &Server{runtime: runtime} + if err != nil { + t.Fatal(err) + } + defer nuke(runtime) + // Try to create a container with a memory limit of 1 byte less than the minimum allowed limit. + _, err = srv.ContainerCreate( + &Config{ + Image: GetTestImage(runtime).ID, + Memory: 524287, + CpuShares: 1000, + Cmd: []string{"/bin/cat"}, + }, + ) + if err == nil { + t.Errorf("Memory limit is smaller than the allowed limit. Container creation should've failed!") + } + +} From 7f118519eb007b2423fff428aceddabd6c1c301d Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 14 Jun 2013 14:46:08 -0700 Subject: [PATCH 29/93] Remove duplicate 'WARNING' --- api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.go b/api.go index d304b49a98..e870ca7723 100644 --- a/api.go +++ b/api.go @@ -441,7 +441,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r } if len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns() { - out.Warnings = append(out.Warnings, fmt.Sprintf("WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns)) + out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns)) config.Dns = defaultDns } From 14265d9a18a4a2151bfd4e5c7e94de45377b6375 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 14 Jun 2013 15:11:34 -0700 Subject: [PATCH 30/93] Various FIXME items --- FIXME | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/FIXME b/FIXME index e252fb2589..0b72feafe8 100644 --- a/FIXME +++ b/FIXME @@ -16,3 +16,13 @@ to put them - so we put them here :) * Unify build commands and regular commands * Move source code into src/ subdir for clarity * Clean up the Makefile, it's a mess +- docker buidl: show short IDs +- docker build: on non-existent local path for ADD, don't show full absolute path on the host +- mount into /dockerinit rather than /sbin/init +- docker tag foo REPO:TAG +- use size header for progress bar in pull +- Clean up context upload in build!!! +- Parallel pull +- Ensure /proc/sys/net/ipv4/ip_forward is 1 +- Force DNS to public! +- Always generate a resolv.conf per container, to avoid changing resolv.conf under thne container's feet From 76a568fc9717ff69999ab54fba9277a0d31c305d Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Fri, 14 Jun 2013 16:08:08 -0700 Subject: [PATCH 31/93] Fix merge issue --- utils/utils.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/utils/utils.go b/utils/utils.go index 4c9f9eeee1..7e95e074d5 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -86,7 +86,7 @@ func (r *progressReader) Read(p []byte) (n int, err error) { } if r.readProgress-r.lastUpdate > updateEvery || err != nil { if r.readTotal > 0 { - fmt.Fprintf(r.output, r.template, HumanSize(r.readProgress), HumanSize(r.readTotal), fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100)) + fmt.Fprintf(r.output, r.template, HumanSize(int64(r.readProgress)), HumanSize(int64(r.readTotal)), fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100)) } else { fmt.Fprintf(r.output, r.template, r.readProgress, "?", "n/a") } @@ -110,18 +110,6 @@ func ProgressReader(r io.ReadCloser, size int, output io.Writer, template []byte return &progressReader{r, NewWriteFlusher(output), size, 0, 0, tpl, sf} } -func HumanSize(origSize int) string { - size := float64(origSize) - for _, unit := range []string{"b", "Kb", "Mb", "Gb", "Tb"} { - if int(size)/1024 == 0 { - return fmt.Sprintf("%.03f%s", size, unit) - } else { - size = size / 1024 - } - } - return strconv.Itoa(origSize) -} - // HumanDuration returns a human-readable approximation of a duration // (eg. "About a minute", "4 hours ago", etc.) func HumanDuration(d time.Duration) string { From 5799806414b266c14a8ea2802cfa0906d920c62d Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 14 Jun 2013 16:29:19 -0700 Subject: [PATCH 32/93] FIXMEs --- FIXME | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FIXME b/FIXME index 0b72feafe8..aaf4c23266 100644 --- a/FIXME +++ b/FIXME @@ -26,3 +26,5 @@ to put them - so we put them here :) - Ensure /proc/sys/net/ipv4/ip_forward is 1 - Force DNS to public! - Always generate a resolv.conf per container, to avoid changing resolv.conf under thne container's feet +- Save metadata with import/export +- Upgrade dockerd without stopping containers From 5b8287617de65d4e14ed6affb0eb46867e9ee617 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 14 Jun 2013 16:43:39 -0700 Subject: [PATCH 33/93] + Builder: ADD of a local file will detect tar archives and unpack them into the container instead of copying them as a regular file. * Builder: ADD uses tar/untar for copies instead of calling 'cp -ar'. This is more consistent, reduces the number of dependencies, and fixe #896. --- archive.go | 25 +++++++++++++++++++++++++ buildfile.go | 16 ++++++---------- buildfile_test.go | 6 ++++++ utils/utils.go | 1 + 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/archive.go b/archive.go index 06466627a1..44fdd56be3 100644 --- a/archive.go +++ b/archive.go @@ -51,6 +51,7 @@ func Tar(path string, compression Compression) (io.Reader, error) { return CmdStream(cmd) } +// FIXME: specify behavior when target path exists vs. doesn't exist. func Untar(archive io.Reader, path string) error { cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x") cmd.Stdin = archive @@ -64,6 +65,30 @@ func Untar(archive io.Reader, path string) error { return nil } +// UntarPath is a convenience function which looks for an archive +// at filesystem path `src`, and unpacks it at `dst`. +func UntarPath(src, dst string) error { + if archive, err := os.Open(src); err != nil { + return err + } else if err := Untar(archive, dst); err != nil { + return err + } + return nil +} + +// CopyWithTar creates a tar archive of filesystem path `src`, and +// unpacks it at filesystem path `dst`. +// The archive is streamed directly with fixed buffering and no +// intermediary disk IO. +// +func CopyWithTar(src, dst string) error { + archive, err := Tar(src, Uncompressed) + if err != nil { + return err + } + return Untar(archive, dst) +} + // CmdStream executes a command, and returns its stdout as a stream. // If the command fails to run or doesn't complete successfully, an error // will be returned, including anything written on stderr. diff --git a/buildfile.go b/buildfile.go index 3c706b04ba..bb4ae721a9 100644 --- a/buildfile.go +++ b/buildfile.go @@ -200,21 +200,17 @@ func (b *buildFile) CmdAdd(args string) error { if err := os.MkdirAll(destPath, 0700); err != nil { return err } - - files, err := ioutil.ReadDir(path.Join(b.context, orig)) - if err != nil { + if err := CopyWithTar(origPath, destPath); err != nil { return err } - for _, fi := range files { - if err := utils.CopyDirectory(path.Join(origPath, fi.Name()), path.Join(destPath, fi.Name())); err != nil { - return err - } - } - } else { + // First try to unpack the source as an archive + } else if err := UntarPath(origPath, destPath); err != nil { + utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err) + // If that fails, just copy it as a regular file if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil { return err } - if err := utils.CopyDirectory(origPath, destPath); err != nil { + if err := CopyWithTar(origPath, destPath); err != nil { return err } } diff --git a/buildfile_test.go b/buildfile_test.go index d9c60a70d5..33e6a3146b 100644 --- a/buildfile_test.go +++ b/buildfile_test.go @@ -23,6 +23,12 @@ from ` + unitTestImageName + ` run sh -c 'echo root:testpass > /tmp/passwd' run mkdir -p /var/run/sshd` +// FIXME: test building with a context + +// FIXME: test building with a local ADD as first command + +// FIXME: test building with 2 successive overlapping ADD commands + func TestBuild(t *testing.T) { dockerfiles := []string{Dockerfile, DockerfileNoNewLine} for _, Dockerfile := range dockerfiles { diff --git a/utils/utils.go b/utils/utils.go index 708c8bb19d..b77c1ea053 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -548,6 +548,7 @@ func GetKernelVersion() (*KernelVersionInfo, error) { }, nil } +// FIXME: this is deprecated by CopyWithTar in archive.go func CopyDirectory(source, dest string) error { if output, err := exec.Command("cp", "-ra", source, dest).CombinedOutput(); err != nil { return fmt.Errorf("Error copy: %s (%s)", err, output) From 080f35fe65a7bb88ccf2abefa985c7a4ae88a47b Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 14 Jun 2013 16:24:22 -0700 Subject: [PATCH 34/93] Fix a bug which caused builds to fail if ADD was the first command --- buildfile.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildfile.go b/buildfile.go index 3c706b04ba..aaa6f6bc7c 100644 --- a/buildfile.go +++ b/buildfile.go @@ -178,6 +178,8 @@ func (b *buildFile) CmdAdd(args string) error { cmd := b.config.Cmd // Create the container and start it + b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)} + b.config.Image = b.image container, err := b.builder.Create(b.config) if err != nil { return err From 6746c385bd7938e1bbcf588a27651de63a2de04a Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Sat, 15 Jun 2013 12:09:10 -0700 Subject: [PATCH 35/93] FIXMEs --- FIXME | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/FIXME b/FIXME index aaf4c23266..b88757e229 100644 --- a/FIXME +++ b/FIXME @@ -16,15 +16,21 @@ to put them - so we put them here :) * Unify build commands and regular commands * Move source code into src/ subdir for clarity * Clean up the Makefile, it's a mess -- docker buidl: show short IDs -- docker build: on non-existent local path for ADD, don't show full absolute path on the host -- mount into /dockerinit rather than /sbin/init -- docker tag foo REPO:TAG -- use size header for progress bar in pull -- Clean up context upload in build!!! -- Parallel pull -- Ensure /proc/sys/net/ipv4/ip_forward is 1 -- Force DNS to public! -- Always generate a resolv.conf per container, to avoid changing resolv.conf under thne container's feet -- Save metadata with import/export -- Upgrade dockerd without stopping containers +* docker buidl: show short IDs +* docker build: on non-existent local path for ADD, don't show full absolute path on the host +* mount into /dockerinit rather than /sbin/init +* docker tag foo REPO:TAG +* use size header for progress bar in pull +* Clean up context upload in build!!! +* Parallel pull +* Ensure /proc/sys/net/ipv4/ip_forward is 1 +* Force DNS to public! +* Always generate a resolv.conf per container, to avoid changing resolv.conf under thne container's feet +* Save metadata with import/export +* Upgrade dockerd without stopping containers +* bring back git revision info, looks like it was lost +* Simple command to remove all untagged images +* Simple command to clean up containers for disk space +* Caching after an ADD +* entry point config +* bring back git revision info, looks like it was lost From fde82f448f6b1508e03f419a3ce4c9b80311d466 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 17 Jun 2013 18:13:40 +0000 Subject: [PATCH 36/93] use go 1.1 cookiejar and revome ResetClient --- registry/registry.go | 15 +++++---------- server.go | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 131b02708e..21979fad8b 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -7,10 +7,10 @@ import ( "fmt" "github.com/dotcloud/docker/auth" "github.com/dotcloud/docker/utils" - "github.com/shin-/cookiejar" "io" "io/ioutil" "net/http" + "net/http/cookiejar" "net/url" "strings" ) @@ -438,11 +438,6 @@ func (r *Registry) SearchRepositories(term string) (*SearchResults, error) { return result, err } -func (r *Registry) ResetClient(authConfig *auth.AuthConfig) { - r.authConfig = authConfig - r.client.Jar = cookiejar.NewCookieJar() -} - func (r *Registry) GetAuthConfig(withPasswd bool) *auth.AuthConfig { password := "" if withPasswd { @@ -478,18 +473,18 @@ type Registry struct { authConfig *auth.AuthConfig } -func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry { +func NewRegistry(root string, authConfig *auth.AuthConfig) (r *Registry, err error) { httpTransport := &http.Transport{ DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment, } - r := &Registry{ + r = &Registry{ authConfig: authConfig, client: &http.Client{ Transport: httpTransport, }, } - r.client.Jar = cookiejar.NewCookieJar() - return r + r.client.Jar, err = cookiejar.New(nil) + return r, err } diff --git a/server.go b/server.go index 30e3ec6b3a..7b7eabe321 100644 --- a/server.go +++ b/server.go @@ -54,8 +54,11 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error { } func (srv *Server) ImagesSearch(term string) ([]APISearch, error) { - - results, err := registry.NewRegistry(srv.runtime.root, nil).SearchRepositories(term) + r, err := registry.NewRegistry(srv.runtime.root, nil) + if err != nil { + return nil, err + } + results, err := r.SearchRepositories(term) if err != nil { return nil, err } @@ -402,7 +405,10 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re } func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error { - r := registry.NewRegistry(srv.runtime.root, authConfig) + r, err := registry.NewRegistry(srv.runtime.root, authConfig) + if err != nil { + return err + } out = utils.NewWriteFlusher(out) if endpoint != "" { if err := srv.pullImage(r, out, name, endpoint, nil, sf); err != nil { @@ -596,8 +602,10 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error { out = utils.NewWriteFlusher(out) img, err := srv.runtime.graph.Get(name) - r := registry.NewRegistry(srv.runtime.root, authConfig) - + r, err2 := registry.NewRegistry(srv.runtime.root, authConfig) + if err2 != nil { + return err2 + } if err != nil { out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", name, len(srv.runtime.repositories.Repositories[name]))) // If it fails, try to get the repository From 13e03a691145921ffc17c56db24f06eacca99a77 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 11:29:02 -0700 Subject: [PATCH 37/93] Fix the auth tests and add the offline mode --- auth/auth_test.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/auth/auth_test.go b/auth/auth_test.go index 6c8d032cf7..e49ec03721 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -10,8 +10,8 @@ import ( func TestEncodeAuth(t *testing.T) { newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"} - authStr := EncodeAuth(newAuthConfig) - decAuthConfig, err := DecodeAuth(authStr) + authStr := encodeAuth(newAuthConfig) + decAuthConfig, err := decodeAuth(authStr) if err != nil { t.Fatal(err) } @@ -27,10 +27,13 @@ func TestEncodeAuth(t *testing.T) { } func TestLogin(t *testing.T) { + if os.Getenv("OFFLINE") != "" { + t.Skip("Offline mode, skipping.") + } os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com") defer os.Setenv("DOCKER_INDEX_URL", "") authConfig := NewAuthConfig("unittester", "surlautrerivejetattendrai", "noise+unittester@dotcloud.com", "/tmp") - status, err := Login(authConfig) + status, err := Login(authConfig, false) if err != nil { t.Fatal(err) } @@ -40,6 +43,9 @@ func TestLogin(t *testing.T) { } func TestCreateAccount(t *testing.T) { + if os.Getenv("OFFLINE") != "" { + t.Skip("Offline mode, skipping.") + } os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com") defer os.Setenv("DOCKER_INDEX_URL", "") tokenBuffer := make([]byte, 16) @@ -50,7 +56,7 @@ func TestCreateAccount(t *testing.T) { token := hex.EncodeToString(tokenBuffer)[:12] username := "ut" + token authConfig := NewAuthConfig(username, "test42", "docker-ut+"+token+"@example.com", "/tmp") - status, err := Login(authConfig) + status, err := Login(authConfig, false) if err != nil { t.Fatal(err) } @@ -60,7 +66,7 @@ func TestCreateAccount(t *testing.T) { t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status) } - status, err = Login(authConfig) + status, err = Login(authConfig, false) if err == nil { t.Fatalf("Expected error but found nil instead") } From e8f001d45157f2f645e415543d7c3e7bf832c665 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 17 Jun 2013 19:01:21 +0000 Subject: [PATCH 38/93] Bumped version to 0.4.1 --- CHANGELOG.md | 17 +++++++++++++++++ commands.go | 2 +- packaging/ubuntu/changelog | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e52eecb5..9757fa806c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 0.4.1 (2013-06-17) + + Remote Api: Add flag to enable cross domain requests + + Remote Api/Client: Add images and containers sizes in docker ps and docker images + + Runtime: Configure dns configuration host-wide with 'docker -d -dns' + + Runtime: Detect faulty DNS configuration and replace it with a public default + + Runtime: allow docker run : + + Runtime: you can now specify public port (ex: -p 80:4500) + * Client: allow multiple params in inspect + * Client: Print the container id before the hijack in `docker run` + * Registry: add regexp check on repo's name + * Registry: Move auth to the client + * Runtime: improved image removal to garbage-collect unreferenced parents + * Vagrantfile: Add the rest api port to vagrantfile's port_forward + * Upgrade to Go 1.1 + - Builder: don't ignore last line in Dockerfile when it doesn't end with \n + - Registry: Remove login check on pull + ## 0.4.0 (2013-06-03) + Introducing Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile + Introducing Remote API: control Docker programmatically using a simple HTTP/json API diff --git a/commands.go b/commands.go index 04eb994f01..ce15fd6cf1 100644 --- a/commands.go +++ b/commands.go @@ -29,7 +29,7 @@ import ( "unicode" ) -const VERSION = "0.4.0" +const VERSION = "0.4.1" var ( GITCOMMIT string diff --git a/packaging/ubuntu/changelog b/packaging/ubuntu/changelog index 5fc2e49d5e..038422967e 100644 --- a/packaging/ubuntu/changelog +++ b/packaging/ubuntu/changelog @@ -1,3 +1,22 @@ +lxc-docker (0.4.1-1) precise; urgency=low + - Builder: don't ignore last line in Dockerfile when it doesn't end with \n + - Client: allow multiple params in inspect + - Client: Print the container id before the hijack in `docker run` + - Remote Api: Add flag to enable cross domain requests + - Remote Api/Client: Add images and containers sizes in docker ps and docker images + - Registry: add regexp check on repo's name + - Registry: Move auth to the client + - Registry: Remove login check on pull + - Runtime: Configure dns configuration host-wide with 'docker -d -dns' + - Runtime: Detect faulty DNS configuration and replace it with a public default + - Runtime: allow docker run : + - Runtime: you can now specify public port (ex: -p 80:4500) + - Runtime: improved image removal to garbage-collect unreferenced parents + - Vagrantfile: Add the rest api port to vagrantfile's port_forward + - Upgrade to Go 1.1 + + -- dotCloud Mon, 17 Jun 2013 00:00:00 -0700 + lxc-docker (0.4.0-1) precise; urgency=low - Introducing Builder: 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile - Introducing Remote API: control Docker programmatically using a simple HTTP/json API From 36231345f17e6fdb08b0f756c4872294d4745048 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 17 Jun 2013 22:05:58 +0200 Subject: [PATCH 39/93] add port redirection doc --- docs/sources/use/index.rst | 1 + docs/sources/use/port_redirection.rst | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 docs/sources/use/port_redirection.rst diff --git a/docs/sources/use/index.rst b/docs/sources/use/index.rst index a1086c1fd2..2f74f60718 100644 --- a/docs/sources/use/index.rst +++ b/docs/sources/use/index.rst @@ -14,6 +14,7 @@ Contents: basics workingwithrepository + port_redirection builder puppet diff --git a/docs/sources/use/port_redirection.rst b/docs/sources/use/port_redirection.rst new file mode 100644 index 0000000000..c0b4041e7c --- /dev/null +++ b/docs/sources/use/port_redirection.rst @@ -0,0 +1,23 @@ +:title: Port redirection +:description: usage about port redirection +:keywords: Usage, basic port, docker, documentation, examples + + +Port redirection +================ + +Port redirection is done on ``docker run`` using the -p flag. + +Here are the 3 ways to redirect a port: + +.. code-block:: bash + + # the port 80 in the container is mapped to a random port of the host + docker run -p 80 + + # the port 80 in the container is mapped to the port 80 of the host + docker run -p :80 + + # the port 80 in the container is mapped to the port 5555 of the host + docker run -p 5555:80 + From 862659875335c953bf6974af4cace397c7ec3902 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Mon, 17 Jun 2013 13:25:50 -0700 Subject: [PATCH 40/93] Added content to port redirect doc --- docs/sources/use/port_redirection.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/sources/use/port_redirection.rst b/docs/sources/use/port_redirection.rst index c0b4041e7c..b866fe309d 100644 --- a/docs/sources/use/port_redirection.rst +++ b/docs/sources/use/port_redirection.rst @@ -6,18 +6,20 @@ Port redirection ================ +Docker can redirect public tcp ports to your container, so it can be reached over the network. Port redirection is done on ``docker run`` using the -p flag. -Here are the 3 ways to redirect a port: +A port redirect is specified as PUBLIC:PRIVATE, where tcp port PUBLIC will be redirected to +tcp port PRIVATE. As a special case, the public port can be omitted, in which case a random +public port will be allocated. .. code-block:: bash - # the port 80 in the container is mapped to a random port of the host + # A random PUBLIC port is redirected to PRIVATE port 80 on the container docker run -p 80 - # the port 80 in the container is mapped to the port 80 of the host - docker run -p :80 + # PUBLIC port 80 is redirected to PRIVATE port 80 + docker run -p 80:80 - # the port 80 in the container is mapped to the port 5555 of the host - docker run -p 5555:80 +Default port redirects can be built into a container with the EXPOSE build command. From cb58e63fc54fb3f1c620c8372269a8e308e43bee Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Mon, 17 Jun 2013 14:28:04 -0600 Subject: [PATCH 41/93] Typo --- docs/sources/use/port_redirection.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/use/port_redirection.rst b/docs/sources/use/port_redirection.rst index b866fe309d..5cf848f9ea 100644 --- a/docs/sources/use/port_redirection.rst +++ b/docs/sources/use/port_redirection.rst @@ -19,7 +19,7 @@ public port will be allocated. docker run -p 80 # PUBLIC port 80 is redirected to PRIVATE port 80 - docker run -p 80:80 + docker run -p 80:80 Default port redirects can be built into a container with the EXPOSE build command. From bd9bf9b646837dac5f935e43a4b950d42353676e Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Mon, 17 Jun 2013 10:31:27 -0700 Subject: [PATCH 42/93] Packaging|dockerbuilder, issue #761: use docker-golang PPA. Add Dockerfile header --- hack/dockerbuilder/Dockerfile | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hack/dockerbuilder/Dockerfile b/hack/dockerbuilder/Dockerfile index 50993ed7b5..5ccd293ca2 100644 --- a/hack/dockerbuilder/Dockerfile +++ b/hack/dockerbuilder/Dockerfile @@ -1,5 +1,13 @@ -# This will build a container capable of producing an official binary build of docker and -# uploading it to S3 +# DESCRIPTION Build a container capable of producing official binary and +# PPA packages and uploading them to S3 and Launchpad +# VERSION 1.2 +# DOCKER_VERSION 0.4 +# AUTHOR Solomon Hykes +# Daniel Mizyrycki +# BUILD_CMD docker build -t dockerbuilder . +# RUN_CMD docker run -e AWS_ID="$AWS_ID" -e AWS_KEY="$AWS_KEY" -e GPG_KEY="$GPG_KEY" dockerbuilder +# +# from ubuntu:12.04 maintainer Solomon Hykes # Workaround the upstart issue @@ -8,7 +16,7 @@ run ln -s /bin/true /sbin/initctl # Enable universe and gophers PPA run DEBIAN_FRONTEND=noninteractive apt-get install -y -q python-software-properties run add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) universe" -run add-apt-repository -y ppa:gophers/go/ubuntu +run add-apt-repository -y ppa:dotcloud/docker-golang/ubuntu run apt-get update # Packages required to checkout, build and upload docker run DEBIAN_FRONTEND=noninteractive apt-get install -y -q s3cmd From 3a0ffbc77267e395676860db265ee3476c45b3c2 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 14:44:35 -0700 Subject: [PATCH 43/93] - Runtime: Fixes #884 enforce stdout/err sync by merging the stream --- commands.go | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/commands.go b/commands.go index ce15fd6cf1..abe91f6eab 100644 --- a/commands.go +++ b/commands.go @@ -1058,37 +1058,23 @@ func (cli *DockerCli) CmdAttach(args ...string) error { return err } - splitStderr := container.Config.Tty - - connections := 1 - if splitStderr { - connections += 1 - } - chErrors := make(chan error, connections) + chErrors := make(chan error) if container.Config.Tty { cli.monitorTtySize(cmd.Arg(0)) } - if splitStderr { - go func() { - chErrors <- cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?stream=1&stderr=1", false, nil, os.Stderr) - }() - } + v := url.Values{} v.Set("stream", "1") v.Set("stdin", "1") v.Set("stdout", "1") - if !splitStderr { - v.Set("stderr", "1") - } + v.Set("stderr", "1") + go func() { chErrors <- cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, os.Stdin, os.Stdout) }() - for connections > 0 { - err := <-chErrors - if err != nil { - return err - } - connections -= 1 + + if err := <-chErrors; err != nil { + return err } return nil } From 2626d88a21f639913f7f8e8b0719fd9e07cfbed4 Mon Sep 17 00:00:00 2001 From: Joseph Anthony Pasquale Holsten Date: Mon, 17 Jun 2013 14:50:58 -0700 Subject: [PATCH 44/93] fix missing command in irc bouncer example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c909e5431..f778ff521d 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ Running an irc bouncer ---------------------- ```bash -BOUNCER_ID=$(docker run -d -p 6667 -u irc shykes/znc $USER $PASSWORD) +BOUNCER_ID=$(docker run -d -p 6667 -u irc shykes/znc zncrun $USER $PASSWORD) echo "Configure your irc client to connect to port $(docker port $BOUNCER_ID 6667) of this machine" ``` From c106ed32ea7613573a2081d47ad2498429ac86f2 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 15:40:04 -0700 Subject: [PATCH 45/93] Move the attach prevention from server to client --- commands.go | 4 ++++ server.go | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/commands.go b/commands.go index ce15fd6cf1..4297ac0c11 100644 --- a/commands.go +++ b/commands.go @@ -1058,6 +1058,10 @@ func (cli *DockerCli) CmdAttach(args ...string) error { return err } + if !container.State.Running { + return fmt.Errorf("Impossible to attach to a stopped container, start it first") + } + splitStderr := container.Config.Tty connections := 1 diff --git a/server.go b/server.go index 30e3ec6b3a..ece6a93ceb 100644 --- a/server.go +++ b/server.go @@ -930,9 +930,6 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std if container.State.Ghost { return fmt.Errorf("Impossible to attach to a ghost container") } - if !container.State.Running { - return fmt.Errorf("Impossible to attach to a stopped container, start it first") - } var ( cStdin io.ReadCloser From 2b6ca3872883dcb487d8a39a1a8530be6a62f947 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 15:45:08 -0700 Subject: [PATCH 46/93] Remove Run race condition --- commands.go | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/commands.go b/commands.go index 4297ac0c11..fb8bb528bb 100644 --- a/commands.go +++ b/commands.go @@ -1261,16 +1261,6 @@ func (cli *DockerCli) CmdRun(args ...string) error { fmt.Fprintln(os.Stderr, "WARNING: ", warning) } - splitStderr := !config.Tty - - connections := 0 - if config.AttachStdin || config.AttachStdout || (!splitStderr && config.AttachStderr) { - connections += 1 - } - if splitStderr && config.AttachStderr { - connections += 1 - } - //start the container _, _, err = cli.call("POST", "/containers/"+out.ID+"/start", nil) if err != nil { @@ -1279,19 +1269,12 @@ func (cli *DockerCli) CmdRun(args ...string) error { if !config.AttachStdout && !config.AttachStderr { fmt.Println(out.ID) - } - if connections > 0 { - chErrors := make(chan error, connections) + } else { + chErrors := make(chan error) if config.Tty { cli.monitorTtySize(out.ID) } - if splitStderr && config.AttachStderr { - go func() { - chErrors <- cli.hijack("POST", "/containers/"+out.ID+"/attach?logs=1&stream=1&stderr=1", config.Tty, nil, os.Stderr) - }() - } - v := url.Values{} v.Set("logs", "1") v.Set("stream", "1") @@ -1302,19 +1285,15 @@ func (cli *DockerCli) CmdRun(args ...string) error { if config.AttachStdout { v.Set("stdout", "1") } - if !splitStderr && config.AttachStderr { + if config.AttachStderr { v.Set("stderr", "1") } go func() { chErrors <- cli.hijack("POST", "/containers/"+out.ID+"/attach?"+v.Encode(), config.Tty, os.Stdin, os.Stdout) }() - for connections > 0 { - err := <-chErrors - if err != nil { - utils.Debugf("Error hijack: %s", err) - return err - } - connections -= 1 + if err := <-chErrors; err != nil { + utils.Debugf("Error hijack: %s", err) + return err } } return nil From fe204e6f48eb47a1deb3553003eaf9863a66fd1a Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 16:10:00 -0700 Subject: [PATCH 47/93] - Runtime: Forbid parralel push/pull for a single image/repo. Fixes #311 --- runtime_test.go | 6 ++++- server.go | 62 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/runtime_test.go b/runtime_test.go index d7d9a5a315..db6367dfaf 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -65,7 +65,11 @@ func init() { // Create the "Server" srv := &Server{ - runtime: runtime, + runtime: runtime, + enableCors: false, + lock: &sync.Mutex{}, + pullingPool: make(map[string]struct{}), + pushingPool: make(map[string]struct{}), } // Retrieve the Image if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil { diff --git a/server.go b/server.go index 30e3ec6b3a..34040df3a0 100644 --- a/server.go +++ b/server.go @@ -15,6 +15,7 @@ import ( "path" "runtime" "strings" + "sync" ) func (srv *Server) DockerVersion() APIVersion { @@ -401,7 +402,47 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re return nil } +func (srv *Server) poolAdd(kind, key string) error { + srv.lock.Lock() + defer srv.lock.Unlock() + + if _, exists := srv.pullingPool[key]; exists { + return fmt.Errorf("%s %s is already in progress", key, kind) + } + + switch kind { + case "pull": + srv.pullingPool[key] = struct{}{} + break + case "push": + srv.pushingPool[key] = struct{}{} + break + default: + return fmt.Errorf("Unkown pool type") + } + return nil +} + +func (srv *Server) poolRemove(kind, key string) error { + switch kind { + case "pull": + delete(srv.pullingPool, key) + break + case "push": + delete(srv.pushingPool, key) + break + default: + return fmt.Errorf("Unkown pool type") + } + return nil +} + func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error { + if err := srv.poolAdd("pull", name+":"+tag); err != nil { + return err + } + defer srv.poolRemove("pull", name+":"+tag) + r := registry.NewRegistry(srv.runtime.root, authConfig) out = utils.NewWriteFlusher(out) if endpoint != "" { @@ -418,7 +459,6 @@ func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *util if err := srv.pullRepository(r, out, name, remote, tag, sf); err != nil { return err } - return nil } @@ -593,7 +633,13 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, return nil } +// FIXME: Allow to interupt current push when new push of same image is done. func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error { + if err := srv.poolAdd("push", name); err != nil { + return err + } + defer srv.poolRemove("push", name) + out = utils.NewWriteFlusher(out) img, err := srv.runtime.graph.Get(name) r := registry.NewRegistry(srv.runtime.root, authConfig) @@ -991,14 +1037,20 @@ func NewServer(autoRestart, enableCors bool, dns ListOpts) (*Server, error) { return nil, err } srv := &Server{ - runtime: runtime, - enableCors: enableCors, + runtime: runtime, + enableCors: enableCors, + lock: &sync.Mutex{}, + pullingPool: make(map[string]struct{}), + pushingPool: make(map[string]struct{}), } runtime.srv = srv return srv, nil } type Server struct { - runtime *Runtime - enableCors bool + runtime *Runtime + enableCors bool + lock *sync.Mutex + pullingPool map[string]struct{} + pushingPool map[string]struct{} } From b25bcf1a666ebef26e2acfa132fa2b72d47d0805 Mon Sep 17 00:00:00 2001 From: Marcus Farkas Date: Mon, 17 Jun 2013 23:32:48 +0000 Subject: [PATCH 48/93] fix docker version git output --- AUTHORS | 1 + Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index eb90cd02d9..89fa178c3b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,6 +41,7 @@ Jérôme Petazzoni Ken Cochrane Kevin J. Lynagh Louis Opter +Marcus Farkas Maxim Treskin Michael Crosby Mikhail Sobolev diff --git a/Makefile b/Makefile index eca409c967..8676014ad4 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ endif GIT_COMMIT = $(shell git rev-parse --short HEAD) GIT_STATUS = $(shell test -n "`git status --porcelain`" && echo "+CHANGES") -BUILD_OPTIONS = -ldflags "-X main.GIT_COMMIT $(GIT_COMMIT)$(GIT_STATUS)" +BUILD_OPTIONS = -ldflags "-X main.GITCOMMIT $(GIT_COMMIT)$(GIT_STATUS)" SRC_DIR := $(GOPATH)/src From 02c291d13be261f84cdfa1d51513bf4dba31ce72 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 18:11:58 -0700 Subject: [PATCH 49/93] Fix bug on compression detection when chunck < 10bytes --- archive.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/archive.go b/archive.go index 5686408179..1e5b683765 100644 --- a/archive.go +++ b/archive.go @@ -1,7 +1,7 @@ package docker import ( - "bytes" + "bufio" "errors" "fmt" "github.com/dotcloud/docker/utils" @@ -85,17 +85,17 @@ func Tar(path string, compression Compression) (io.Reader, error) { func Untar(archive io.Reader, path string) error { - buf := make([]byte, 10) - if _, err := archive.Read(buf); err != nil { + bufferedArchive := bufio.NewReaderSize(archive, 10) + buf, err := bufferedArchive.Peek(10) + if err != nil { return err } compression := DetectCompression(buf) - archive = io.MultiReader(bytes.NewReader(buf), archive) utils.Debugf("Archive compression detected: %s", compression.Extension()) cmd := exec.Command("tar", "-f", "-", "-C", path, "-x"+compression.Flag()) - cmd.Stdin = archive + cmd.Stdin = bufferedArchive // Hardcode locale environment for predictable outcome regardless of host configuration. // (see https://github.com/dotcloud/docker/issues/355) cmd.Env = []string{"LANG=en_US.utf-8", "LC_ALL=en_US.utf-8"} From 3bfc82257878e55141bb029390574130c3ac0530 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 18:39:30 -0700 Subject: [PATCH 50/93] * API: Add tag lookup to history command. Fixes #882 --- api_params.go | 1 + commands.go | 2 +- server.go | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/api_params.go b/api_params.go index 2a641f8ccd..c3fabb2be0 100644 --- a/api_params.go +++ b/api_params.go @@ -2,6 +2,7 @@ package docker type APIHistory struct { ID string `json:"Id"` + Tag string `json:",omitempty"` Created int64 CreatedBy string `json:",omitempty"` } diff --git a/commands.go b/commands.go index ce15fd6cf1..98be40181c 100644 --- a/commands.go +++ b/commands.go @@ -627,7 +627,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error { fmt.Fprintln(w, "ID\tCREATED\tCREATED BY") for _, out := range outs { - fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.ID, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy) + fmt.Fprintf(w, "%s (%s)\t%s ago\t%s\n", out.ID, out.Tag, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy) } w.Flush() return nil diff --git a/server.go b/server.go index 30e3ec6b3a..912349b82e 100644 --- a/server.go +++ b/server.go @@ -218,12 +218,26 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) { return nil, err } + lookupMap := make(map[string]string) + for name, repository := range srv.runtime.repositories.Repositories { + for tag, id := range repository { + // If the ID already has a reverse lookup, do not update it unless for "latest" + if _, exists := lookupMap[id]; exists { + if tag != "latest" { + continue + } + } + lookupMap[id] = name + ":" + tag + } + } + outs := []APIHistory{} //produce [] when empty instead of 'null' err = image.WalkHistory(func(img *Image) error { var out APIHistory out.ID = srv.runtime.repositories.ImageName(img.ShortID()) out.Created = img.Created.Unix() out.CreatedBy = strings.Join(img.ContainerConfig.Cmd, " ") + out.Tag = lookupMap[img.ID] outs = append(outs, out) return nil }) From 02a002d264faa7b8cdf5c68b7370c31d6794a44d Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Mon, 17 Jun 2013 18:41:13 -0700 Subject: [PATCH 51/93] Update documentation --- docs/sources/api/docker_remote_api_v1.2.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sources/api/docker_remote_api_v1.2.rst b/docs/sources/api/docker_remote_api_v1.2.rst index fb69168120..44a397a4db 100644 --- a/docs/sources/api/docker_remote_api_v1.2.rst +++ b/docs/sources/api/docker_remote_api_v1.2.rst @@ -691,6 +691,7 @@ Get the history of an image [ { "Id":"b750fe79269d", + "Tag":"base:latest", "Created":1364102658, "CreatedBy":"/bin/bash" }, From e664a46ff334ff9f7c8dfb438e15950e3cacf184 Mon Sep 17 00:00:00 2001 From: Daniel Mizyrycki Date: Mon, 17 Jun 2013 19:50:31 -0700 Subject: [PATCH 52/93] Packaging, issue 919: Bump version to 0.4.2 --- CHANGELOG.md | 3 +++ commands.go | 2 +- packaging/ubuntu/changelog | 35 ++++++++++++++++++++--------------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9757fa806c..1e2112218b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.4.2 (2013-06-17) + - Packaging: Bumped version to work around an Ubuntu bug + ## 0.4.1 (2013-06-17) + Remote Api: Add flag to enable cross domain requests + Remote Api/Client: Add images and containers sizes in docker ps and docker images diff --git a/commands.go b/commands.go index ce15fd6cf1..cf23a8d65e 100644 --- a/commands.go +++ b/commands.go @@ -29,7 +29,7 @@ import ( "unicode" ) -const VERSION = "0.4.1" +const VERSION = "0.4.2" var ( GITCOMMIT string diff --git a/packaging/ubuntu/changelog b/packaging/ubuntu/changelog index 038422967e..ef7efba473 100644 --- a/packaging/ubuntu/changelog +++ b/packaging/ubuntu/changelog @@ -1,19 +1,24 @@ +lxc-docker (0.4.2-1) precise; urgency=low + - Packaging: Bumped version to work around an Ubuntu bug + + -- dotCloud Mon, 17 Jun 2013 00:00:00 -0700 + lxc-docker (0.4.1-1) precise; urgency=low - - Builder: don't ignore last line in Dockerfile when it doesn't end with \n - - Client: allow multiple params in inspect - - Client: Print the container id before the hijack in `docker run` - - Remote Api: Add flag to enable cross domain requests - - Remote Api/Client: Add images and containers sizes in docker ps and docker images - - Registry: add regexp check on repo's name - - Registry: Move auth to the client - - Registry: Remove login check on pull - - Runtime: Configure dns configuration host-wide with 'docker -d -dns' - - Runtime: Detect faulty DNS configuration and replace it with a public default - - Runtime: allow docker run : - - Runtime: you can now specify public port (ex: -p 80:4500) - - Runtime: improved image removal to garbage-collect unreferenced parents - - Vagrantfile: Add the rest api port to vagrantfile's port_forward - - Upgrade to Go 1.1 + - Builder: don't ignore last line in Dockerfile when it doesn't end with \n + - Client: allow multiple params in inspect + - Client: Print the container id before the hijack in `docker run` + - Remote Api: Add flag to enable cross domain requests + - Remote Api/Client: Add images and containers sizes in docker ps and docker images + - Registry: add regexp check on repo's name + - Registry: Move auth to the client + - Registry: Remove login check on pull + - Runtime: Configure dns configuration host-wide with 'docker -d -dns' + - Runtime: Detect faulty DNS configuration and replace it with a public default + - Runtime: allow docker run : + - Runtime: you can now specify public port (ex: -p 80:4500) + - Runtime: improved image removal to garbage-collect unreferenced parents + - Vagrantfile: Add the rest api port to vagrantfile's port_forward + - Upgrade to Go 1.1 -- dotCloud Mon, 17 Jun 2013 00:00:00 -0700 From 3491d7d2f11246ba4067708a3c5336ba21da4767 Mon Sep 17 00:00:00 2001 From: Thatcher Peskens Date: Mon, 17 Jun 2013 20:16:56 -0700 Subject: [PATCH 53/93] Fixed on documentation. * replaced previously removed concepts/containers and concepts/introcution by a redirect * moved orphan index/varable to workingwiththerepository * added favicon to the layout.html * added redirect_home which is a http refresh redirect. It works like a 301 for google * fixed an issue in the layout that would make it break when on small screens --- docs/sources/concepts/containers.rst | 8 -- docs/sources/concepts/introduction.rst | 125 --------------------- docs/sources/conf.py | 24 +++- docs/sources/index/variable.rst | 27 ----- docs/sources/use/workingwithrepository.rst | 25 +++++ docs/theme/docker/layout.html | 12 +- docs/theme/docker/redirect_home.html | 12 ++ docs/theme/docker/static/css/main.css | 10 +- docs/theme/docker/static/css/main.less | 29 ++--- docs/theme/docker/static/favicon.ico | Bin 1150 -> 0 bytes docs/theme/docker/static/favicon.png | Bin 0 -> 404 bytes 11 files changed, 82 insertions(+), 190 deletions(-) delete mode 100644 docs/sources/concepts/containers.rst delete mode 100644 docs/sources/concepts/introduction.rst delete mode 100644 docs/sources/index/variable.rst create mode 100644 docs/theme/docker/redirect_home.html delete mode 100755 docs/theme/docker/static/favicon.ico create mode 100644 docs/theme/docker/static/favicon.png diff --git a/docs/sources/concepts/containers.rst b/docs/sources/concepts/containers.rst deleted file mode 100644 index e08c3654c0..0000000000 --- a/docs/sources/concepts/containers.rst +++ /dev/null @@ -1,8 +0,0 @@ -:title: Introduction -:description: An introduction to docker and standard containers? -:keywords: containers, lxc, concepts, explanation, docker, documentation - - -:note: This version of the introduction is temporary, just to make sure we don't break the links from the website when the documentation is updated - -This document has been moved to :ref:`introduction`, please update your bookmarks. \ No newline at end of file diff --git a/docs/sources/concepts/introduction.rst b/docs/sources/concepts/introduction.rst deleted file mode 100644 index 7251b51786..0000000000 --- a/docs/sources/concepts/introduction.rst +++ /dev/null @@ -1,125 +0,0 @@ -:title: Introduction -:description: An introduction to docker and standard containers? -:keywords: containers, lxc, concepts, explanation - -Introduction -============ - -Docker -- The Linux container runtime -------------------------------------- - -Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers. - -Docker is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc. - - -- **Heterogeneous payloads** Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all. -- **Any server** Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments. -- **Isolation** docker isolates processes from each other and from the underlying host, using lightweight containers. -- **Repeatability** Because containers are isolated in their own filesystem, they behave the same regardless of where, when, and alongside what they run. - -.. image:: images/lego_docker.jpg - - -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. - -The spec for Standard Containers is currently work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment. - -A great analogy for this is the shipping container. Just like Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery. - -Standard operations -~~~~~~~~~~~~~~~~~~~ - -Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged. - - -Content-agnostic -~~~~~~~~~~~~~~~~~~~ - -Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts. - - -Infrastructure-agnostic -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions. - - -Designed for automation -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon. - -Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods. - -Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider. - - -Industrial-grade delivery -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded on the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away. - -With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality. - - -Standard Container Specification -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -(TODO) - -Image format -~~~~~~~~~~~~ - -Standard operations -~~~~~~~~~~~~~~~~~~~ - -- Copy -- Run -- Stop -- Wait -- Commit -- Attach standard streams -- List filesystem changes -- ... - -Execution environment -~~~~~~~~~~~~~~~~~~~~~ - -Root filesystem -^^^^^^^^^^^^^^^ - -Environment variables -^^^^^^^^^^^^^^^^^^^^^ - -Process arguments -^^^^^^^^^^^^^^^^^ - -Networking -^^^^^^^^^^ - -Process namespacing -^^^^^^^^^^^^^^^^^^^ - -Resource limits -^^^^^^^^^^^^^^^ - -Process monitoring -^^^^^^^^^^^^^^^^^^ - -Logging -^^^^^^^ - -Signals -^^^^^^^ - -Pseudo-terminal allocation -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Security -^^^^^^^^ - diff --git a/docs/sources/conf.py b/docs/sources/conf.py index d443d34052..41dba70201 100644 --- a/docs/sources/conf.py +++ b/docs/sources/conf.py @@ -20,6 +20,20 @@ import sys, os # -- General configuration ----------------------------------------------------- + + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# the 'redirect_home.html' page redirects using a http meta refresh which, according +# to official sources is more or less equivalent of a 301. + +html_additional_pages = { + 'concepts/containers': 'redirect_home.html', + 'concepts/introduction': 'redirect_home.html', + } + + + # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' @@ -120,7 +134,11 @@ html_theme_path = ['../theme'] # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None + +# We use a png favicon. This is not compatible with internet explorer, but looks +# much better on all other browsers. However, sphynx doesn't like it (it likes +# .ico better) so we have just put it in the template rather than used this setting +# html_favicon = 'favicon.png' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -138,10 +156,6 @@ html_static_path = ['static_files'] # Custom sidebar templates, maps document names to template names. #html_sidebars = {} -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - # If false, no module index is generated. #html_domain_indices = True diff --git a/docs/sources/index/variable.rst b/docs/sources/index/variable.rst deleted file mode 100644 index 90eac3af8a..0000000000 --- a/docs/sources/index/variable.rst +++ /dev/null @@ -1,27 +0,0 @@ -:title: Index Environment Variable -:description: Setting this environment variable on the docker server will change the URL docker index. -:keywords: docker, index environment variable, documentation - -================================= -Docker Index Environment Variable -================================= - -Variable --------- - -.. code-block:: sh - - DOCKER_INDEX_URL - -Setting this environment variable on the docker server will change the URL docker index. -This address is used in commands such as ``docker login``, ``docker push`` and ``docker pull``. -The docker daemon doesn't need to be restarted for this parameter to take effect. - -Example -------- - -.. code-block:: sh - - docker -d & - export DOCKER_INDEX_URL="https://index.docker.io" - diff --git a/docs/sources/use/workingwithrepository.rst b/docs/sources/use/workingwithrepository.rst index 6fccc01a98..45702597ab 100644 --- a/docs/sources/use/workingwithrepository.rst +++ b/docs/sources/use/workingwithrepository.rst @@ -77,3 +77,28 @@ Now you can commit this image to the repository # for example docker push dhrp/kickassapp docker push + +Changing the server to connect to +---------------------------------- + +When you are running your own index and/or registry, You can change the server the docker client will connect to. + +Variable +^^^^^^^^ + +.. code-block:: sh + + DOCKER_INDEX_URL + +Setting this environment variable on the docker server will change the URL docker index. +This address is used in commands such as ``docker login``, ``docker push`` and ``docker pull``. +The docker daemon doesn't need to be restarted for this parameter to take effect. + +Example +^^^^^^^ + +.. code-block:: sh + + docker -d & + export DOCKER_INDEX_URL="https://index.docker.io" + diff --git a/docs/theme/docker/layout.html b/docs/theme/docker/layout.html index baaaec9155..707888a927 100755 --- a/docs/theme/docker/layout.html +++ b/docs/theme/docker/layout.html @@ -40,6 +40,8 @@ {%- set script_files = script_files + ['_static/js/docs.js'] %} + + {%- for cssfile in css_files %} {%- endfor %} @@ -48,9 +50,8 @@ {%- endfor %} - {%- if favicon %} - - {%- endif %} + + {%- block extrahead %}{% endblock %} @@ -104,11 +105,8 @@
-
-
- -