Skip to content

Commit 6eced3d

Browse files
committed
feat(Kubernetes): Support init containers
Allow additional containers to be declared as init containers. Handle them correctly when setting up the Kubernetes manifest. This makes it possible to run some initialization tasks before an ORT Server worker gets active. Signed-off-by: Oliver Heger <oliver.heger@bosch.com>
1 parent 1aee48d commit 6eced3d

4 files changed

Lines changed: 75 additions & 12 deletions

File tree

transport/kubernetes/src/main/kotlin/Container.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,13 @@ data class Container(
6565
* A list with the names of volume mounts to add to this container. The strings in the list reference the names of
6666
* declared volume mounts. In addition, volume mounts without a name are added to all containers.
6767
*/
68-
val volumeMounts: List<String> = emptyList()
68+
val volumeMounts: List<String> = emptyList(),
69+
70+
/**
71+
* A flag whether this container is an init container.
72+
* See https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
73+
*/
74+
val isInitContainer: Boolean = false
6975
) {
7076
/**
7177
* Return an optional [V1ResourceRequirements] object based on the properties related to resource requests and

transport/kubernetes/src/main/kotlin/KubernetesMessageSender.kt

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.eclipse.apoapsis.ortserver.transport.kubernetes
2121

2222
import io.kubernetes.client.openapi.apis.BatchV1Api
23+
import io.kubernetes.client.openapi.models.V1ContainerFluent
2324
import io.kubernetes.client.openapi.models.V1EnvVar
2425
import io.kubernetes.client.openapi.models.V1EnvVarBuilder
2526
import io.kubernetes.client.openapi.models.V1JobBuilder
@@ -189,14 +190,34 @@ private fun <A : V1PodSpecFluent<A>> A.addContainers(
189190
namedMounts: Map<String, V1VolumeMount>
190191
): A =
191192
(listOf(config.mainContainer) + config.additionalContainers).fold(this) { pod, container ->
192-
pod.addNewContainer()
193-
.withName(container.name)
194-
.withImage(container.imageName.substituteVariables(variables))
195-
.withImagePullPolicy(container.imagePullPolicy)
196-
.withCommand(container.commands)
197-
.withArgs(container.args)
198-
.withEnv(environment)
199-
.withResources(container.createResources(variables))
200-
.withVolumeMounts(globalMounts + container.volumeMounts.mapNotNull { namedMounts[it] })
201-
.endContainer()
193+
if (container.isInitContainer) {
194+
pod.addNewInitContainer()
195+
.configureContainer(container, environment, variables, globalMounts, namedMounts)
196+
.endInitContainer()
197+
} else {
198+
pod.addNewContainer()
199+
.configureContainer(container, environment, variables, globalMounts, namedMounts)
200+
.endContainer()
201+
}
202202
}
203+
204+
/**
205+
* Configure this container fluent builder with all properties from the given [container]. The [environment] is set
206+
* as env vars. Variable substitution is done based on the provided [variables]. Volume mounts are generated from
207+
* [globalMounts] (added to all containers) and [namedMounts] (explicitly referenced by single containers).
208+
*/
209+
private fun <F : V1ContainerFluent<F>> F.configureContainer(
210+
container: Container,
211+
environment: List<V1EnvVar>,
212+
variables: Map<String, String>,
213+
globalMounts: List<V1VolumeMount>,
214+
namedMounts: Map<String, V1VolumeMount>
215+
): F =
216+
withName(container.name)
217+
.withImage(container.imageName.substituteVariables(variables))
218+
.withImagePullPolicy(container.imagePullPolicy)
219+
.withCommand(container.commands)
220+
.withArgs(container.args)
221+
.withEnv(environment)
222+
.withResources(container.createResources(variables))
223+
.withVolumeMounts(globalMounts + container.volumeMounts.mapNotNull { namedMounts[it] })

transport/kubernetes/src/main/kotlin/KubernetesSenderConfig.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,8 @@ data class KubernetesSenderConfig(
323323
cpuRequest = System.getenv("${prefix}CPU_REQUEST"),
324324
memoryLimit = System.getenv("${prefix}MEMORY_LIMIT"),
325325
memoryRequest = System.getenv("${prefix}MEMORY_REQUEST"),
326-
volumeMounts = System.getenv("${prefix}VOLUME_MOUNTS").splitAt(splitCommaListRegex)
326+
volumeMounts = System.getenv("${prefix}VOLUME_MOUNTS").splitAt(splitCommaListRegex),
327+
isInitContainer = System.getenv("${prefix}INIT_CONTAINER")?.toBoolean() ?: false
327328
)
328329
}
329330

transport/kubernetes/src/test/kotlin/KubernetesMessageSenderTest.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,41 @@ class KubernetesMessageSenderTest : StringSpec({
289289
expectMounts("dir1", "dir2", "secret-volume-1", "pvc-volume-2")
290290
}
291291
}
292+
293+
"Init containers can be created" {
294+
val containerVariables = mapOf(
295+
"INIT_INIT_CONTAINER" to "true",
296+
"INIT_IMAGE_NAME" to "init-image:1.0",
297+
"INIT_COMMANDS" to "initialize.sh",
298+
"INIT_MEMORY_REQUEST" to "128",
299+
"INIT_VOLUME_MOUNTS" to "secretMount"
300+
)
301+
302+
val config = createConfig(
303+
mapOf(
304+
"additionalContainers" to "INIT",
305+
"mountPvcs" to "",
306+
"mountSecrets" to "secretMount=topSecret->/mnt/top/secret|sub-secret",
307+
"mountEmptyDirs" to "dir1->/mnt/dir1"
308+
),
309+
containerVariables
310+
)
311+
312+
val job = createJob(config, message)
313+
314+
job.spec?.template?.spec?.containers.orEmpty() shouldHaveSize 1
315+
316+
job.spec?.template?.spec?.initContainers.orEmpty().single().shouldNotBeNull {
317+
image shouldBe "init-image:1.0"
318+
command shouldBe listOf("initialize.sh")
319+
args shouldBe config.mainContainer.args
320+
resources shouldNotBeNull {
321+
limits?.keys.orEmpty() should beEmpty()
322+
requests shouldBe mapOf("memory" to Quantity("128"))
323+
}
324+
expectMounts("secret-volume-1", "dir1")
325+
}
326+
}
292327
})
293328

294329
private val annotations = mapOf(

0 commit comments

Comments
 (0)