Browse code

Fixes for resolv.conf

Handle the case of systemd-resolved, and if in place
use a different resolv.conf source.
Set appropriately the option on libnetwork.
Move unix specific code to container_operation_unix

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>

Flavio Crisciani authored on 2018/07/18 04:11:38
Showing 10 changed files
... ...
@@ -75,6 +75,8 @@ type commonBridgeConfig struct {
75 75
 type NetworkConfig struct {
76 76
 	// Default address pools for docker networks
77 77
 	DefaultAddressPools opts.PoolsOpt `json:"default-address-pools,omitempty"`
78
+	// NetworkControlPlaneMTU allows to specify the control plane MTU, this will allow to optimize the network use in some components
79
+	NetworkControlPlaneMTU int `json:"network-control-plane-mtu,omitempty"`
78 80
 }
79 81
 
80 82
 // CommonTLSOptions defines TLS configuration for the daemon server.
... ...
@@ -192,8 +194,6 @@ type CommonConfig struct {
192 192
 	// Exposed node Generic Resources
193 193
 	// e.g: ["orange=red", "orange=green", "orange=blue", "apple=3"]
194 194
 	NodeGenericResources []string `json:"node-generic-resources,omitempty"`
195
-	// NetworkControlPlaneMTU allows to specify the control plane MTU, this will allow to optimize the network use in some components
196
-	NetworkControlPlaneMTU int `json:"network-control-plane-mtu,omitempty"`
197 195
 
198 196
 	// ContainerAddr is the address used to connect to containerd if we're
199 197
 	// not starting it ourselves
... ...
@@ -69,3 +69,9 @@ func (conf *Config) GetInitPath() string {
69 69
 	}
70 70
 	return DefaultInitBinary
71 71
 }
72
+
73
+// GetResolvConf returns the appropriate resolv.conf
74
+// Check setupResolvConf on how this is selected
75
+func (conf *Config) GetResolvConf() string {
76
+	return conf.ResolvConf
77
+}
... ...
@@ -37,6 +37,8 @@ type Config struct {
37 37
 	ShmSize              opts.MemBytes            `json:"default-shm-size,omitempty"`
38 38
 	NoNewPrivileges      bool                     `json:"no-new-privileges,omitempty"`
39 39
 	IpcMode              string                   `json:"default-ipc-mode,omitempty"`
40
+	// ResolvConf is the path to the configuration of the host resolver
41
+	ResolvConf string `json:"resolv-conf,omitempty"`
40 42
 }
41 43
 
42 44
 // BridgeConfig stores all the bridge driver specific
... ...
@@ -63,21 +63,13 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
63 63
 
64 64
 	if container.HostConfig.NetworkMode.IsHost() {
65 65
 		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
66
-		if len(container.HostConfig.ExtraHosts) == 0 {
67
-			sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
68
-		}
69
-		if len(container.HostConfig.DNS) == 0 && len(daemon.configStore.DNS) == 0 &&
70
-			len(container.HostConfig.DNSSearch) == 0 && len(daemon.configStore.DNSSearch) == 0 &&
71
-			len(container.HostConfig.DNSOptions) == 0 && len(daemon.configStore.DNSOptions) == 0 {
72
-			sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
73
-		}
74 66
 	} else {
75 67
 		// OptionUseExternalKey is mandatory for userns support.
76 68
 		// But optional for non-userns support
77 69
 		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
78 70
 	}
79 71
 
80
-	if err = setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
72
+	if err = daemon.setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
81 73
 		return nil, err
82 74
 	}
83 75
 
... ...
@@ -369,9 +369,17 @@ func (daemon *Daemon) isNetworkHotPluggable() bool {
369 369
 	return true
370 370
 }
371 371
 
372
-func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
372
+func (daemon *Daemon) setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
373 373
 	var err error
374 374
 
