YARN-6930. Admins should be able to explicitly enable specific LinuxContainerRuntime in the NodeManager. Contributed by Shane Kumpf

(cherry picked from commit b0b535d9d5)
This commit is contained in:
Jason Lowe 2017-09-07 16:12:09 -05:00
parent 5757600b8d
commit 7287932397
10 changed files with 314 additions and 80 deletions

View File

@ -1464,6 +1464,23 @@ public class YarnConfiguration extends Configuration {
/** Prefix for runtime configuration constants. */ /** Prefix for runtime configuration constants. */
public static final String LINUX_CONTAINER_RUNTIME_PREFIX = NM_PREFIX + public static final String LINUX_CONTAINER_RUNTIME_PREFIX = NM_PREFIX +
"runtime.linux."; "runtime.linux.";
/**
* Comma separated list of runtimes that are allowed when using
* LinuxContainerExecutor. The allowed values are:
* <ul>
* <li>default</li>
* <li>docker</li>
* <li>javasandbox</li>
* </ul>
*/
public static final String LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES =
LINUX_CONTAINER_RUNTIME_PREFIX + "allowed-runtimes";
/** The default list of allowed runtimes when using LinuxContainerExecutor. */
public static final String[] DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES
= {"default"};
public static final String DOCKER_CONTAINER_RUNTIME_PREFIX = public static final String DOCKER_CONTAINER_RUNTIME_PREFIX =
LINUX_CONTAINER_RUNTIME_PREFIX + "docker."; LINUX_CONTAINER_RUNTIME_PREFIX + "docker.";

View File

@ -1571,6 +1571,14 @@
<value>false</value> <value>false</value>
</property> </property>
<property>
<description>Comma separated list of runtimes that are allowed when using
LinuxContainerExecutor. The allowed values are default, docker, and
javasandbox.</description>
<name>yarn.nodemanager.runtime.linux.allowed-runtimes</name>
<value>default</value>
</property>
<property> <property>
<description>This configuration setting determines the capabilities <description>This configuration setting determines the capabilities
assigned to docker containers when they are launched. While these may not assigned to docker containers when they are launched. While these may not

View File

@ -51,6 +51,7 @@ import org.apache.hadoop.yarn.exceptions.ConfigurationException;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerDiagnosticsUpdateEvent; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerDiagnosticsUpdateEvent;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch; import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerPrepareContext; import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerPrepareContext;
import org.apache.hadoop.yarn.server.nodemanager.util.NodeManagerHardwareUtils; import org.apache.hadoop.yarn.server.nodemanager.util.NodeManagerHardwareUtils;
import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerLivenessContext; import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerLivenessContext;
@ -663,7 +664,8 @@ public abstract class ContainerExecutor implements Configurable {
} }
// LinuxContainerExecutor overrides this method and behaves differently. // LinuxContainerExecutor overrides this method and behaves differently.
public String[] getIpAndHost(Container container) { public String[] getIpAndHost(Container container)
throws ContainerExecutionException {
return getLocalIpAndHost(container); return getLocalIpAndHost(container);
} }

View File

@ -625,7 +625,8 @@ public class LinuxContainerExecutor extends ContainerExecutor {
} }
@Override @Override
public String[] getIpAndHost(Container container) { public String[] getIpAndHost(Container container)
throws ContainerExecutionException {
return linuxContainerRuntime.getIpAndHost(container); return linuxContainerRuntime.getIpAndHost(container);
} }

View File

