Skip to content

Commit b9f16dc

Browse files
authored
Add ability to scale Ephemeral storage along with memory, similar to CPU (#5008)
* Add ability to scale Ephemeral storage along with memory, similar to CPU. * Enforce the limit even when scaling ephemeral storage * Code formatter
1 parent 597d61d commit b9f16dc

File tree

4 files changed

+54
-4
lines changed

4 files changed

+54
-4
lines changed

core/invoker/src/main/resources/application.conf

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,13 @@ whisk {
120120
#}
121121

122122
#if missing, the pod will be created without ephermal disk request/limit
123-
#if specified, the pod will be created with ephemeral-storage request+limit set
123+
#if specified, the pod will be created with ephemeral-storage request+limit set or using the scale factor
124+
#as a multiple of the request memory. If the scaled value exceeds the limit, the limit will be used so, it's good
125+
#practice to set the limit if you plan on using the scale-factor.
124126
#See: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage
125127
#ephemeral-storage {
126128
# limit = 2 g
129+
# scale-factor = 2.0
127130
#}
128131

129132
#enable PodDisruptionBudget creation for pods? (will include same labels as pods, and specify minAvailable=1 to prevent termination of action pods during maintenance)

core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/kubernetes/KubernetesClient.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ case class KubernetesCpuScalingConfig(millicpus: Int, memory: ByteSize, maxMilli
7474
/**
7575
* Configuration for kubernetes ephemeral storage limit for the action container
7676
*/
77-
case class KubernetesEphemeralStorageConfig(limit: ByteSize)
77+
case class KubernetesEphemeralStorageConfig(limit: ByteSize, scaleFactor: Double)
7878

7979
/**
8080
* Exception to indicate a pod took too long to become ready.

core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/kubernetes/WhiskPodBuilder.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,14 @@ class WhiskPodBuilder(client: NamespacedKubernetesClient, config: KubernetesClie
108108
.getOrElse(Map.empty)
109109

110110
val diskLimit = config.ephemeralStorage
111-
.map(diskConfig => Map("ephemeral-storage" -> new Quantity(diskConfig.limit.toMB + "Mi")))
111+
.map(
112+
diskConfig =>
113+
// Scale the ephemeral storage unless it exceeds the limit, if it exceeds the limit use the limit.
114+
if ((diskConfig.scaleFactor > 0) && (diskConfig.scaleFactor * memory.toMB < diskConfig.limit.toMB)) {
115+
Map("ephemeral-storage" -> new Quantity(diskConfig.scaleFactor * memory.toMB + "Mi"))
116+
} else {
117+
Map("ephemeral-storage" -> new Quantity(diskConfig.limit.toMB + "Mi"))
118+
})
112119
.getOrElse(Map.empty)
113120

114121
//In container its assumed that env, port, resource limits are set explicitly

tests/src/test/scala/org/apache/openwhisk/core/containerpool/kubernetes/test/WhiskPodBuilderTests.scala

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,47 @@ class WhiskPodBuilderTests extends FlatSpec with Matchers with KubeClientSupport
133133
Some(KubernetesCpuScalingConfig(300, 3.MB, 1000)),
134134
false,
135135
None,
136-
Some(KubernetesEphemeralStorageConfig(1.GB)))
136+
Some(KubernetesEphemeralStorageConfig(1.GB, 0.0)))
137+
val builder = new WhiskPodBuilder(kubeClient, config)
138+
139+
val (pod, _) = builder.buildPodSpec(name, testImage, 2.MB, Map("foo" -> "bar"), Map("fooL" -> "barV"), config)
140+
withClue(Serialization.asYaml(pod)) {
141+
val c = getActionContainer(pod)
142+
c.getResources.getLimits.asScala.get("ephemeral-storage").map(_.getAmount) shouldBe Some("1024Mi")
143+
c.getResources.getRequests.asScala.get("ephemeral-storage").map(_.getAmount) shouldBe Some("1024Mi")
144+
}
145+
}
146+
it should "scale ephemeral storage when scale factor is given" in {
147+
val config = KubernetesClientConfig(
148+
KubernetesClientTimeoutConfig(1.second, 1.second),
149+
KubernetesInvokerNodeAffinity(false, "k", "v"),
150+
true,
151+
None,
152+
None,
153+
Some(KubernetesCpuScalingConfig(300, 3.MB, 1000)),
154+
false,
155+
None,
156+
Some(KubernetesEphemeralStorageConfig(1.GB, 1.25)))
157+
val builder = new WhiskPodBuilder(kubeClient, config)
158+
159+
val (pod, _) = builder.buildPodSpec(name, testImage, 2.MB, Map("foo" -> "bar"), Map("fooL" -> "barV"), config)
160+
withClue(Serialization.asYaml(pod)) {
161+
val c = getActionContainer(pod)
162+
c.getResources.getLimits.asScala.get("ephemeral-storage").map(_.getAmount) shouldBe Some("2.5Mi")
163+
c.getResources.getRequests.asScala.get("ephemeral-storage").map(_.getAmount) shouldBe Some("2.5Mi")
164+
}
165+
}
166+
it should "use ephemeral storage limit when scale factor suggests larger size" in {
167+
val config = KubernetesClientConfig(
168+
KubernetesClientTimeoutConfig(1.second, 1.second),
169+
KubernetesInvokerNodeAffinity(false, "k", "v"),
170+
true,
171+
None,
172+
None,
173+
Some(KubernetesCpuScalingConfig(300, 3.MB, 1000)),
174+
false,
175+
None,
176+
Some(KubernetesEphemeralStorageConfig(1.GB, 1000)))
137177
val builder = new WhiskPodBuilder(kubeClient, config)
138178

139179
val (pod, _) = builder.buildPodSpec(name, testImage, 2.MB, Map("foo" -> "bar"), Map("fooL" -> "barV"), config)

0 commit comments

Comments
 (0)