diff --git a/spring-cloud-deployer-kubernetes/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/AbstractKubernetesDeployer.java b/spring-cloud-deployer-kubernetes/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/AbstractKubernetesDeployer.java index 02fa71e3..c05b6149 100755 --- a/spring-cloud-deployer-kubernetes/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/AbstractKubernetesDeployer.java +++ b/spring-cloud-deployer-kubernetes/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/AbstractKubernetesDeployer.java @@ -16,6 +16,7 @@ package org.springframework.cloud.deployer.spi.kubernetes; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -249,11 +250,6 @@ PodSpec createPodSpec(AppDeploymentRequest appDeploymentRequest) { podSpec.withTolerations(this.deploymentPropertiesResolver.getTolerations(deploymentProperties)); - // only add volumes with corresponding volume mounts - podSpec.withVolumes(this.deploymentPropertiesResolver.getVolumes(deploymentProperties).stream() - .filter(volume -> container.getVolumeMounts().stream() - .anyMatch(volumeMount -> volumeMount.getName().equals(volume.getName()))) - .collect(Collectors.toList())); if (hostNetwork) { podSpec.withHostNetwork(true); @@ -311,6 +307,22 @@ PodSpec createPodSpec(AppDeploymentRequest appDeploymentRequest) { .forEach((c) -> c.setSecurityContext(containerSecurityContext)); } podSpec.addAllToContainers(additionalContainers); + + List allContainers = new ArrayList<>(); + allContainers.add(container); + if (initContainer != null) { + allContainers.add(initContainer); + } + allContainers.addAll(additionalContainers); + // only add volumes with corresponding volume mounts in any container. + podSpec.withVolumes(this.deploymentPropertiesResolver.getVolumes(deploymentProperties).stream() + .filter(volume -> allContainers.stream() + .anyMatch(c -> c.getVolumeMounts() + .stream() + .anyMatch(volumeMount -> volumeMount.getName().equals(volume.getName())) + ) + ) + .collect(Collectors.toList())); return podSpec.build(); } diff --git a/spring-cloud-deployer-kubernetes/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java b/spring-cloud-deployer-kubernetes/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java index 6c7e40fd..dd42190b 100644 --- a/spring-cloud-deployer-kubernetes/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java +++ b/spring-cloud-deployer-kubernetes/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java @@ -23,14 +23,19 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.AffinityBuilder; import io.fabric8.kubernetes.api.model.Capabilities; import io.fabric8.kubernetes.api.model.ConfigMapKeySelector; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.HostPathVolumeSource; import io.fabric8.kubernetes.api.model.HostPathVolumeSourceBuilder; +import io.fabric8.kubernetes.api.model.KeyToPath; import io.fabric8.kubernetes.api.model.LabelSelector; import io.fabric8.kubernetes.api.model.LabelSelectorRequirementBuilder; import io.fabric8.kubernetes.api.model.NodeAffinity; @@ -50,6 +55,7 @@ import io.fabric8.kubernetes.api.model.SecurityContextBuilder; import io.fabric8.kubernetes.api.model.Sysctl; import io.fabric8.kubernetes.api.model.Toleration; +import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeBuilder; import io.fabric8.kubernetes.api.model.WeightedPodAffinityTerm; import io.fabric8.kubernetes.api.model.WindowsSecurityContextOptions; @@ -139,7 +145,47 @@ public void deployWithVolumesAndVolumeMounts() throws Exception { new VolumeBuilder().withName("testpvc").withNewPersistentVolumeClaim("testClaim", true).build(), new VolumeBuilder().withName("testnfs").withNewNfs("/test/override/nfs", null, "192.168.1.1:111").build()); } + @Test + public void deployWithVolumesAndVolumeMountsOnAdditionalContainer() throws Exception { + AppDefinition definition = new AppDefinition("app-test", null); + Map props = new HashMap<>(); + props.put("spring.cloud.deployer.kubernetes.volumes", "[{name: 'config', configMap: {name: promtail-config, items: [{key: promtail.yaml, path: promtail.yaml}]}},{name: 'config2', configMap: {name: promtail-config, items: [{key: promtail.yaml, path: promtail.yaml}]}}]"); + props.put("spring.cloud.deployer.kubernetes.additional-containers", "[{name: 'promtail',image: image-path-of-promtail, ports:[{protocol: TCP,containerPort: 8080}],args: [\"-config.file=/home/conf/promtail.yaml\"],volumeMounts: [{name: 'config', mountPath: '/home/conf'}]},{name: 'promtail2',image: image-path-of-promtail, ports:[{protocol: TCP,containerPort: 8080}],args: [\"-config.file=/home/conf/promtail.yaml\"],volumeMounts: [{name: 'config2', mountPath: '/home/conf'}]}]"); + AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); + + deployer = k8sAppDeployer(); + PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); + + ConfigMapVolumeSource configMapVolumeSource = new ConfigMapVolumeSourceBuilder() + .withName("promtail-config") + .withItems(new KeyToPath("promtail.yaml", null, "promtail.yaml")) + .build(); + Volume volume = new VolumeBuilder().withName("config").withNewConfigMapLike(configMapVolumeSource).endConfigMap().build(); + Volume volume2 = new VolumeBuilder().withName("config2").withNewConfigMapLike(configMapVolumeSource).endConfigMap().build(); + assertThat(podSpec.getVolumes()).containsExactly(volume, volume2); + } + @Test + public void deployWithVolumesAndVolumeMountsOnAdditionalContainerAbsentVolumeMount() throws Exception { + AppDefinition definition = new AppDefinition("app-test", null); + Map props = new HashMap<>(); + props.put("spring.cloud.deployer.kubernetes.volumes", "[{name: 'config', configMap: {name: promtail-config, items: [{key: promtail.yaml, path: promtail.yaml}]}},{name: 'config2', configMap: {name: promtail-config, items: [{key: promtail.yaml, path: promtail.yaml}]}}]"); + // both containers reference config. + props.put("spring.cloud.deployer.kubernetes.additional-containers", "[{name: 'promtail',image: image-path-of-promtail, ports:[{protocol: TCP,containerPort: 8080}],args: [\"-config.file=/home/conf/promtail.yaml\"],volumeMounts: [{name: 'config', mountPath: '/home/conf'}]},{name: 'promtail2',image: image-path-of-promtail, ports:[{protocol: TCP,containerPort: 8080}],args: [\"-config.file=/home/conf/promtail.yaml\"],volumeMounts: [{name: 'config', mountPath: '/home/conf'}]}]"); + AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); + deployer = k8sAppDeployer(); + PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); + + ConfigMapVolumeSource configMapVolumeSource = new ConfigMapVolumeSourceBuilder() + .withName("promtail-config") + .withItems(new KeyToPath("promtail.yaml", null, "promtail.yaml")) + .build(); + Set volumeNames = podSpec.getVolumes().stream().map(v -> v.getName()).collect(Collectors.toSet()); + assertThat(volumeNames).doesNotContain("config2"); + Volume volume = new VolumeBuilder().withName("config").withNewConfigMapLike(configMapVolumeSource).endConfigMap().build(); + assertThat(podSpec.getVolumes()).containsExactly(volume); + + } @Test public void deployWithNodeSelectorGlobalProperty() throws Exception { AppDefinition definition = new AppDefinition("app-test", null);