@ -20,9 +20,11 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime; package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
@ -31,6 +33,7 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.Contai
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.EnumSet;
import java.util.Map; import java.util.Map;
/** /**
@ -50,34 +53,62 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
private DefaultLinuxContainerRuntime defaultLinuxContainerRuntime; private DefaultLinuxContainerRuntime defaultLinuxContainerRuntime;
private DockerLinuxContainerRuntime dockerLinuxContainerRuntime; private DockerLinuxContainerRuntime dockerLinuxContainerRuntime;
private JavaSandboxLinuxContainerRuntime javaSandboxLinuxContainerRuntime; private JavaSandboxLinuxContainerRuntime javaSandboxLinuxContainerRuntime;
private EnumSet<LinuxContainerRuntimeConstants.RuntimeType> allowedRuntimes =
EnumSet.noneOf(LinuxContainerRuntimeConstants.RuntimeType.class);
@Override @Override
public void initialize(Configuration conf) public void initialize(Configuration conf)
throws ContainerExecutionException { throws ContainerExecutionException {
PrivilegedOperationExecutor privilegedOperationExecutor = String[] configuredRuntimes = conf.getTrimmedStrings(
PrivilegedOperationExecutor.getInstance(conf); YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
defaultLinuxContainerRuntime = new DefaultLinuxContainerRuntime( YarnConfiguration.DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES);
privilegedOperationExecutor); for (String configuredRuntime : configuredRuntimes) {
defaultLinuxContainerRuntime.initialize(conf); try {
dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime( allowedRuntimes.add(
privilegedOperationExecutor); LinuxContainerRuntimeConstants.RuntimeType.valueOf(
dockerLinuxContainerRuntime.initialize(conf); configuredRuntime.toUpperCase()));
} catch (IllegalArgumentException e) {
throw new ContainerExecutionException("Invalid runtime set in "
+ YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES + " : "
+ configuredRuntime);
}
}
if (isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX)) {
javaSandboxLinuxContainerRuntime = new JavaSandboxLinuxContainerRuntime( javaSandboxLinuxContainerRuntime = new JavaSandboxLinuxContainerRuntime(
privilegedOperationExecutor); PrivilegedOperationExecutor.getInstance(conf));
javaSandboxLinuxContainerRuntime.initialize(conf); javaSandboxLinuxContainerRuntime.initialize(conf);
} }
if (isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER)) {
dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime(
PrivilegedOperationExecutor.getInstance(conf));
dockerLinuxContainerRuntime.initialize(conf);
}
if (isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT)) {
defaultLinuxContainerRuntime = new DefaultLinuxContainerRuntime(
PrivilegedOperationExecutor.getInstance(conf));
defaultLinuxContainerRuntime.initialize(conf);
}
}
private LinuxContainerRuntime pickContainerRuntime( @VisibleForTesting
Map<String, String> environment){ LinuxContainerRuntime pickContainerRuntime(
Map<String, String> environment) throws ContainerExecutionException {
LinuxContainerRuntime runtime; LinuxContainerRuntime runtime;
//Sandbox checked first to ensure DockerRuntime doesn't circumvent controls //Sandbox checked first to ensure DockerRuntime doesn't circumvent controls
if (javaSandboxLinuxContainerRuntime.isSandboxContainerRequested()){ if (javaSandboxLinuxContainerRuntime != null &&
javaSandboxLinuxContainerRuntime.isSandboxContainerRequested()){
runtime = javaSandboxLinuxContainerRuntime; runtime = javaSandboxLinuxContainerRuntime;
} else if (DockerLinuxContainerRuntime } else if (dockerLinuxContainerRuntime != null &&
.isDockerContainerRequested(environment)){ DockerLinuxContainerRuntime.isDockerContainerRequested(environment)){
runtime = dockerLinuxContainerRuntime; runtime = dockerLinuxContainerRuntime;
} else { } else if (defaultLinuxContainerRuntime != null &&
!DockerLinuxContainerRuntime.isDockerContainerRequested(environment)) {
runtime = defaultLinuxContainerRuntime; runtime = defaultLinuxContainerRuntime;
} else {
throw new ContainerExecutionException("Requested runtime not allowed.");
} }
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
@ -88,7 +119,8 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
return runtime; return runtime;
} }
private LinuxContainerRuntime pickContainerRuntime(Container container) { private LinuxContainerRuntime pickContainerRuntime(Container container)
throws ContainerExecutionException {
return pickContainerRuntime(container.getLaunchContext().getEnvironment()); return pickContainerRuntime(container.getLaunchContext().getEnvironment());
} }
@ -127,8 +159,15 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
} }
@Override @Override
public String[] getIpAndHost(Container container) { public String[] getIpAndHost(Container container)
throws ContainerExecutionException {
LinuxContainerRuntime runtime = pickContainerRuntime(container); LinuxContainerRuntime runtime = pickContainerRuntime(container);
return runtime.getIpAndHost(container); return runtime.getIpAndHost(container);
} }
@VisibleForTesting
boolean isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType runtimeType) {
return allowedRuntimes.contains(runtimeType);
}
} }

View File

@ -31,6 +31,15 @@ public final class LinuxContainerRuntimeConstants {
private LinuxContainerRuntimeConstants() { private LinuxContainerRuntimeConstants() {
} }
/**
* Linux container runtime types for {@link DelegatingLinuxContainerRuntime}.
*/
public enum RuntimeType {
DEFAULT,
DOCKER,
JAVASANDBOX;
}
public static final Attribute<Map> LOCALIZED_RESOURCES = Attribute public static final Attribute<Map> LOCALIZED_RESOURCES = Attribute
.attribute(Map.class, "localized_resources"); .attribute(Map.class, "localized_resources");
public static final Attribute<List> CONTAINER_LAUNCH_PREFIX_COMMANDS = public static final Attribute<List> CONTAINER_LAUNCH_PREFIX_COMMANDS =

