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

This commit is contained in:
Jason Lowe 2017-09-07 16:24:55 -05:00
parent ef342455cb
commit c004d57d47
9 changed files with 243 additions and 73 deletions

View File

@ -1423,6 +1423,22 @@ 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>
* </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

@ -1537,6 +1537,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 and docker.
</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

@ -52,6 +52,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.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;
import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerReacquisitionContext; import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerReacquisitionContext;
@ -656,7 +657,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

@ -600,7 +600,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;
/** /**
@ -49,28 +52,50 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
LoggerFactory.getLogger(DelegatingLinuxContainerRuntime.class); LoggerFactory.getLogger(DelegatingLinuxContainerRuntime.class);
private DefaultLinuxContainerRuntime defaultLinuxContainerRuntime; private DefaultLinuxContainerRuntime defaultLinuxContainerRuntime;
private DockerLinuxContainerRuntime dockerLinuxContainerRuntime; private DockerLinuxContainerRuntime dockerLinuxContainerRuntime;
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.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(Container container) { @VisibleForTesting
Map<String, String> env = container.getLaunchContext().getEnvironment(); LinuxContainerRuntime pickContainerRuntime(
Map<String, String> environment) throws ContainerExecutionException {
LinuxContainerRuntime runtime; LinuxContainerRuntime runtime;
if (dockerLinuxContainerRuntime != null &&
if (DockerLinuxContainerRuntime.isDockerContainerRequested(env)){ 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()) {
@ -81,6 +106,11 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
return runtime; return runtime;
} }
private LinuxContainerRuntime pickContainerRuntime(Container container)
throws ContainerExecutionException {
return pickContainerRuntime(container.getLaunchContext().getEnvironment());
}
@Override @Override
public void prepareContainer(ContainerRuntimeContext ctx) public void prepareContainer(ContainerRuntimeContext ctx)
throws ContainerExecutionException { throws ContainerExecutionException {
@ -118,8 +148,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,14 @@ public final class LinuxContainerRuntimeConstants {
private LinuxContainerRuntimeConstants() { private LinuxContainerRuntimeConstants() {
} }
/**
* Linux container runtime types for {@link DelegatingLinuxContainerRuntime}.
*/
public enum RuntimeType {
DEFAULT,
DOCKER;
}
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

@ -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,80 @@
/*
* 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.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));
}
@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));
}
@Test
public void testIsRuntimeAllowedMultiple() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
"default,docker");
delegatingLinuxContainerRuntime.initialize(conf);
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DOCKER));
assertTrue(delegatingLinuxContainerRuntime.isRuntimeAllowed(
LinuxContainerRuntimeConstants.RuntimeType.DEFAULT));
}
}

View File

@ -71,68 +71,82 @@ 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
<property> <configuration>
<name>yarn.nodemanager.container-executor.class</name> <property>
<value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value> <name>yarn.nodemanager.container-executor.class</name>
<description> <value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
This is the container executor setting that ensures that all applications <description>
are started with the LinuxContainerExecutor. This is the container executor setting that ensures that all applications
</description> are started with the LinuxContainerExecutor.
</property> </description>
</property>
<property> <property>
<name>yarn.nodemanager.linux-container-executor.group</name> <name>yarn.nodemanager.linux-container-executor.group</name>
<value>hadoop</value> <value>hadoop</value>
<description> <description>
The POSIX group of the NodeManager. It should match the setting in The POSIX group of the NodeManager. It should match the setting in
"container-executor.cfg". This configuration is required for validating "container-executor.cfg". This configuration is required for validating
the secure access of the container-executor binary. the secure access of the container-executor binary.
</description> </description>
</property> </property>
<property> <property>
<name>yarn.nodemanager.linux-container-executor.nonsecure-mode.limit-users</name> <name>yarn.nodemanager.linux-container-executor.nonsecure-mode.limit-users</name>
<value>false</value> <value>false</value>
<description> <description>
Whether all applications should be run as the NodeManager process' owner. Whether all applications should be run as the NodeManager process' owner.
When false, applications are launched instead as the application owner. When false, applications are launched instead as the application owner.
</description> </description>
</property> </property>
<property> <property>
<name>yarn.nodemanager.runtime.linux.docker.allowed-container-networks</name> <name>yarn.nodemanager.runtime.linux.allowed-runtimes</name>
<value>host,none,bridge</value> <value>default,docker</value>
<description> <description>
Optional. A comma-separated set of networks allowed when launching Comma separated list of runtimes that are allowed when using
containers. Valid values are determined by Docker networks available from LinuxContainerExecutor. The allowed values are default and docker.
`docker network ls` </description>
</description> </property>
</property>
<property> <property>
<description>The network used when launching Docker containers when no <name>yarn.nodemanager.runtime.linux.docker.allowed-container-networks</name>
network is specified in the request. This network must be one of the <value>host,none,bridge</value>
(configurable) set of allowed container networks.</description> <description>
<name>yarn.nodemanager.runtime.linux.docker.default-container-network</name> Optional. A comma-separated set of networks allowed when launching
<value>host</value> containers. Valid values are determined by Docker networks available from
</property> `docker network ls`
</description>
</property>
<property> <property>
<name>yarn.nodemanager.runtime.linux.docker.privileged-containers.allowed</name> <name>yarn.nodemanager.runtime.linux.docker.default-container-network</name>
<value>false</value> <value>host</value>
<description> <description>
Optional. Whether applications are allowed to run in privileged containers. The network used when launching Docker containers when no
</description> network is specified in the request. This network must be one of the
</property> (configurable) set of allowed container networks.
</description>
</property>
<property> <property>
<name>yarn.nodemanager.runtime.linux.docker.privileged-containers.acl</name> <name>yarn.nodemanager.runtime.linux.docker.privileged-containers.allowed</name>
<value></value> <value>false</value>
<description> <description>
Optional. A comma-separated list of users who are allowed to request Optional. Whether applications are allowed to run in privileged
privileged contains if privileged containers are allowed. containers.
</description> </description>
</property> </property>
<property>
<name>yarn.nodemanager.runtime.linux.docker.privileged-containers.acl</name>
<value></value>
<description>
Optional. A comma-separated list of users who are allowed to request
privileged contains if privileged containers are allowed.
</description>
</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