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()) {