View File

@ -38,6 +38,7 @@ import org.apache.hadoop.yarn.server.nodemanager.Context;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerImpl; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerImpl;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerKillEvent; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerKillEvent;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
import org.apache.hadoop.yarn.server.nodemanager.timelineservice.NMTimelinePublisher; import org.apache.hadoop.yarn.server.nodemanager.timelineservice.NMTimelinePublisher;
import org.apache.hadoop.yarn.server.nodemanager.util.NodeManagerHardwareUtils; import org.apache.hadoop.yarn.server.nodemanager.util.NodeManagerHardwareUtils;
import org.apache.hadoop.yarn.util.ResourceCalculatorPlugin; import org.apache.hadoop.yarn.util.ResourceCalculatorPlugin;
@ -502,7 +503,8 @@ public class ContainersMonitorImpl extends AbstractService implements
* @param entry process tree entry to fill in * @param entry process tree entry to fill in
*/ */
private void initializeProcessTrees( private void initializeProcessTrees(
Entry<ContainerId, ProcessTreeInfo> entry) { Entry<ContainerId, ProcessTreeInfo> entry)
throws ContainerExecutionException {
ContainerId containerId = entry.getKey(); ContainerId containerId = entry.getKey();
ProcessTreeInfo ptInfo = entry.getValue(); ProcessTreeInfo ptInfo = entry.getValue();
String pId = ptInfo.getPID(); String pId = ptInfo.getPID();

View File

@ -77,6 +77,10 @@ public interface ContainerRuntime {
/** /**
* Return the host and ip of the container * Return the host and ip of the container
*
* @param container the {@link Container}
* @throws ContainerExecutionException if an error occurs while getting the ip
* and hostname
*/ */
String[] getIpAndHost(Container container); String[] getIpAndHost(Container container) throws ContainerExecutionException;
} }

View File

@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntime;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
/**
* Test container runtime delegation.
*/
public class TestDelegatingLinuxContainerRuntime {
private DelegatingLinuxContainerRuntime delegatingLinuxContainerRuntime;
private Configuration conf;
private Map<String, String> env = new HashMap<>();
@Before
public void setUp() throws Exception {
delegatingLinuxContainerRuntime = new DelegatingLinuxContainerRuntime();
conf = new Configuration();
env.clear();
}
@Test
public void testIsRuntimeAllowedDefault() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
YarnConfiguration.DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES[0]);
System.out.println(conf.get(
YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES));
delegatingLinuxContainerRuntime.initialize(conf);
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX));
}
@Test
public void testIsRuntimeAllowedDocker() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"docker");
delegatingLinuxContainerRuntime.initialize(conf);
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX));
}
@Test
public void testIsRuntimeAllowedJavaSandbox() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"javasandbox");
delegatingLinuxContainerRuntime.initialize(conf);
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER));
}
@Test
public void testIsRuntimeAllowedMultiple() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"docker,javasandbox");
delegatingLinuxContainerRuntime.initialize(conf);
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER));
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX));
assertFalse(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT));
}
@Test
public void testIsRuntimeAllowedAll() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"default,docker,javasandbox");
delegatingLinuxContainerRuntime.initialize(conf);
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT));
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER));
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX));
}
@Test
public void testJavaSandboxNotAllowedButPermissive() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"default,docker");
conf.set(YarnConfiguration.YARN_CONTAINER_SANDBOX, "permissive");
delegatingLinuxContainerRuntime.initialize(conf);
ContainerRuntime runtime =
delegatingLinuxContainerRuntime.pickContainerRuntime(env);
assertTrue(runtime instanceof DefaultLinuxContainerRuntime);
}
@Test
public void testJavaSandboxNotAllowedButPermissiveDockerRequested()
throws Exception {
env.put(ContainerRuntimeConstants.ENV_CONTAINER_TYPE, "docker");
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"default,docker");
conf.set(YarnConfiguration.YARN_CONTAINER_SANDBOX, "permissive");
delegatingLinuxContainerRuntime.initialize(conf);
ContainerRuntime runtime =
delegatingLinuxContainerRuntime.pickContainerRuntime(env);
assertTrue(runtime instanceof DockerLinuxContainerRuntime);
}
}

