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-10-11 09:57:49 -05:00
parent 108c2394c3
commit 5c4f269b26
5 changed files with 163 additions and 18 deletions

View File

@ -1180,6 +1180,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

@ -1460,6 +1460,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

@ -20,16 +20,19 @@
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.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
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;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
import java.util.EnumSet;
import java.util.Map; import java.util.Map;
@InterfaceAudience.Private @InterfaceAudience.Private
@ -39,42 +42,70 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
.getLog(DelegatingLinuxContainerRuntime.class); .getLog(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,
YarnConfiguration.DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES);
defaultLinuxContainerRuntime = new DefaultLinuxContainerRuntime( for (String configuredRuntime : configuredRuntimes) {
privilegedOperationExecutor); try {
defaultLinuxContainerRuntime.initialize(conf); allowedRuntimes.add(
dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime( LinuxContainerRuntimeConstants.RuntimeType.valueOf(
privilegedOperationExecutor); configuredRuntime.toUpperCase()));
dockerLinuxContainerRuntime.initialize(conf); } 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);
}
} }
@Override @Override
public boolean useWhitelistEnv(Map<String, String> env) { public boolean useWhitelistEnv(Map<String, String> env) {
LinuxContainerRuntime runtime = pickContainerRuntime(env); try {
return runtime.useWhitelistEnv(env); LinuxContainerRuntime runtime = pickContainerRuntime(env);
return runtime.useWhitelistEnv(env);
} catch (ContainerExecutionException e) {
LOG.debug("Unable to determine runtime");
return false;
}
} }
private LinuxContainerRuntime pickContainerRuntime(Container container) { private LinuxContainerRuntime pickContainerRuntime(Container container)
throws ContainerExecutionException {
return pickContainerRuntime(container.getLaunchContext().getEnvironment()); return pickContainerRuntime(container.getLaunchContext().getEnvironment());
} }
private LinuxContainerRuntime pickContainerRuntime(Map<String, String> env) { @VisibleForTesting
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.isInfoEnabled()) { if (LOG.isDebugEnabled()) {
LOG.info("Using container runtime: " + runtime.getClass() LOG.debug("Using container runtime: " + runtime.getClass()
.getSimpleName()); .getSimpleName());
} }
@ -116,4 +147,10 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
runtime.reapContainer(ctx); runtime.reapContainer(ctx);
} }
@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

@ -0,0 +1,76 @@
/*
* 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;
@Before
public void setUp() throws Exception {
delegatingLinuxContainerRuntime = new DelegatingLinuxContainerRuntime();
conf = new Configuration();
}
@Test
public void testIsRuntimeAllowedDefault() throws Exception {
conf.set(YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
YarnConfiguration.DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES[0]);
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));
}
}