Set container DNS with `--default_container_dns` in Docker executor.

Review: https://reviews.apache.org/r/60558


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/3da83b33
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/3da83b33
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/3da83b33

Branch: refs/heads/master
Commit: 3da83b3318a612b3bbf1223fbafe506c1ed4bcc4
Parents: 48b5ef0
Author: Qian Zhang <zhq527...@gmail.com>
Authored: Fri Jun 30 09:53:41 2017 +0800
Committer: Qian Zhang <zhq527...@gmail.com>
Committed: Thu Aug 3 13:53:26 2017 +0800

----------------------------------------------------------------------
 src/docker/docker.cpp   | 105 +++++++++++++++++++++++++++++++++++++++++--
 src/docker/docker.hpp   |  14 +++++-
 src/docker/executor.cpp |   3 +-
 3 files changed, 116 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/3da83b33/src/docker/docker.cpp
----------------------------------------------------------------------
diff --git a/src/docker/docker.cpp b/src/docker/docker.cpp
index 8081c02..daa340f 100755
--- a/src/docker/docker.cpp
+++ b/src/docker/docker.cpp
@@ -59,6 +59,8 @@ using std::map;
 using std::string;
 using std::vector;
 
+using mesos::internal::ContainerDNSInfo;
+
 
 template <typename T>
 static Future<T> failure(
@@ -505,7 +507,8 @@ Try<Docker::RunOptions> Docker::RunOptions::create(
     const Option<Resources>& resources,
     bool enableCfsQuota,
     const Option<map<string, string>>& env,
-    const Option<vector<Device>>& devices)
+    const Option<vector<Device>>& devices,
+    const Option<ContainerDNSInfo>& defaultContainerDNS)
 {
   if (!containerInfo.has_docker()) {
     return Error("No docker info found in container info");
@@ -727,9 +730,71 @@ Try<Docker::RunOptions> Docker::RunOptions::create(
 
   options.name = name;
 
+  bool dnsSpecified = false;
   foreach (const Parameter& parameter, dockerInfo.parameters()) {
     options.additionalOptions.push_back(
         "--" + parameter.key() + "=" + parameter.value());
+
+    // In Docker 1.13.0, `--dns-option` was added and `--dns-opt` was hidden
+    // (but it can still be used), so here we need to check both of them.
+    if (!dnsSpecified &&
+        (parameter.key() == "dns" ||
+         parameter.key() == "dns-search" ||
+         parameter.key() == "dns-opt" ||
+         parameter.key() == "dns-option")) {
+      dnsSpecified = true;
+    }
+  }
+
+  if (!dnsSpecified && defaultContainerDNS.isSome()) {
+    Option<ContainerDNSInfo::DockerInfo> bridgeDNS;
+    Option<ContainerDNSInfo::DockerInfo> defaultUserDNS;
+    hashmap<string, ContainerDNSInfo::DockerInfo> userDNSMap;
+
+    foreach (const ContainerDNSInfo::DockerInfo& dnsInfo,
+             defaultContainerDNS->docker()) {
+      // Currently we only support setting DNS for containers which join
+      // Docker bridge network or user-defined network.
+      if (dnsInfo.network_mode() == ContainerDNSInfo::DockerInfo::BRIDGE) {
+        bridgeDNS = dnsInfo;
+      } else if (dnsInfo.network_mode() == ContainerDNSInfo::DockerInfo::USER) 
{
+        if (!dnsInfo.has_network_name()) {
+          // The DNS info which has network node set as `USER` and has no
+          // network name set is considered as the default DNS for all
+          // user-defined networks. It applies to the Docker container which
+          // joins a user-defined network but that network can not be found in
+          // `defaultContainerDNS`.
+          defaultUserDNS = dnsInfo;
+        } else {
+          userDNSMap[dnsInfo.network_name()] = dnsInfo;
+        }
+      }
+    }
+
+    auto setDNSInfo = [&](const ContainerDNSInfo::DockerInfo& dnsInfo) {
+      options.dns.assign(
+          dnsInfo.dns().nameservers().begin(),
+          dnsInfo.dns().nameservers().end());
+
+      options.dnsSearch.assign(
+          dnsInfo.dns().search().begin(),
+          dnsInfo.dns().search().end());
+
+      options.dnsOpt.assign(
+          dnsInfo.dns().options().begin(),
+          dnsInfo.dns().options().end());
+    };
+
+    if (dockerInfo.network() == ContainerInfo::DockerInfo::BRIDGE &&
+        bridgeDNS.isSome()) {
+      setDNSInfo(bridgeDNS.get());
+    } else if (dockerInfo.network() == ContainerInfo::DockerInfo::USER) {
+      if (userDNSMap.contains(options.network.get())) {
+        setDNSInfo(userDNSMap.at(options.network.get()));
+      } else if (defaultUserDNS.isSome()) {
+        setDNSInfo(defaultUserDNS.get());
+      }
+    }
   }
 
   options.image = dockerInfo.image();
@@ -827,14 +892,48 @@ Future<Option<int>> Docker::run(
     if (network != "host" &&
         network != "bridge" &&
         network != "none") {
-      // User defined networks require docker version >= 1.9.0.
+      // User defined networks require Docker version >= 1.9.0.
       Try<Nothing> validateVer = validateVersion(Version(1, 9, 0));
-
       if (validateVer.isError()) {
         return Failure("User defined networks require Docker "
                        "version 1.9.0 or higher");
       }
     }
+
+    if (network == "host" && !options.dns.empty()) {
+      // `--dns` option with host network requires Docker version >= 1.12.0,
+      // see https://github.com/moby/moby/pull/22408 for details.
+      Try<Nothing> validateVer = validateVersion(Version(1, 12, 0));
+      if (validateVer.isError()) {
+        return Failure("--dns option with host network requires Docker "
+                       "version 1.12.0 or higher");
+      }
+    }
+  }
+
+  foreach (const string& dns, options.dns) {
+    argv.push_back("--dns");
+    argv.push_back(dns);
+  }
+
+  foreach (const string& search, options.dnsSearch) {
+    argv.push_back("--dns-search");
+    argv.push_back(search);
+  }
+
+  if (!options.dnsOpt.empty()) {
+    // `--dns-opt` option requires Docker version >= 1.9.0,
+    // see https://github.com/moby/moby/pull/16031 for details.
+    Try<Nothing> validateVer = validateVersion(Version(1, 9, 0));
+    if (validateVer.isError()) {
+      return Failure("--dns-opt option requires Docker "
+                     "version 1.9.0 or higher");
+    }
+  }
+
+  foreach (const string& opt, options.dnsOpt) {
+    argv.push_back("--dns-opt");
+    argv.push_back(opt);
   }
 
   if (options.hostname.isSome()) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/3da83b33/src/docker/docker.hpp
----------------------------------------------------------------------
diff --git a/src/docker/docker.hpp b/src/docker/docker.hpp
index 5593cb6..9581aa2 100644
--- a/src/docker/docker.hpp
+++ b/src/docker/docker.hpp
@@ -37,6 +37,7 @@
 
 #include "mesos/resources.hpp"
 
+#include "messages/flags.hpp"
 
 // OS-specific default prefix to be used for the DOCKER_HOST environment
 // variable. Note that on Linux, the default prefix is the only prefix
@@ -48,7 +49,6 @@ constexpr char DEFAULT_DOCKER_HOST_PREFIX[] = "npipe://";
 constexpr char DEFAULT_DOCKER_HOST_PREFIX[] = "unix://";
 #endif // __WINDOWS__
 
-
 // Abstraction for working with Docker (modeled on CLI).
 //
 // TODO(benh): Make futures returned by functions be discardable.
@@ -163,7 +163,8 @@ public:
         const Option<mesos::Resources>& resources = None(),
         bool enableCfsQuota = false,
         const Option<std::map<std::string, std::string>>& env = None(),
-        const Option<std::vector<Device>>& devices = None());
+        const Option<std::vector<Device>>& devices = None(),
+        const Option<mesos::internal::ContainerDNSInfo>& defaultContainerDNS = 
None()); // NOLINT(whitespace/line_length)
 
     // "--privileged" option.
     bool privileged;
@@ -193,6 +194,15 @@ public:
     // "--hostname" option.
     Option<std::string> hostname;
 
+    // "--dns" option.
+    std::vector<std::string> dns;
+
+    // "--dns-search" option.
+    std::vector<std::string> dnsSearch;
+
+    // "--dns-opt" option.
+    std::vector<std::string> dnsOpt;
+
     // Port mappings for "-p" option.
     std::vector<PortMapping> portMappings;
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/3da83b33/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index a14ac7d..26f12ec 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -170,7 +170,8 @@ public:
         task.resources() + task.executor().resources(),
         cgroupsEnableCfs,
         taskEnvironment,
-        None() // No extra devices.
+        None(), // No extra devices.
+        defaultContainerDNS
     );
 
     if (runOptions.isError()) {

Reply via email to