View File

@ -71,6 +71,7 @@ request. For example:
The following properties should be set in yarn-site.xml: The following properties should be set in yarn-site.xml:
```xml ```xml
<configuration>
<property> <property>
<name>yarn.nodemanager.container-executor.class</name> <name>yarn.nodemanager.container-executor.class</name>
<value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value> <value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
@ -99,6 +100,16 @@ The following properties should be set in yarn-site.xml:
</description> </description>
</property> </property>
<property>
<name>yarn.nodemanager.runtime.linux.allowed-runtimes</name>
<value>default,docker</value>
<description>
Comma separated list of runtimes that are allowed when using
LinuxContainerExecutor. The allowed values are default, docker, and
javasandbox.
</description>
</property>
<property> <property>
<name>yarn.nodemanager.runtime.linux.docker.allowed-container-networks</name> <name>yarn.nodemanager.runtime.linux.docker.allowed-container-networks</name>
<value>host,none,bridge</value> <value>host,none,bridge</value>
@ -110,18 +121,21 @@ The following properties should be set in yarn-site.xml:
</property> </property>
<property> <property>
<description>The network used when launching Docker containers when no
network is specified in the request. This network must be one of the
(configurable) set of allowed container networks.</description>
<name>yarn.nodemanager.runtime.linux.docker.default-container-network</name> <name>yarn.nodemanager.runtime.linux.docker.default-container-network</name>
<value>host</value> <value>host</value>
<description>
The network used when launching Docker containers when no
network is specified in the request. This network must be one of the
(configurable) set of allowed container networks.
</description>
</property> </property>
<property> <property>
<name>yarn.nodemanager.runtime.linux.docker.privileged-containers.allowed</name> <name>yarn.nodemanager.runtime.linux.docker.privileged-containers.allowed</name>
<value>false</value> <value>false</value>
<description> <description>
Optional. Whether applications are allowed to run in privileged containers. Optional. Whether applications are allowed to run in privileged
containers.
</description> </description>
</property> </property>
@ -133,6 +147,7 @@ The following properties should be set in yarn-site.xml:
privileged contains if privileged containers are allowed. privileged contains if privileged containers are allowed.
</description> </description>
</property> </property>
</configuration>
``` ```
In addition, a container-executer.cfg file must exist and contain settings for In addition, a container-executer.cfg file must exist and contain settings for