YARN-4553. Add cgroups support for docker containers. Contributed by Sidharta Seethana.
(cherry picked from commit 3ddb92bd30
)
This commit is contained in:
parent
ffca0ebfff
commit
6220a024b1
|
@ -36,6 +36,9 @@ Release 2.9.0 - UNRELEASED
|
||||||
YARN-4551. Address the duplication between StatusUpdateWhenHealthy and
|
YARN-4551. Address the duplication between StatusUpdateWhenHealthy and
|
||||||
StatusUpdateWhenUnhealthy transitions. (Sunil G via kasha)
|
StatusUpdateWhenUnhealthy transitions. (Sunil G via kasha)
|
||||||
|
|
||||||
|
YARN-4553. Add cgroups support for docker containers.
|
||||||
|
(Sidharta Seethana via vvasudev)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
|
@ -27,6 +27,9 @@ import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
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.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.ContainerExecutionException;
|
||||||
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
|
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
|
||||||
|
|
||||||
|
@ -45,12 +48,19 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
|
||||||
throws ContainerExecutionException {
|
throws ContainerExecutionException {
|
||||||
PrivilegedOperationExecutor privilegedOperationExecutor =
|
PrivilegedOperationExecutor privilegedOperationExecutor =
|
||||||
PrivilegedOperationExecutor.getInstance(conf);
|
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(
|
defaultLinuxContainerRuntime = new DefaultLinuxContainerRuntime(
|
||||||
privilegedOperationExecutor);
|
privilegedOperationExecutor);
|
||||||
defaultLinuxContainerRuntime.initialize(conf);
|
defaultLinuxContainerRuntime.initialize(conf);
|
||||||
dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime(
|
dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime(
|
||||||
privilegedOperationExecutor);
|
privilegedOperationExecutor, cGroupsHandler);
|
||||||
dockerLinuxContainerRuntime.initialize(conf);
|
dockerLinuxContainerRuntime.initialize(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.PrivilegedOperationException;
|
||||||
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.linux.resources.CGroupsHandler;
|
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.DockerClient;
|
||||||
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerRunCommand;
|
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.ContainerExecutionException;
|
||||||
|
@ -76,6 +74,7 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
||||||
private Configuration conf;
|
private Configuration conf;
|
||||||
private DockerClient dockerClient;
|
private DockerClient dockerClient;
|
||||||
private PrivilegedOperationExecutor privilegedOperationExecutor;
|
private PrivilegedOperationExecutor privilegedOperationExecutor;
|
||||||
|
private CGroupsHandler cGroupsHandler;
|
||||||
private AccessControlList privilegedContainersAcl;
|
private AccessControlList privilegedContainersAcl;
|
||||||
|
|
||||||
public static boolean isDockerContainerRequested(
|
public static boolean isDockerContainerRequested(
|
||||||
|
@ -90,8 +89,9 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DockerLinuxContainerRuntime(PrivilegedOperationExecutor
|
public DockerLinuxContainerRuntime(PrivilegedOperationExecutor
|
||||||
privilegedOperationExecutor) {
|
privilegedOperationExecutor, CGroupsHandler cGroupsHandler) {
|
||||||
this.privilegedOperationExecutor = privilegedOperationExecutor;
|
this.privilegedOperationExecutor = privilegedOperationExecutor;
|
||||||
|
this.cGroupsHandler = cGroupsHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,30 +116,23 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
||||||
if (resourcesOptions.equals(
|
if (resourcesOptions.equals(
|
||||||
(PrivilegedOperation.CGROUP_ARG_PREFIX + PrivilegedOperation
|
(PrivilegedOperation.CGROUP_ARG_PREFIX + PrivilegedOperation
|
||||||
.CGROUP_ARG_NO_TASKS))) {
|
.CGROUP_ARG_NO_TASKS))) {
|
||||||
if (LOG.isInfoEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.info("no resource restrictions specified. not using docker's "
|
LOG.debug("no resource restrictions specified. not using docker's "
|
||||||
+ "cgroup options");
|
+ "cgroup options");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (LOG.isInfoEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.info("using docker's cgroups options");
|
LOG.debug("using docker's cgroups options");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
String cGroupPath = "/" + cGroupsHandler.getRelativePathForCGroup(
|
||||||
CGroupsHandler cGroupsHandler = ResourceHandlerModule
|
containerIdStr);
|
||||||
.getCGroupsHandler(conf);
|
|
||||||
String cGroupPath = "/" + cGroupsHandler.getRelativePathForCGroup(
|
|
||||||
containerIdStr);
|
|
||||||
|
|
||||||
if (LOG.isInfoEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.info("using cgroup parent: " + cGroupPath);
|
LOG.debug("using cgroup parent: " + cGroupPath);
|
||||||
}
|
|
||||||
|
|
||||||
runCommand.setCGroupParent(cGroupPath);
|
|
||||||
} catch (ResourceHandlerException e) {
|
|
||||||
LOG.warn("unable to use cgroups handler. Exception: ", e);
|
|
||||||
throw new ContainerExecutionException(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runCommand.setCGroupParent(cGroupPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,11 +249,7 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
||||||
|
|
||||||
String resourcesOpts = ctx.getExecutionAttribute(RESOURCES_OPTIONS);
|
String resourcesOpts = ctx.getExecutionAttribute(RESOURCES_OPTIONS);
|
||||||
|
|
||||||
/** Disabling docker's cgroup parent support for the time being. Docker
|
addCGroupParentIfRequired(resourcesOpts, containerIdStr, runCommand);
|
||||||
* 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);
|
|
||||||
|
|
||||||
Path nmPrivateContainerScriptPath = ctx.getExecutionAttribute(
|
Path nmPrivateContainerScriptPath = ctx.getExecutionAttribute(
|
||||||
NM_PRIVATE_CONTAINER_SCRIPT_PATH);
|
NM_PRIVATE_CONTAINER_SCRIPT_PATH);
|
||||||
|
|
|
@ -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.PrivilegedOperation;
|
||||||
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationException;
|
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.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.ContainerExecutionException;
|
||||||
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants;
|
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants;
|
||||||
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
|
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeContext;
|
||||||
|
@ -62,6 +64,7 @@ public class TestDockerContainerRuntime {
|
||||||
.getLog(TestDockerContainerRuntime.class);
|
.getLog(TestDockerContainerRuntime.class);
|
||||||
private Configuration conf;
|
private Configuration conf;
|
||||||
PrivilegedOperationExecutor mockExecutor;
|
PrivilegedOperationExecutor mockExecutor;
|
||||||
|
CGroupsHandler mockCGroupsHandler;
|
||||||
String containerId;
|
String containerId;
|
||||||
Container container;
|
Container container;
|
||||||
ContainerId cId;
|
ContainerId cId;
|
||||||
|
@ -94,6 +97,7 @@ public class TestDockerContainerRuntime {
|
||||||
|
|
||||||
mockExecutor = Mockito
|
mockExecutor = Mockito
|
||||||
.mock(PrivilegedOperationExecutor.class);
|
.mock(PrivilegedOperationExecutor.class);
|
||||||
|
mockCGroupsHandler = Mockito.mock(CGroupsHandler.class);
|
||||||
containerId = "container_id";
|
containerId = "container_id";
|
||||||
container = mock(Container.class);
|
container = mock(Container.class);
|
||||||
cId = mock(ContainerId.class);
|
cId = mock(ContainerId.class);
|
||||||
|
@ -118,7 +122,7 @@ public class TestDockerContainerRuntime {
|
||||||
pidFilePath = new Path("/test_pid_file_path");
|
pidFilePath = new Path("/test_pid_file_path");
|
||||||
localDirs = new ArrayList<>();
|
localDirs = new ArrayList<>();
|
||||||
logDirs = new ArrayList<>();
|
logDirs = new ArrayList<>();
|
||||||
resourcesOptions = "cgroups:none";
|
resourcesOptions = "cgroups=none";
|
||||||
|
|
||||||
localDirs.add("/test_local_dir");
|
localDirs.add("/test_local_dir");
|
||||||
logDirs.add("/test_log_dir");
|
logDirs.add("/test_log_dir");
|
||||||
|
@ -204,7 +208,7 @@ public class TestDockerContainerRuntime {
|
||||||
throws ContainerExecutionException, PrivilegedOperationException,
|
throws ContainerExecutionException, PrivilegedOperationException,
|
||||||
IOException {
|
IOException {
|
||||||
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
||||||
mockExecutor);
|
mockExecutor, mockCGroupsHandler);
|
||||||
runtime.initialize(conf);
|
runtime.initialize(conf);
|
||||||
|
|
||||||
String[] testCapabilities = {"NET_BIND_SERVICE", "SYS_CHROOT"};
|
String[] testCapabilities = {"NET_BIND_SERVICE", "SYS_CHROOT"};
|
||||||
|
@ -256,7 +260,7 @@ public class TestDockerContainerRuntime {
|
||||||
throws ContainerExecutionException, PrivilegedOperationException,
|
throws ContainerExecutionException, PrivilegedOperationException,
|
||||||
IOException{
|
IOException{
|
||||||
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
||||||
mockExecutor);
|
mockExecutor, mockCGroupsHandler);
|
||||||
runtime.initialize(conf);
|
runtime.initialize(conf);
|
||||||
|
|
||||||
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
||||||
|
@ -284,7 +288,7 @@ public class TestDockerContainerRuntime {
|
||||||
throws ContainerExecutionException, PrivilegedOperationException,
|
throws ContainerExecutionException, PrivilegedOperationException,
|
||||||
IOException{
|
IOException{
|
||||||
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
||||||
mockExecutor);
|
mockExecutor, mockCGroupsHandler);
|
||||||
runtime.initialize(conf);
|
runtime.initialize(conf);
|
||||||
|
|
||||||
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
||||||
|
@ -307,7 +311,7 @@ public class TestDockerContainerRuntime {
|
||||||
true);
|
true);
|
||||||
|
|
||||||
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
||||||
mockExecutor);
|
mockExecutor, mockCGroupsHandler);
|
||||||
runtime.initialize(conf);
|
runtime.initialize(conf);
|
||||||
|
|
||||||
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
||||||
|
@ -338,7 +342,7 @@ public class TestDockerContainerRuntime {
|
||||||
whitelistedUser);
|
whitelistedUser);
|
||||||
|
|
||||||
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
||||||
mockExecutor);
|
mockExecutor, mockCGroupsHandler);
|
||||||
runtime.initialize(conf);
|
runtime.initialize(conf);
|
||||||
|
|
||||||
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
||||||
|
@ -365,7 +369,7 @@ public class TestDockerContainerRuntime {
|
||||||
submittingUser);
|
submittingUser);
|
||||||
|
|
||||||
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
DockerLinuxContainerRuntime runtime = new DockerLinuxContainerRuntime(
|
||||||
mockExecutor);
|
mockExecutor, mockCGroupsHandler);
|
||||||
runtime.initialize(conf);
|
runtime.initialize(conf);
|
||||||
|
|
||||||
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
env.put("YARN_CONTAINER_RUNTIME_DOCKER_RUN_PRIVILEGED_CONTAINER",
|
||||||
|
@ -388,4 +392,34 @@ public class TestDockerContainerRuntime {
|
||||||
+ ": " + command, command.contains("--privileged"));
|
+ ": " + 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue