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 static boolean isAclEnabled(Configuration conf) {
/** 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.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 void activateContainer(ContainerId containerId, Path pidFilePath) {
} }
// 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 int launchContainer(ContainerStartContext ctx)
} }
@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.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 {
allowedRuntimes.add(
LinuxContainerRuntimeConstants.RuntimeType.valueOf(
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( dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime(
privilegedOperationExecutor); PrivilegedOperationExecutor.getInstance(conf));
dockerLinuxContainerRuntime.initialize(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 @@ private LinuxContainerRuntime pickContainerRuntime(Container container) {
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 void reapContainer(ContainerRuntimeContext ctx)
} }
@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 @@ void reapContainer(ContainerRuntimeContext ctx)
/** /**
* 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,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,15 @@ 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 and docker.
</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 +120,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 +146,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