Browse code

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 <vbatts@redhat.com>

Vincent Batts authored on 2014/10/13 11:26:42
Showing 2 changed files
... ...
@@ -5,10 +5,13 @@ import (
5 5
 	"encoding/json"
6 6
 	"fmt"
7 7
 	"io"
8
+	"net"
9
+	"net/http"
8 10
 	"os"
9 11
 	"reflect"
10 12
 	"strings"
11 13
 	"text/template"
14
+	"time"
12 15
 
13 16
 	flag "github.com/docker/docker/pkg/mflag"
14 17
 	"github.com/docker/docker/pkg/term"
... ...
@@ -34,6 +37,7 @@ type DockerCli struct {
34 34
 	isTerminalIn bool
35 35
 	// isTerminalOut describes if client's STDOUT is a TTY
36 36
 	isTerminalOut bool
37
+	transport     *http.Transport
37 38
 }
38 39
 
39 40
 var funcMap = template.FuncMap{
... ...
@@ -131,6 +135,19 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey,
131 131
 		err = out
132 132
 	}
133 133
 
134
+	// The transport is created here for reuse during the client session
135
+	tr := &http.Transport{
136
+		TLSClientConfig: tlsConfig,
137
+		Dial: func(dial_network, dial_addr string) (net.Conn, error) {
138
+			// Why 32? See issue 8035
139
+			return net.DialTimeout(proto, addr, 32*time.Second)
140
+		},
141
+	}
142
+	if proto == "unix" {
143
+		// no need in compressing for local communications
144
+		tr.DisableCompression = true
145
+	}
146
+
134 147
 	return &DockerCli{
135 148
 		proto:         proto,
136 149
 		addr:          addr,
... ...
@@ -144,5 +161,6 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, key libtrust.PrivateKey,
144 144
 		isTerminalOut: isTerminalOut,
145 145
 		tlsConfig:     tlsConfig,
146 146
 		scheme:        scheme,
147
+		transport:     tr,
147 148
 	}
148 149
 }
... ...
@@ -8,7 +8,6 @@ import (
8 8
 	"fmt"
9 9
 	"io"
10 10
 	"io/ioutil"
11
-	"net"
12 11
 	"net/http"
13 12
 	"net/url"
14 13
 	"os"
... ...
@@ -16,7 +15,6 @@ import (
16 16
 	"strconv"
17 17
 	"strings"
18 18
 	"syscall"
19
-	"time"
20 19
 
21 20
 	"github.com/docker/docker/api"
22 21
 	"github.com/docker/docker/dockerversion"
... ...
@@ -33,22 +31,7 @@ var (
33 33
 )
34 34
 
35 35
 func (cli *DockerCli) HTTPClient() *http.Client {
36
-	tr := &http.Transport{
37
-		TLSClientConfig: cli.tlsConfig,
38
-		Dial: func(network, addr string) (net.Conn, error) {
39
-			// Why 32? See issue 8035
40
-			return net.DialTimeout(cli.proto, cli.addr, 32*time.Second)
41
-		},
42
-	}
43
-	if cli.proto == "unix" {
44
-		// XXX workaround for net/http Transport which caches connections, but is
45
-		// intended for tcp connections, not unix sockets.
46
-		tr.DisableKeepAlives = true
47
-
48
-		// no need in compressing for local communications
49
-		tr.DisableCompression = true
50
-	}
51
-	return &http.Client{Transport: tr}
36
+	return &http.Client{Transport: cli.transport}
52 37
 }
53 38
 
54 39
 func (cli *DockerCli) encodeData(data interface{}) (*bytes.Buffer, error) {