375
+	if container.HostConfig.NetworkMode.IsHost() {
376
+		// Point to the host files, so that will be copied into the container running in host mode
377
+		*sboxOptions = append(*sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
378
+		*sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
379
+	} else {
380
+		*sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath(daemon.configStore.GetResolvConf()))
381
+	}
382
+
375 383
 	container.HostsPath, err = container.GetRootResourcePath("hosts")
376 384
 	if err != nil {
377 385
 		return err
... ...
@@ -155,7 +155,7 @@ func (daemon *Daemon) isNetworkHotPluggable() bool {
155 155
 	return true
156 156
 }
157 157
 
158
-func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
158
+func (daemon *Daemon) setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
159 159
 	return nil
160 160
 }
161 161
 
... ...
@@ -581,6 +581,9 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
581 581
 	// Do we have a disabled network?
582 582
 	config.DisableBridge = isBridgeNetworkDisabled(config)
583 583
 
584
+	// Setup the resolv.conf
585
+	setupResolvConf(config)
586
+
584 587
 	// Verify the platform is supported as a daemon
585 588
 	if !platformSupported {
586 589
 		return nil, errSystemNotSupported
... ...
@@ -8,12 +8,19 @@ import (
8 8
 	"regexp"
9 9
 	"strings"
10 10
 
11
+	"github.com/docker/docker/daemon/config"
12
+	"github.com/docker/docker/internal/procfs"
11 13
 	"github.com/docker/docker/pkg/fileutils"
12 14
 	"github.com/docker/docker/pkg/mount"
13 15
 	"github.com/pkg/errors"
14 16
 	"github.com/sirupsen/logrus"
15 17
 )
16 18
 
19
+const (
20
+	defaultResolvConf   = "/etc/resolv.conf"
21
+	alternateResolvConf = "/run/systemd/resolve/resolv.conf"
22
+)
23
+
17 24
 // On Linux, plugins use a static path for storing execution state,
18 25
 // instead of deriving path from daemon's exec-root. This is because
19 26
 // plugin socket files are created here and they cannot exceed max
... ...
@@ -131,3 +138,30 @@ func shouldUnmountRoot(root string, info *mount.Info) bool {
131 131
 	}
132 132
 	return hasMountinfoOption(info.Optional, sharedPropagationOption)
133 133
 }
134
+
135
+// setupResolvConf sets the appropriate resolv.conf file if not specified
136
+// When systemd-resolved is running the default /etc/resolv.conf points to
137
+// localhost. In this case fetch the alternative config file that is in a
138
+// different path so that containers can use it
139
+// In all the other cases fallback to the default one
140
+func setupResolvConf(config *config.Config) {
141
+	if config.ResolvConf != "" {
142
+		return
143
+	}
144
+
145
+	config.ResolvConf = defaultResolvConf
146
+	pids, err := procfs.PidOf("systemd-resolved")
147
+	if err != nil {
148
+		logrus.Errorf("unable to check systemd-resolved status: %s", err)
149
+		return
150
+	}
151
+	if len(pids) > 0 && pids[0] > 0 {
152
+		_, err := os.Stat(alternateResolvConf)
153
+		if err == nil {
154
+			logrus.Infof("systemd-resolved is running, so using resolvconf: %s", alternateResolvConf)
155
+			config.ResolvConf = alternateResolvConf
156
+			return
157
+		}
158
+		logrus.Infof("systemd-resolved is running, but %s is not present, fallback to %s", alternateResolvConf, defaultResolvConf)
159
+	}
160
+}
... ...
@@ -1,5 +1,9 @@
1 1
 // +build !linux,!freebsd,!windows
2 2
 
3 3
 package daemon // import "github.com/docker/docker/daemon"
4
+import "github.com/docker/docker/daemon/config"
4 5
 
5 6
 const platformSupported = false
7
+
8
+func setupResolvConf(config *config.Config) {
9
+}
... ...
@@ -653,3 +653,6 @@ func (daemon *Daemon) loadRuntimes() error {
653 653
 func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error {
654 654
 	return nil
655 655
 }
656
+
657
+func setupResolvConf(config *config.Config) {
658
+}