You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by qi...@apache.org on 2020/05/05 08:12:57 UTC
[mesos] 05/05: Updated Docker containerizer's `usage()` to support
resource limits.
This is an automated email from the ASF dual-hosted git repository.
qianzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 95b806474da6f63ec8d50904a4336f903c0c5d08
Author: Qian Zhang <zh...@gmail.com>
AuthorDate: Tue Apr 21 09:30:26 2020 +0800
Updated Docker containerizer's `usage()` to support resource limits.
Review: https://reviews.apache.org/r/72402
---
src/slave/containerizer/docker.cpp | 105 +++++++++++++++++++--
.../containerizer/docker_containerizer_tests.cpp | 25 +++--
2 files changed, 116 insertions(+), 14 deletions(-)
diff --git a/src/slave/containerizer/docker.cpp b/src/slave/containerizer/docker.cpp
index 8aed025..431f7c6 100644
--- a/src/slave/containerizer/docker.cpp
+++ b/src/slave/containerizer/docker.cpp
@@ -2082,16 +2082,105 @@ Future<ResourceStatistics> DockerContainerizerProcess::usage(
result = cgroupStats.get();
#endif // __linux__
- // Set the resource allocations.
- const Resources& resource = container->resourceRequests;
- const Option<Bytes> mem = resource.mem();
- if (mem.isSome()) {
- result.set_mem_limit_bytes(mem->bytes());
+ Option<double> cpuRequest, cpuLimit, memLimit;
+ Option<Bytes> memRequest;
+
+ // For command tasks, we should subtract the default resources (0.1 cpus and
+ // 32MB memory) for command executor from the container's resource requests
+ // and limits, otherwise we would report wrong resource statistics.
+ if (container->resourceRequests.cpus().isSome()) {
+ if (container->generatedForCommandTask) {
+ cpuRequest =
+ container->resourceRequests.cpus().get() - DEFAULT_EXECUTOR_CPUS;
+ } else {
+ cpuRequest = container->resourceRequests.cpus();
+ }
+ }
+
+ if (container->resourceRequests.mem().isSome()) {
+ if (container->generatedForCommandTask) {
+ memRequest =
+ container->resourceRequests.mem().get() - DEFAULT_EXECUTOR_MEM;
+ } else {
+ memRequest = container->resourceRequests.mem();
+ }
+ }
+
+ foreach (auto&& limit, container->resourceLimits) {
+ if (limit.first == "cpus") {
+ if (container->generatedForCommandTask &&
+ !std::isinf(limit.second.value())) {
+ cpuLimit = limit.second.value() - DEFAULT_EXECUTOR_CPUS;
+ } else {
+ cpuLimit = limit.second.value();
+ }
+ } else if (limit.first == "mem") {
+ if (container->generatedForCommandTask &&
+ !std::isinf(limit.second.value())) {
+ memLimit = limit.second.value() -
+ DEFAULT_EXECUTOR_MEM.bytes() / Bytes::MEGABYTES;
+ } else {
+ memLimit = limit.second.value();
+ }
+ }
+ }
+
+ if (cpuRequest.isSome()) {
+ result.set_cpus_soft_limit(cpuRequest.get());
+ }
+
+ if (cpuLimit.isSome()) {
+ // Get the total CPU numbers of this node, we will use
+ // it to set container's hard CPU limit if the CPU limit
+ // specified by framework is infinity.
+ static Option<long> totalCPUs;
+ if (totalCPUs.isNone()) {
+ Try<long> cpus = os::cpus();
+ if (cpus.isError()) {
+ return Failure(
+ "Failed to auto-detect the number of cpus: " + cpus.error());
+ }
+
+ totalCPUs = cpus.get();
+ }
+
+ CHECK_SOME(totalCPUs);
+
+ result.set_cpus_limit(
+ std::isinf(cpuLimit.get()) ? totalCPUs.get() : cpuLimit.get());
+#ifdef __linux__
+ } else if (flags.cgroups_enable_cfs && cpuRequest.isSome()) {
+ result.set_cpus_limit(cpuRequest.get());
+#endif
}
- const Option<double> cpus = resource.cpus();
- if (cpus.isSome()) {
- result.set_cpus_limit(cpus.get());
+ if (memLimit.isSome()) {
+ // Get the total memory of this node, we will use it to
+ // set container's hard memory limit if the memory limit
+ // specified by framework is infinity.
+ static Option<Bytes> totalMem;
+ if (totalMem.isNone()) {
+ Try<os::Memory> mem = os::memory();
+ if (mem.isError()) {
+ return Failure(
+ "Failed to auto-detect the size of main memory: " + mem.error());
+ }
+
+ totalMem = mem->total;
+ }
+
+ CHECK_SOME(totalMem);
+
+ result.set_mem_limit_bytes(
+ std::isinf(memLimit.get())
+ ? totalMem->bytes()
+ : Megabytes(static_cast<uint64_t>(memLimit.get())).bytes());
+
+ if (memRequest.isSome()) {
+ result.set_mem_soft_limit_bytes(memRequest->bytes());
+ }
+ } else if (memRequest.isSome()) {
+ result.set_mem_limit_bytes(memRequest->bytes());
}
return result;
diff --git a/src/tests/containerizer/docker_containerizer_tests.cpp b/src/tests/containerizer/docker_containerizer_tests.cpp
index 42692dc..fc3a651 100644
--- a/src/tests/containerizer/docker_containerizer_tests.cpp
+++ b/src/tests/containerizer/docker_containerizer_tests.cpp
@@ -946,7 +946,7 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_Usage)
ASSERT_SOME(master);
slave::Flags flags = CreateSlaveFlags();
- flags.resources = Option<string>("cpus:2;mem:1024");
+ flags.resources = Option<string>("cpus:1;mem:1024");
MockDocker* mockDocker =
new MockDocker(tests::flags.docker, tests::flags.docker_socket);
@@ -1000,10 +1000,22 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_Usage)
command.set_value("dd if=/dev/zero of=/dev/null");
#endif // __WINDOWS__
+ Value::Scalar cpuLimit, memLimit;
+ cpuLimit.set_value(2);
+ memLimit.set_value(2048);
+
+ google::protobuf::Map<string, Value::Scalar> resourceLimits;
+ resourceLimits.insert({"cpus", cpuLimit});
+ resourceLimits.insert({"mem", memLimit});
+
TaskInfo task = createTask(
offers->front().slave_id(),
offers->front().resources(),
- command);
+ command,
+ None(),
+ "test-task",
+ id::UUID::random().toString(),
+ resourceLimits);
// TODO(tnachen): Use local image to test if possible.
task.mutable_container()->CopyFrom(createDockerInfo(DOCKER_TEST_IMAGE));
@@ -1056,10 +1068,11 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_Usage)
waited += Milliseconds(200);
} while (waited < Seconds(3));
- // Usage includes the executor resources.
- EXPECT_EQ(2.0 + slave::DEFAULT_EXECUTOR_CPUS, statistics.cpus_limit());
- EXPECT_EQ((Gigabytes(1) + slave::DEFAULT_EXECUTOR_MEM).bytes(),
- statistics.mem_limit_bytes());
+ EXPECT_EQ(1, statistics.cpus_soft_limit());
+ EXPECT_EQ(2, statistics.cpus_limit());
+ EXPECT_EQ(Gigabytes(1).bytes(), statistics.mem_soft_limit_bytes());
+ EXPECT_EQ(Gigabytes(2).bytes(), statistics.mem_limit_bytes());
+
#ifndef __WINDOWS__
// These aren't provided by the Windows Container APIs, so skip them.
EXPECT_LT(0, statistics.cpus_user_time_secs());