From da42ae536cf86dafbdad88901b9322ea7317f154 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Sun, 12 Oct 2014 22:26:42 -0400 Subject: [PATCH] client: even cleaner use of Transport First off, sorry for the noise. This is a cleaner step of #8508 Found more of a root cause of the open file handles. After more testing I found that the open file descriptors will still occur for TCP:// connections to the daemon, causing client and/or daemon to fail. The issue was instantiating a new http.Transport on _ever_ client request. So each instance held the prior connection alive, but was only ever used once. By moving it out to the initilization of DockerCli, we can now have reuse of idled connections. Simplifies the garbage overhead of the client too, though that's not usually a deal. Signed-off-by: Vincent Batts --- api/client/cli.go | 18 ++++++++++++++++++ api/client/utils.go | 19 +------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/api/client/cli.go b/api/client/cli.go index 6bc3fc350760830620468e94c92413e8b6c76726..70eae6e4b4e3509b5b882d51b1920605388aa7b4 100644 --- a/api/client/cli.go +++ b/api/client/cli.go @@ -5,10 +5,13 @@ import ( "encoding/json" "fmt" "io" + "net" + "net/http" "os" "reflect" "strings" "text/template" + "time" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/term" @@ -34,6 +37,7 @@ type DockerCli struct { isTerminalIn bool // isTerminalOut describes if client's STDOUT is a TTY isTerminalOut bool + transport *http.Transport } var funcMap = template.FuncMap{ @@ -131,6 +135,19 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey, err = out } + // The transport is created here for reuse during the client session + tr := &http.Transport{ + TLSClientConfig: tlsConfig, + Dial: func(dial_network, dial_addr string) (net.Conn, error) { + // Why 32? See issue 8035 + return net.DialTimeout(proto, addr, 32*time.Second) + }, + } + if proto == "unix" { + // no need in compressing for local communications + tr.DisableCompression = true + } + return &DockerCli{ proto: proto, addr: addr, @@ -144,5 +161,6 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey, isTerminalOut: isTerminalOut, tlsConfig: tlsConfig, scheme: scheme, + transport: tr, } } diff --git a/api/client/utils.go b/api/client/utils.go index 58b730bd1b29d1c25ce15bbb39dbf669a54d59bb..11e39729af9d165fdcb3f867b700f019e934f331 100644 --- a/api/client/utils.go +++ b/api/client/utils.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "io/ioutil" - "net" "net/http" "net/url" "os" @@ -16,7 +15,6 @@ import ( "strconv" "strings" "syscall" - "time" "github.com/docker/docker/api" "github.com/docker/docker/dockerversion" @@ -33,22 +31,7 @@ var ( ) func (cli *DockerCli) HTTPClient() *http.Client { - tr := &http.Transport{ - TLSClientConfig: cli.tlsConfig, - Dial: func(network, addr string) (net.Conn, error) { - // Why 32? See issue 8035 - return net.DialTimeout(cli.proto, cli.addr, 32*time.Second) - }, - } - if cli.proto == "unix" { - // XXX workaround for net/http Transport which caches connections, but is - // intended for tcp connections, not unix sockets. - tr.DisableKeepAlives = true - - // no need in compressing for local communications - tr.DisableCompression = true - } - return &http.Client{Transport: tr} + return &http.Client{Transport: cli.transport} } func (cli *DockerCli) encodeData(data interface{}) (*bytes.Buffer, error) {