From b02ff5c059440a2a7b178d30c3147e9ce879a282 Mon Sep 17 00:00:00 2001 From: toby Date: Wed, 17 Jan 2018 12:18:13 +0100 Subject: Apply NAT to all interfaces and set container /etc/hosts --- .../hosted/dockerapi/CreateContainerCommandImpl.java | 9 ++++++++- .../java/com/yahoo/vespa/hosted/dockerapi/Docker.java | 1 + .../hosted/node/admin/docker/DockerOperationsImpl.java | 15 +++++++++++---- .../node/admin/maintenance/acl/iptables/NATCommand.java | 12 +++++------- .../hosted/node/admin/integrationTests/DockerMock.java | 5 +++++ .../admin/maintenance/acl/iptables/NATCommandTest.java | 10 ++++------ 6 files changed, 34 insertions(+), 18 deletions(-) diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java index 485de99082b..62bc78dcfce 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/CreateContainerCommandImpl.java @@ -39,6 +39,7 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { private Optional entrypoint = Optional.empty(); private Set addCapabilities = new HashSet<>(); private Set dropCapabilities = new HashSet<>(); + private List extraHosts = new ArrayList<>(); CreateContainerCommandImpl(DockerClient docker, DockerImage dockerImage, @@ -88,7 +89,6 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { return this; } - @Override public Docker.CreateContainerCommand withEnvironment(String name, String value) { assert name.indexOf('=') == -1; @@ -109,6 +109,12 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { return this; } + @Override + public Docker.CreateContainerCommand withExtraHost(String hostname, String ip) { + extraHosts.add(hostname + ":" + ip); + return this; + } + @Override public Docker.CreateContainerCommand withIpAddress(InetAddress address) { if (address instanceof Inet6Address) { @@ -140,6 +146,7 @@ class CreateContainerCommandImpl implements Docker.CreateContainerCommand { .withLabels(labels) .withEnv(environmentAssignments) .withBinds(volumeBinds) + .withExtraHosts(extraHosts) .withUlimits(ulimits) .withCapAdd(new ArrayList<>(addCapabilities)) .withCapDrop(new ArrayList<>(dropCapabilities)); diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java index b30b1f96dbb..6fc9472a30e 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java @@ -28,6 +28,7 @@ public interface Docker { CreateContainerCommand withManagedBy(String manager); CreateContainerCommand withAddCapability(String capabilityName); CreateContainerCommand withDropCapability(String capabilityName); + CreateContainerCommand withExtraHost(String hostname, String ip); void create(); } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java index ea4ae79ccfe..f5257dff92b 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java @@ -120,12 +120,15 @@ public class DockerOperationsImpl implements DockerOperations { .withAddCapability("SYS_ADMIN"); // Needed for perf if (!docker.networkNATted()) { - logger.info("Network not natted - setting up with specific ip address on a macvlan"); + logger.info("Network not nated - setting up with specific ip address on a macvlan"); command.withIpAddress(nodeInetAddress); command.withNetworkMode(DockerImpl.DOCKER_CUSTOM_MACVLAN_NETWORK_NAME); + command.withVolume("/etc/hosts", "/etc/hosts"); + } else { + logger.info("Network is nated - Adding hostname to /etc/hosts"); + command.withExtraHost(nodeSpec.hostname, isIPv6 ? "::1" : "127.0.0.1"); } - command.withVolume("/etc/hosts", "/etc/hosts"); for (String pathInNode : DIRECTORIES_TO_MOUNT.keySet()) { String pathInHost = environment.pathInHostFromPathInNode(containerName, pathInNode).toString(); command.withVolume(pathInHost, pathInNode); @@ -211,9 +214,13 @@ public class DockerOperationsImpl implements DockerOperations { private void setupContainerNetworkConnectivity(ContainerName containerName, InetAddress externalAddress) throws IOException { if (docker.networkNATted()) { String ipv6Str = docker.getGlobalIPv6Address(containerName); - String natCommand = NATCommand.create(externalAddress, InetAddress.getByName(ipv6Str), "eth0"); + String natCommand = NATCommand.create(externalAddress, InetAddress.getByName(ipv6Str)); PrefixLogger logger = PrefixLogger.getNodeAgentLogger(DockerOperationsImpl.class, containerName); - logger.info("Please setup these rules:" + natCommand); + logger.info("Setting up NAT rules: " + natCommand); + Pair result = processExecuter.exec(natCommand); + if (result.getFirst() != 0) { + throw new IOException("Unable to setup NAT rule - error message: " + result.getSecond()); + } } else { InetAddress hostDefaultGateway = DockerNetworkCreator.getDefaultGatewayLinux(true); executeCommandInNetworkNamespace(containerName, diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommand.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommand.java index 05ccaebe04b..23368014a8a 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommand.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommand.java @@ -17,17 +17,15 @@ public class NATCommand implements Command { private final String snatCommand; private final String dnatCommand; - public NATCommand(InetAddress externalIp, InetAddress internalIp, String iface) { + public NATCommand(InetAddress externalIp, InetAddress internalIp) { String command = externalIp instanceof Inet6Address ? "ip6tables" : "iptables"; - this.snatCommand = String.format("%s -t nat -A POSTROUTING -o %s -s %s -j SNAT --to %s", + this.snatCommand = String.format("%s -t nat -A POSTROUTING -s %s -j SNAT --to %s", command, - iface, internalIp.getHostAddress(), externalIp.getHostAddress()); - this.dnatCommand = String.format("%s -t nat -A PREROUTING -i %s -d %s -j DNAT --to-destination %s", + this.dnatCommand = String.format("%s -t nat -A PREROUTING -d %s -j DNAT --to-destination %s", command, - iface, externalIp.getHostAddress(), internalIp.getHostAddress()); } @@ -40,7 +38,7 @@ public class NATCommand implements Command { @Override public String asString(String commandName) { return asString(); } - public static String create(InetAddress externalIp, InetAddress internalIp, String iface) { - return new NATCommand(externalIp, internalIp, iface).asString(); + public static String create(InetAddress externalIp, InetAddress internalIp) { + return new NATCommand(externalIp, internalIp).asString(); } } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java index 8a4c4fd8c88..e0142410e79 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java @@ -218,6 +218,11 @@ public class DockerMock implements Docker { return this; } + @Override + public CreateContainerCommand withExtraHost(String hostname, String ip) { + return this; + } + @Override public void create() { diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommandTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommandTest.java index c2a2575f6b1..086aef8295b 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommandTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/acl/iptables/NATCommandTest.java @@ -20,19 +20,17 @@ public class NATCommandTest { public void sampleNATCommandIPv6() throws UnknownHostException{ InetAddress externalIP = Inet6Address.getByName("2001:db8::1"); InetAddress internalIP = Inet6Address.getByName("2001:db8::2"); - String iface = "eth0"; - NATCommand command = new NATCommand(externalIP, internalIP, iface); - Assert.assertEquals("ip6tables -t nat -A POSTROUTING -o eth0 -s 2001:db8:0:0:0:0:0:2 -j SNAT --to 2001:db8:0:0:0:0:0:1; ip6tables -t nat -A PREROUTING -i eth0 -d 2001:db8:0:0:0:0:0:1 -j DNAT --to-destination 2001:db8:0:0:0:0:0:2", command.asString()); + NATCommand command = new NATCommand(externalIP, internalIP); + Assert.assertEquals("ip6tables -t nat -A POSTROUTING -s 2001:db8:0:0:0:0:0:2 -j SNAT --to 2001:db8:0:0:0:0:0:1; ip6tables -t nat -A PREROUTING -d 2001:db8:0:0:0:0:0:1 -j DNAT --to-destination 2001:db8:0:0:0:0:0:2", command.asString()); } @Test public void sampleNATCommandIPv4() throws UnknownHostException{ InetAddress externalIP = Inet4Address.getByName("192.168.0.1"); InetAddress internalIP = Inet4Address.getByName("192.168.0.2"); - String iface = "eth0"; - NATCommand command = new NATCommand(externalIP, internalIP, iface); - Assert.assertEquals("iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.2 -j SNAT --to 192.168.0.1; iptables -t nat -A PREROUTING -i eth0 -d 192.168.0.1 -j DNAT --to-destination 192.168.0.2", command.asString()); + NATCommand command = new NATCommand(externalIP, internalIP); + Assert.assertEquals("iptables -t nat -A POSTROUTING -s 192.168.0.2 -j SNAT --to 192.168.0.1; iptables -t nat -A PREROUTING -d 192.168.0.1 -j DNAT --to-destination 192.168.0.2", command.asString()); } } -- cgit v1.2.3