YARN-9379. Can't specify docker runtime through environment. Contributed by caozhiqiang

This commit is contained in:
Eric Badger 2019-04-15 18:23:49 +00:00
parent 7fa73fac26
commit 254efc9358
4 changed files with 96 additions and 0 deletions

View File

@ -2030,6 +2030,16 @@ public static boolean isAclEnabled(Configuration conf) {
public static final String DEFAULT_NM_DOCKER_DEFAULT_CONTAINER_NETWORK =
"host";
/** The set of runtimes allowed when launching containers using the
* DockerContainerRuntime. */
public static final String NM_DOCKER_ALLOWED_CONTAINER_RUNTIMES =
DOCKER_CONTAINER_RUNTIME_PREFIX + "allowed-container-runtimes";
/** The set of runtimes allowed when launching containers using the
* DockerContainerRuntime. */
public static final String[] DEFAULT_NM_DOCKER_ALLOWED_CONTAINER_RUNTIMES =
{"runc"};
/** Allow host pid namespace for containers. Use with care. */
public static final String NM_DOCKER_ALLOW_HOST_PID_NAMESPACE =
DOCKER_CONTAINER_RUNTIME_PREFIX + "host-pid-namespace.allowed";

View File

@ -1803,6 +1803,13 @@
<value>host</value>
</property>
<property>
<description>The set of runtimes allowed when launching containers using the
DockerContainerRuntime.</description>
<name>yarn.nodemanager.runtime.linux.docker.allowed-container-runtimes</name>
<value>runc</value>
</property>
<property>
<description>This configuration setting determines whether the host's PID
namespace is allowed for docker containers on this cluster.

View File

@ -265,6 +265,9 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
@InterfaceAudience.Private
public static final String ENV_DOCKER_CONTAINER_YARN_SYSFS =
"YARN_CONTAINER_RUNTIME_YARN_SYSFS_ENABLE";
@InterfaceAudience.Private
public static final String ENV_DOCKER_CONTAINER_DOCKER_RUNTIME =
"YARN_CONTAINER_RUNTIME_DOCKER_RUNTIME";
public static final String YARN_SYSFS_PATH =
"/hadoop/yarn/sysfs";
private Configuration conf;
@ -275,7 +278,9 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
private String defaultImageName;
private Boolean defaultImageUpdate;
private Set<String> allowedNetworks = new HashSet<>();
private Set<String> allowedRuntimes = new HashSet<>();
private String defaultNetwork;
private String defaultRuntime;
private CGroupsHandler cGroupsHandler;
private AccessControlList privilegedContainersAcl;
private boolean enableUserReMapping;
@ -349,6 +354,7 @@ public void initialize(Configuration conf, Context nmContext)
this.conf = conf;
dockerClient = new DockerClient();
allowedNetworks.clear();
allowedRuntimes.clear();
defaultROMounts.clear();
defaultRWMounts.clear();
defaultTmpfsMounts.clear();
@ -363,6 +369,10 @@ public void initialize(Configuration conf, Context nmContext)
defaultNetwork = conf.getTrimmed(
YarnConfiguration.NM_DOCKER_DEFAULT_CONTAINER_NETWORK,
YarnConfiguration.DEFAULT_NM_DOCKER_DEFAULT_CONTAINER_NETWORK);
allowedRuntimes.addAll(Arrays.asList(
conf.getTrimmedStrings(
YarnConfiguration.NM_DOCKER_ALLOWED_CONTAINER_RUNTIMES,
YarnConfiguration.DEFAULT_NM_DOCKER_ALLOWED_CONTAINER_RUNTIMES)));
if(!allowedNetworks.contains(defaultNetwork)) {
String message = "Default network: " + defaultNetwork
@ -529,6 +539,19 @@ private void validateContainerNetworkType(String network)
throw new ContainerExecutionException(msg);
}
private void validateContainerRuntimeType(String runtime)
throws ContainerExecutionException {
if (runtime == null || runtime.isEmpty()
|| allowedRuntimes.contains(runtime)) {
return;
}
String msg = "Disallowed runtime: '" + runtime
+ "' specified. Allowed networks: are " + allowedRuntimes
.toString();
throw new ContainerExecutionException(msg);
}
/**
* Return whether the YARN container is allowed to run using the host's PID
* namespace for the Docker container. For this to be allowed, the submitting
@ -801,6 +824,7 @@ public void launchContainer(ContainerRuntimeContext ctx)
String imageName = environment.get(ENV_DOCKER_CONTAINER_IMAGE);
String network = environment.get(ENV_DOCKER_CONTAINER_NETWORK);
String hostname = environment.get(ENV_DOCKER_CONTAINER_HOSTNAME);
String runtime = environment.get(ENV_DOCKER_CONTAINER_DOCKER_RUNTIME);
boolean useEntryPoint = checkUseEntryPoint(environment);
if (imageName == null || imageName.isEmpty()) {
@ -816,6 +840,8 @@ public void launchContainer(ContainerRuntimeContext ctx)
validateImageName(imageName);
validateContainerRuntimeType(runtime);
if (defaultImageUpdate) {
pullImageFromRemote(containerIdStr, imageName);
}
@ -886,6 +912,9 @@ public void launchContainer(ContainerRuntimeContext ctx)
}
runCommand.setCapabilities(capabilities);
if (runtime != null && !runtime.isEmpty()) {
runCommand.addRuntime(runtime);
}
runCommand.addAllReadWriteMountLocations(containerLogDirs);
runCommand.addAllReadWriteMountLocations(applicationLocalDirs);

View File

@ -2481,6 +2481,56 @@ public void testDockerContainerRelaunch()
dockerCommands.get(counter));
}
@Test
public void testLaunchContainersWithSpecificDockerRuntime()
throws ContainerExecutionException, PrivilegedOperationException,
IOException {
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
mockExecutor, mockCGroupsHandler);
runtime.initialize(conf, nmContext);
env.put(DockerLinuxContainerRuntime
.ENV_DOCKER_CONTAINER_DOCKER_RUNTIME, "runc");
runtime.launchContainer(builder.build());
List<String> dockerCommands = readDockerCommands();
Assert.assertEquals(14, dockerCommands.size());
Assert.assertEquals(" runtime=runc", dockerCommands.get(11));
}
@Test
@SuppressWarnings("unchecked")
public void testContainerLaunchWithAllowedRuntimes()
throws ContainerExecutionException, IOException,
PrivilegedOperationException {
DockerLinuxContainerRuntime runtime =
new DockerLinuxContainerRuntime(mockExecutor, mockCGroupsHandler);
runtime.initialize(conf, nmContext);
String disallowedRuntime = "runc2";
try {
env.put(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_DOCKER_RUNTIME,
disallowedRuntime);
runtime.launchContainer(builder.build());
Assert.fail("Runtime was expected to be disallowed: " +
disallowedRuntime);
} catch (ContainerExecutionException e) {
LOG.info("Caught expected exception: " + e);
}
String allowedRuntime = "runc";
env.put(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_DOCKER_RUNTIME,
allowedRuntime);
//this should cause no failures.
runtime.launchContainer(builder.build());
List<String> dockerCommands = readDockerCommands();
//This is the expected docker invocation for this case
Assert.assertEquals(14, dockerCommands.size());
Assert.assertEquals(" runtime=runc", dockerCommands.get(11));
}
private static void verifyStopCommand(List<String> dockerCommands,
String signal) {
Assert.assertEquals(4, dockerCommands.size());