diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
index be4c0232035..974dcae42e1 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java
@@ -1238,6 +1238,24 @@ private static void addDeprecatedKeys() {
/** Default list for users allowed to run privileged containers is empty. */
public static final String DEFAULT_NM_DOCKER_PRIVILEGED_CONTAINERS_ACL = "";
+ /** The list of allowed images when launching container using the
+ * DockerContainerRuntime
+ */
+ public static final String NM_DOCKER_ALLOWED_IMAGES =
+ DOCKER_CONTAINER_RUNTIME_PREFIX + "allowed-images";
+
+ /** The default allowed images to be used when using the
+ * DockerContainerRuntime
+ */
+ public static final String[] NM_DOCKER_DEFAULT_ALLOWED_IMAGES =
+ {""};
+
+ /** The image used when launching container using the
+ * DockerContainerRuntime
+ */
+ public static final String NM_DOCKER_IMAGE_NAME =
+ DOCKER_CONTAINER_RUNTIME_PREFIX + "image-name";
+
/** The path to the Linux container executor.*/
public static final String NM_LINUX_CONTAINER_EXECUTOR_PATH =
NM_PREFIX + "linux-container-executor.path";
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
index 881ca8e3590..98bdc94e9b8 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml
@@ -1493,6 +1493,13 @@
+
+ The list of allowed images when launching container using the
+ DockerContainerRuntime
+ yarn.nodemanager.runtime.linux.docker.allowed-images
+
+
+
This flag determines whether memory limit will be set for the Windows Job
Object of the containers launched by the default container executor.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
index e39592b5289..9c5cb2443e3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
@@ -40,6 +40,7 @@
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerModule;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DelegatingLinuxContainerRuntime;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.LinuxContainerRuntime;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.NodeSpecificLinuxContainerRuntime;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ContainerLocalizer;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
@@ -199,7 +200,7 @@ public void init() throws IOException {
try {
if (linuxContainerRuntime == null) {
- LinuxContainerRuntime runtime = new DelegatingLinuxContainerRuntime();
+ LinuxContainerRuntime runtime = new NodeSpecificLinuxContainerRuntime();
runtime.initialize(conf);
this.linuxContainerRuntime = runtime;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/NodeSpecificLinuxContainerRuntime.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/NodeSpecificLinuxContainerRuntime.java
new file mode 100644
index 00000000000..c49d3518e46
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/NodeSpecificLinuxContainerRuntime.java
@@ -0,0 +1,154 @@
+/*
+ * 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.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+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.ContainerRuntimeContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class NodeSpecificLinuxContainerRuntime implements LinuxContainerRuntime {
+ private static final Logger LOG = LoggerFactory.getLogger(
+ NodeSpecificLinuxContainerRuntime.class);
+ private boolean isDockerSupported;
+ private String defaultDockerImage;
+ private LinuxContainerRuntime linuxContainerRuntime;
+ private EnumSet allowedRuntimes =
+ EnumSet.noneOf(LinuxContainerRuntimeConstants.RuntimeType.class);
+ private Set allowedImages = new HashSet<>();
+
+ @Override
+ public void initialize(Configuration conf)
+ throws ContainerExecutionException {
+ String[] configuredRuntimes = conf.getTrimmedStrings(
+ YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
+ YarnConfiguration.DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES);
+ for (String configuredRuntime : configuredRuntimes) {
+ 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);
+ }
+ }
+
+ PrivilegedOperationExecutor privilegedOperationExecutor =
+ PrivilegedOperationExecutor.getInstance(conf);
+ isDockerSupported = new File("/usr/bin/docker").exists();
+ if(isDockerSupported && isRuntimeAllowed(LinuxContainerRuntimeConstants.RuntimeType.DOCKER)) {
+ linuxContainerRuntime = new DockerLinuxContainerRuntime(
+ privilegedOperationExecutor);
+ allowedImages.addAll(Arrays.asList(
+ conf.getStrings(YarnConfiguration.NM_DOCKER_ALLOWED_IMAGES,
+ YarnConfiguration.NM_DOCKER_DEFAULT_ALLOWED_IMAGES)));
+ defaultDockerImage = conf.get(YarnConfiguration.NM_DOCKER_IMAGE_NAME);
+ if(!allowedImages.contains(defaultDockerImage)) {
+ String message = "Default Docker Image: " + defaultDockerImage
+ + " is not in the set of allowed images: " + allowedImages
+ + ". Please check configuration";
+ LOG.warn(message);
+ throw new ContainerExecutionException(message);
+ }
+ } else if (isRuntimeAllowed(LinuxContainerRuntimeConstants.RuntimeType.DEFAULT)) {
+ linuxContainerRuntime = new DefaultLinuxContainerRuntime(
+ privilegedOperationExecutor);
+ }
+
+ if(linuxContainerRuntime == null) {
+ throw new ContainerExecutionException("linuxContainerRuntime not set. " +
+ "No allowed container runtimes available");
+ }
+ LOG.info("Using container runtime: " + linuxContainerRuntime.getClass()
+ .getSimpleName());
+ linuxContainerRuntime.initialize(conf);
+ }
+
+ private LinuxContainerRuntime pickContainerRuntime() {
+ return linuxContainerRuntime;
+ }
+
+ @Override
+ public void prepareContainer(ContainerRuntimeContext ctx)
+ throws ContainerExecutionException {
+ LinuxContainerRuntime runtime = pickContainerRuntime();
+ runtime.prepareContainer(ctx);
+ }
+
+ @Override
+ public void launchContainer(ContainerRuntimeContext ctx)
+ throws ContainerExecutionException {
+ LinuxContainerRuntime runtime = pickContainerRuntime();
+ if(runtime.getClass() == DockerLinuxContainerRuntime.class) {
+ Map env = ctx.getContainer().getLaunchContext().getEnvironment();
+ String dockerImage = env.get(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_IMAGE);
+ if (dockerImage != null && !dockerImage.isEmpty()) {
+ if(!allowedImages.contains(dockerImage)) {
+ throw new ContainerExecutionException(
+ "User-defined Docker Image: " + dockerImage
+ + " is not in the set of allowed images: " + allowedImages);
+ }
+ } else {
+ env.put(DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_IMAGE,
+ defaultDockerImage);
+ }
+ }
+ runtime.launchContainer(ctx);
+ }
+
+ @Override
+ public void signalContainer(ContainerRuntimeContext ctx)
+ throws ContainerExecutionException {
+ LinuxContainerRuntime runtime = pickContainerRuntime();
+ runtime.signalContainer(ctx);
+ }
+
+ @Override
+ public void reapContainer(ContainerRuntimeContext ctx)
+ throws ContainerExecutionException {
+ LinuxContainerRuntime runtime = pickContainerRuntime();
+ runtime.reapContainer(ctx);
+ }
+
+ @Override
+ public boolean useWhitelistEnv(Map env) {
+ return linuxContainerRuntime.useWhitelistEnv(env);
+ }
+
+ boolean isRuntimeAllowed(
+ LinuxContainerRuntimeConstants.RuntimeType runtimeType) {
+ return allowedRuntimes.contains(runtimeType);
+ }
+}