diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index 5e8add245fe..f7c22b3ee7d 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -94,6 +94,9 @@ Release 2.9.0 - UNRELEASED YARN-4551. Address the duplication between StatusUpdateWhenHealthy and StatusUpdateWhenUnhealthy transitions. (Sunil G via kasha) + YARN-4553. Add cgroups support for docker containers. + (Sidharta Seethana via vvasudev) + OPTIMIZATIONS BUG FIXES 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/DelegatingLinuxContainerRuntime.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/DelegatingLinuxContainerRuntime.java index a59415fff3f..7adba4d8bc9 100644 --- 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/DelegatingLinuxContainerRuntime.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/DelegatingLinuxContainerRuntime.java @@ -27,6 +27,9 @@ import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.conf.Configuration; 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.resources.CGroupsHandler; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerException; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerModule; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext; @@ -45,12 +48,19 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime { throws ContainerExecutionException { PrivilegedOperationExecutor privilegedOperationExecutor = PrivilegedOperationExecutor.getInstance(conf); + CGroupsHandler cGroupsHandler; + try { + cGroupsHandler = ResourceHandlerModule.getCGroupsHandler(conf); + } catch (ResourceHandlerException e) { + LOG.error("Unable to get cgroups handle."); + throw new ContainerExecutionException(e); + } defaultLinuxContainerRuntime = new DefaultLinuxContainerRuntime( privilegedOperationExecutor); defaultLinuxContainerRuntime.initialize(conf); dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime( - privilegedOperationExecutor); + privilegedOperationExecutor, cGroupsHandler); dockerLinuxContainerRuntime.initialize(conf); } 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/DockerLinuxContainerRuntime.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/DockerLinuxContainerRuntime.java index 9ad04a8dbe4..f8aae81c7f4 100644 --- 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/DockerLinuxContainerRuntime.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/DockerLinuxContainerRuntime.java @@ -36,8 +36,6 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileg import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerException; -import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerModule; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerClient; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerRunCommand; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException; @@ -76,6 +74,7 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { private Configuration conf; private DockerClient dockerClient; private PrivilegedOperationExecutor privilegedOperationExecutor; + private CGroupsHandler cGroupsHandler; private AccessControlList privilegedContainersAcl; public static boolean isDockerContainerRequested( @@ -90,8 +89,9 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { } public DockerLinuxContainerRuntime(PrivilegedOperationExecutor - privilegedOperationExecutor) { + privilegedOperationExecutor, CGroupsHandler cGroupsHandler) { this.privilegedOperationExecutor = privilegedOperationExecutor; + this.cGroupsHandler = cGroupsHandler; } @Override @@ -116,30 +116,23 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { if (resourcesOptions.equals( (PrivilegedOperation.CGROUP_ARG_PREFIX + PrivilegedOperation .CGROUP_ARG_NO_TASKS))) { - if (LOG.isInfoEnabled()) { - LOG.info("no resource restrictions specified. not using docker's " + if (LOG.isDebugEnabled()) { + LOG.debug("no resource restrictions specified. not using docker's " + "cgroup options"); } } else { - if (LOG.isInfoEnabled()) { - LOG.info("using docker's cgroups options"); + if (LOG.isDebugEnabled()) { + LOG.debug("using docker's cgroups options"); } - try { - CGroupsHandler cGroupsHandler = ResourceHandlerModule - .getCGroupsHandler(conf); - String cGroupPath = "/" + cGroupsHandler.getRelativePathForCGroup( - containerIdStr); + String cGroupPath = "/" + cGroupsHandler.getRelativePathForCGroup( + containerIdStr); - if (LOG.isInfoEnabled()) { - LOG.info("using cgroup parent: " + cGroupPath); - } - - runCommand.setCGroupParent(cGroupPath); - } catch (ResourceHandlerException e) { - LOG.warn("unable to use cgroups handler. Exception: ", e); - throw new ContainerExecutionException(e); + if (LOG.isDebugEnabled()) { + LOG.debug("using cgroup parent: " + cGroupPath); } + + runCommand.setCGroupParent(cGroupPath); } } @@ -256,11 +249,7 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime { String resourcesOpts = ctx.getExecutionAttribute(RESOURCES_OPTIONS); - /** Disabling docker's cgroup parent support for the time being. Docker - * needs to use a more recent libcontainer that supports net_cls. In - * addition we also need to revisit current cgroup creation in YARN. - */ - //addCGroupParentIfRequired(resourcesOpts, containerIdStr, runCommand); + addCGroupParentIfRequired(resourcesOpts, containerIdStr, runCommand); Path nmPrivateContainerScriptPath = ctx.getExecutionAttribute( NM_PRIVATE_CONTAINER_SCRIPT_PATH); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java index 417689fc75c..7fc0158b600 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java @@ -31,6 +31,8 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Cont import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerRunCommand; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext; @@ -62,6 +64,7 @@ public class TestDockerContainerRuntime { .getLog(TestDockerContainerRuntime.class); private Configuration conf; PrivilegedOperationExecutor mockExecutor; + CGroupsHandler mockCGroupsHandler; String containerId; Container container; ContainerId cId; @@ -94,6 +97,7 @@ public class TestDockerContainerRuntime { mockExecutor = Mockito .mock(PrivilegedOperationExecutor.class); + mockCGroupsHandler = Mockito.mock(CGroupsHandler.class); containerId = "container_id"; container = mock(Container.class); cId = mock(ContainerId.class); @@ -118,7 +122,7 @@ public class TestDockerContainerRuntime { pidFilePath = new Path("/test_pid_file_path"); localDirs = new ArrayList<>(); logDirs = new ArrayList<>(); - resourcesOptions = "cgroups:none"; + resourcesOptions = "cgroups=none"; localDirs.add("/test_local_dir"); logDirs.add("/test_log_dir"); @@ -204,7 +208,7 @@ public class TestDockerContainerRuntime { throws ContainerExecutionException, PrivilegedOperationException, IOException { DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( - mockExecutor); + mockExecutor, mockCGroupsHandler); runtime.initialize(conf); String[] testCapabilities = {"NET_BIND_SERVICE", "SYS_CHROOT"}; @@ -256,7 +260,7 @@ public class TestDockerContainerRuntime { throws ContainerExecutionException, PrivilegedOperationException, IOException{ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( - mockExecutor); + mockExecutor, mockCGroupsHandler); runtime.initialize(conf); env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER", @@ -284,7 +288,7 @@ public class TestDockerContainerRuntime { throws ContainerExecutionException, PrivilegedOperationException, IOException{ DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( - mockExecutor); + mockExecutor, mockCGroupsHandler); runtime.initialize(conf); env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER", @@ -307,7 +311,7 @@ public class TestDockerContainerRuntime { true); DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( - mockExecutor); + mockExecutor, mockCGroupsHandler); runtime.initialize(conf); env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER", @@ -338,7 +342,7 @@ public class TestDockerContainerRuntime { whitelistedUser); DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( - mockExecutor); + mockExecutor, mockCGroupsHandler); runtime.initialize(conf); env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER", @@ -365,7 +369,7 @@ public class TestDockerContainerRuntime { submittingUser); DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime( - mockExecutor); + mockExecutor, mockCGroupsHandler); runtime.initialize(conf); env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER", @@ -388,4 +392,34 @@ public class TestDockerContainerRuntime { + ": " + command, command.contains("--privileged")); } + @Test + public void testCGroupParent() throws ContainerExecutionException { + String hierarchy = "hadoop-yarn-test"; + conf.set(YarnConfiguration.NM_LINUX_CONTAINER_CGROUPS_HIERARCHY, + hierarchy); + + DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime + (mockExecutor, mockCGroupsHandler); + runtime.initialize(conf); + + String resourceOptionsNone = "cgroups=none"; + DockerRunCommand command = Mockito.mock(DockerRunCommand.class); + + Mockito.when(mockCGroupsHandler.getRelativePathForCGroup(containerId)) + .thenReturn(hierarchy + "/" + containerIdStr); + runtime.addCGroupParentIfRequired(resourceOptionsNone, containerIdStr, + command); + + //no --cgroup-parent should be added here + Mockito.verifyZeroInteractions(command); + + String resourceOptionsCpu = "/sys/fs/cgroup/cpu/" + hierarchy + + containerIdStr; + runtime.addCGroupParentIfRequired(resourceOptionsCpu, containerIdStr, + command); + + //--cgroup-parent should be added for the containerId in question + String expectedPath = "/" + hierarchy + "/" + containerIdStr; + Mockito.verify(command).setCGroupParent(expectedPath); + } }