Repository: apache/camel-k (go)

Issue:
Stable container name
When camel-k creates a deployment, it sets the name of the container after the name of the integration instead, when a knative service is created, the container name is not set.

For better user experience it could be nice to:
- by default, set the name of the container to `integration-container` for deployments and knative services
- have an option to customize the container name `-t container.name=something`

Pull request description:
Stable container name
Fixes #826

Patch:
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 118428a56..d3044d99a 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -19,6 +19,9 @@ package trait
 
 import (
 	"fmt"
+	"strings"
+
+	"github.com/apache/camel-k/pkg/util/envvar"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	serving "github.com/knative/serving/pkg/apis/serving/v1alpha1"
@@ -28,6 +31,11 @@ import (
 	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
+const (
+	defaultContainerName = "integration"
+	containerTraitID     = "container"
+)
+
 type containerTrait struct {
 	BaseTrait `property:",squash"`
 
@@ -41,15 +49,17 @@ type containerTrait struct {
 	PortName        string `property:"port-name"`
 	ServicePort     int    `property:"service-port"`
 	ServicePortName string `property:"service-port-name"`
+	Name            string `property:"name"`
 }
 
 func newContainerTrait() *containerTrait {
 	return &containerTrait{
-		BaseTrait:       newBaseTrait("container"),
+		BaseTrait:       newBaseTrait(containerTraitID),
 		Port:            8080,
 		PortName:        httpPortName,
 		ServicePort:     80,
 		ServicePortName: httpPortName,
+		Name:            defaultContainerName,
 	}
 }
 
@@ -73,21 +83,61 @@ func (t *containerTrait) Configure(e *Environment) (bool, error) {
 }
 
 func (t *containerTrait) Apply(e *Environment) error {
+	container := corev1.Container{
+		Name:  t.Name,
+		Image: e.Integration.Status.Image,
+		Env:   make([]corev1.EnvVar, 0),
+	}
 
-	if e.Resources != nil {
-		//
-		// Add mounted volumes as resources
-		//
-		e.Resources.VisitDeployment(func(deployment *appsv1.Deployment) {
-			for i := 0; i < len(deployment.Spec.Template.Spec.Containers); i++ {
-				t.configureResources(e, &deployment.Spec.Template.Spec.Containers[i])
-			}
-		})
-		e.Resources.VisitKnativeService(func(service *serving.Service) {
-			t.configureResources(e, &service.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container)
-		})
+	// combine Environment of integration with platform, kit, integration
+	for key, value := range e.CollectConfigurationPairs("env") {
+		envvar.SetVal(&container.Env, key, value)
 	}
 
+	envvar.SetVal(&container.Env, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
+	envvar.SetVal(&container.Env, "CAMEL_K_ROUTES", strings.Join(e.ComputeSourcesURI(), ","))
+	envvar.SetVal(&container.Env, "CAMEL_K_CONF", "/etc/camel/conf/application.properties")
+	envvar.SetVal(&container.Env, "CAMEL_K_CONF_D", "/etc/camel/conf.d")
+
+	t.configureResources(e, &container)
+
+	e.Resources.VisitDeployment(func(deployment *appsv1.Deployment) {
+		for _, envVar := range e.EnvVars {
+			envvar.SetVar(&container.Env, envVar)
+		}
+
+		e.ConfigureVolumesAndMounts(
+			&deployment.Spec.Template.Spec.Volumes,
+			&container.VolumeMounts,
+		)
+
+		deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, container)
+	})
+
+	e.Resources.VisitKnativeService(func(service *serving.Service) {
+		for _, env := range e.EnvVars {
+			switch {
+			case env.ValueFrom == nil:
+				envvar.SetVar(&container.Env, env)
+			case env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.namespace":
+				envvar.SetVar(&container.Env, corev1.EnvVar{Name: env.Name, Value: e.Integration.Namespace})
+			case env.ValueFrom.FieldRef != nil:
+				t.L.Infof("Environment variable %s uses fieldRef and cannot be set on a Knative service", env.Name)
+			case env.ValueFrom.ResourceFieldRef != nil:
+				t.L.Infof("Environment variable %s uses resourceFieldRef and cannot be set on a Knative service", env.Name)
+			default:
+				envvar.SetVar(&container.Env, env)
+			}
+		}
+
+		e.ConfigureVolumesAndMounts(
+			&service.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Volumes,
+			&container.VolumeMounts,
+		)
+
+		service.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container = container
+	})
+
 	if t.Expose != nil && *t.Expose {
 		t.configureService(e)
 	}
@@ -101,7 +151,7 @@ func (t *containerTrait) configureService(e *Environment) {
 		return
 	}
 
-	container := e.Resources.GetContainerForIntegration(e.Integration)
+	container := e.Resources.GetContainerByName(t.Name)
 	if container == nil {
 		return
 	}
diff --git a/pkg/trait/deployment.go b/pkg/trait/deployment.go
index 157ef8424..b86736641 100644
--- a/pkg/trait/deployment.go
+++ b/pkg/trait/deployment.go
@@ -18,10 +18,7 @@ limitations under the License.
 package trait
 
 import (
-	"strings"
-
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
-	"github.com/apache/camel-k/pkg/util/envvar"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -121,28 +118,6 @@ func (t *deploymentTrait) Apply(e *Environment) error {
 // **********************************
 
 func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
-	paths := e.ComputeSourcesURI()
-	environment := make([]corev1.EnvVar, 0)
-
-	// combine Environment of integration with platform, kit, integration
-	for key, value := range e.CollectConfigurationPairs("env") {
-		envvar.SetVal(&environment, key, value)
-	}
-
-	// camel-k runtime
-	envvar.SetVal(&environment, "CAMEL_K_ROUTES", strings.Join(paths, ","))
-	envvar.SetVal(&environment, "CAMEL_K_CONF", "/etc/camel/conf/application.properties")
-	envvar.SetVal(&environment, "CAMEL_K_CONF_D", "/etc/camel/conf.d")
-
-	// add a dummy env var to trigger deployment if everything but the code
-	// has been changed
-	envvar.SetVal(&environment, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
-
-	// add env vars from traits
-	for _, envVar := range e.EnvVars {
-		envvar.SetVar(&environment, envVar)
-	}
-
 	// create a copy to avoid sharing the underlying annotation map
 	annotations := make(map[string]string)
 	if e.Integration.Annotations != nil {
@@ -183,22 +158,10 @@ func (t *deploymentTrait) getDeploymentFor(e *Environment) *appsv1.Deployment {
 				},
 				Spec: corev1.PodSpec{
 					ServiceAccountName: e.Integration.Spec.ServiceAccountName,
-					Containers: []corev1.Container{
-						{
-							Name:  e.Integration.Name,
-							Image: e.Integration.Status.Image,
-							Env:   environment,
-						},
-					},
 				},
 			},
 		},
 	}
 
-	e.ConfigureVolumesAndMounts(
-		&deployment.Spec.Template.Spec.Volumes,
-		&deployment.Spec.Template.Spec.Containers[0].VolumeMounts,
-	)
-
 	return &deployment
 }
diff --git a/pkg/trait/jolokia.go b/pkg/trait/jolokia.go
index 60dec4df4..bfe617452 100644
--- a/pkg/trait/jolokia.go
+++ b/pkg/trait/jolokia.go
@@ -115,7 +115,13 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) {
 	}
 	envvar.SetVal(&e.EnvVars, "AB_JOLOKIA_OPTS", strings.Join(optionValues, ","))
 
-	container := e.Resources.GetContainerForIntegration(e.Integration)
+	containerName := defaultContainerName
+	dt := e.Catalog.GetTrait(containerTraitID)
+	if dt != nil {
+		containerName = dt.(*containerTrait).Name
+	}
+
+	container := e.Resources.GetContainerByName(containerName)
 	if container == nil {
 		e.Integration.Status.SetCondition(
 			v1alpha1.IntegrationConditionJolokiaAvailable,
@@ -137,7 +143,6 @@ func (t *jolokiaTrait) Apply(e *Environment) (err error) {
 		v1alpha1.IntegrationConditionJolokiaAvailable,
 		corev1.ConditionTrue,
 		v1alpha1.IntegrationConditionJolokiaAvailableReason,
-		// service -> container
 		fmt.Sprintf("%s(%s/%d)", container.Name, containerPort.Name, containerPort.ContainerPort),
 	)
 
diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go
index 1c916cbaa..8c1f33420 100644
--- a/pkg/trait/knative_service.go
+++ b/pkg/trait/knative_service.go
@@ -19,13 +19,11 @@ package trait
 
 import (
 	"strconv"
-	"strings"
 
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/metadata"
-	"github.com/apache/camel-k/pkg/util/envvar"
 	serving "github.com/knative/serving/pkg/apis/serving/v1alpha1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -209,10 +207,6 @@ func (t *knativeServiceTrait) getServiceFor(e *Environment) *serving.Service {
 						},
 						Spec: serving.RevisionSpec{
 							ServiceAccountName: e.Integration.Spec.ServiceAccountName,
-							Container: corev1.Container{
-								Image: e.Integration.Status.Image,
-								Env:   make([]corev1.EnvVar, 0),
-							},
 						},
 					},
 				},
@@ -220,53 +214,5 @@ func (t *knativeServiceTrait) getServiceFor(e *Environment) *serving.Service {
 		},
 	}
 
-	paths := e.ComputeSourcesURI()
-	environment := &svc.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container.Env
-
-	// combine Environment of integration with kit, integration
-	for key, value := range e.CollectConfigurationPairs("env") {
-		envvar.SetVal(environment, key, value)
-	}
-
-	// add a dummy env var to trigger deployment if everything but the code
-	// has been changed
-	envvar.SetVal(environment, "CAMEL_K_DIGEST", e.Integration.Status.Digest)
-
-	envvar.SetVal(environment, "CAMEL_K_ROUTES", strings.Join(paths, ","))
-	envvar.SetVal(environment, "CAMEL_K_CONF", "/etc/camel/conf/application.properties")
-	envvar.SetVal(environment, "CAMEL_K_CONF_D", "/etc/camel/conf.d")
-
-	// add env vars from traits
-	for _, envVar := range t.getAllowedEnvVars(e) {
-		envvar.SetVar(&svc.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container.Env, envVar)
-	}
-
-	e.ConfigureVolumesAndMounts(
-		&svc.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Volumes,
-		&svc.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container.VolumeMounts,
-	)
-
 	return &svc
 }
-
-func (t *knativeServiceTrait) getAllowedEnvVars(e *Environment) []corev1.EnvVar {
-	res := make([]corev1.EnvVar, 0, len(e.EnvVars))
-	for _, env := range e.EnvVars {
-		switch {
-		case env.ValueFrom == nil:
-			res = append(res, env)
-		case env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.namespace":
-			res = append(res, corev1.EnvVar{
-				Name:  env.Name,
-				Value: e.Integration.Namespace,
-			})
-		case env.ValueFrom.FieldRef != nil:
-			t.L.Infof("Environment variable %s uses fieldRef and cannot be set on a Knative service", env.Name)
-		case env.ValueFrom.ResourceFieldRef != nil:
-			t.L.Infof("Environment variable %s uses resourceFieldRef and cannot be set on a Knative service", env.Name)
-		default:
-			res = append(res, env)
-		}
-	}
-	return res
-}
diff --git a/pkg/trait/prometheus.go b/pkg/trait/prometheus.go
index 51cdbb5ab..f52ad54c1 100644
--- a/pkg/trait/prometheus.go
+++ b/pkg/trait/prometheus.go
@@ -110,7 +110,13 @@ func (t *prometheusTrait) Apply(e *Environment) (err error) {
 }
 
 func (t *prometheusTrait) configureContainerPort(e *Environment) (*corev1.Container, *corev1.ContainerPort) {
-	container := e.Resources.GetContainerForIntegration(e.Integration)
+	containerName := defaultContainerName
+	dt := e.Catalog.GetTrait(containerTraitID)
+	if dt != nil {
+		containerName = dt.(*containerTrait).Name
+	}
+
+	container := e.Resources.GetContainerByName(containerName)
 	if container == nil {
 		return nil, nil
 	}
diff --git a/pkg/util/kubernetes/collection.go b/pkg/util/kubernetes/collection.go
index ca27e9a69..b1444c3c2 100644
--- a/pkg/util/kubernetes/collection.go
+++ b/pkg/util/kubernetes/collection.go
@@ -261,14 +261,10 @@ func (c *Collection) GetContainer(filter func(container *corev1.Container) bool)
 	return retValue
 }
 
-// GetContainerForIntegration --
-func (c *Collection) GetContainerForIntegration(integration *v1alpha1.Integration) *corev1.Container {
-	if integration == nil {
-		return nil
-	}
-
+// GetContainerByName --
+func (c *Collection) GetContainerByName(name string) *corev1.Container {
 	return c.GetContainer(func(c *corev1.Container) bool {
-		return c.Name == integration.Name
+		return c.Name == name
 	})
 }
 


Test patch:
diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go
new file mode 100644
index 000000000..f5793cc42
--- /dev/null
+++ b/pkg/trait/container_test.go
@@ -0,0 +1,151 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package trait
+
+import (
+	"context"
+	"testing"
+
+	"github.com/scylladb/go-set/strset"
+
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+	"github.com/apache/camel-k/pkg/util/test"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestContainerWithDefaults(t *testing.T) {
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(context.TODO(), nil)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1alpha1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      ServiceTestName,
+				Namespace: "ns",
+			},
+			Status: v1alpha1.IntegrationStatus{
+				Phase: v1alpha1.IntegrationPhaseDeploying,
+			},
+			Spec: v1alpha1.IntegrationSpec{
+				Profile: v1alpha1.TraitProfileKubernetes,
+			},
+		},
+		IntegrationKit: &v1alpha1.IntegrationKit{
+			Status: v1alpha1.IntegrationKitStatus{
+				Phase: v1alpha1.IntegrationKitPhaseReady,
+			},
+		},
+		Platform: &v1alpha1.IntegrationPlatform{
+			Spec: v1alpha1.IntegrationPlatformSpec{
+				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
+				Build: v1alpha1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1alpha1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1alpha1.IntegrationPlatformRegistrySpec{Address: "registry"},
+				},
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+		Classpath:      strset.New(),
+	}
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(ID("deployment")))
+	assert.NotNil(t, environment.GetTrait(ID("container")))
+
+	d := environment.Resources.GetDeploymentForIntegration(environment.Integration)
+
+	assert.NotNil(t, d)
+	assert.Len(t, d.Spec.Template.Spec.Containers, 1)
+	assert.Equal(t, defaultContainerName, d.Spec.Template.Spec.Containers[0].Name)
+}
+
+func TestContainerWithCustomName(t *testing.T) {
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(context.TODO(), nil)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1alpha1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      ServiceTestName,
+				Namespace: "ns",
+			},
+			Status: v1alpha1.IntegrationStatus{
+				Phase: v1alpha1.IntegrationPhaseDeploying,
+			},
+			Spec: v1alpha1.IntegrationSpec{
+				Profile: v1alpha1.TraitProfileKubernetes,
+				Traits: map[string]v1alpha1.TraitSpec{
+					"container": {
+						Configuration: map[string]string{
+							"name": "my-container-name",
+						},
+					},
+				},
+			},
+		},
+		IntegrationKit: &v1alpha1.IntegrationKit{
+			Status: v1alpha1.IntegrationKitStatus{
+				Phase: v1alpha1.IntegrationKitPhaseReady,
+			},
+		},
+		Platform: &v1alpha1.IntegrationPlatform{
+			Spec: v1alpha1.IntegrationPlatformSpec{
+				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
+				Build: v1alpha1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1alpha1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1alpha1.IntegrationPlatformRegistrySpec{Address: "registry"},
+				},
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+		Classpath:      strset.New(),
+	}
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(ID("deployment")))
+	assert.NotNil(t, environment.GetTrait(ID("container")))
+
+	d := environment.Resources.GetDeploymentForIntegration(environment.Integration)
+
+	assert.NotNil(t, d)
+	assert.Len(t, d.Spec.Template.Spec.Containers, 1)
+	assert.Equal(t, environment.Integration.Spec.Traits["container"].Configuration["name"], d.Spec.Template.Spec.Containers[0].Name)
+}
diff --git a/pkg/trait/knative_service_test.go b/pkg/trait/knative_service_test.go
index 30db75902..01e2fb138 100644
--- a/pkg/trait/knative_service_test.go
+++ b/pkg/trait/knative_service_test.go
@@ -178,3 +178,82 @@ func TestKnativeService(t *testing.T) {
 	test.EnvVarHasValue(t, spec.Container.Env, "CAMEL_K_CONF", "/etc/camel/conf/application.properties")
 	test.EnvVarHasValue(t, spec.Container.Env, "CAMEL_K_CONF_D", "/etc/camel/conf.d")
 }
+
+func TestKnativeServiceWithCustomContainerName(t *testing.T) {
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(context.TODO(), nil)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1alpha1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      KnativeServiceTestName,
+				Namespace: KnativeServiceTestNamespace,
+			},
+			Status: v1alpha1.IntegrationStatus{
+				Phase: v1alpha1.IntegrationPhaseDeploying,
+			},
+
+			Spec: v1alpha1.IntegrationSpec{
+				Profile: v1alpha1.TraitProfileKnative,
+				Traits: map[string]v1alpha1.TraitSpec{
+					"deployer": {
+						Configuration: map[string]string{
+							"kind": "knative-service",
+						},
+					},
+					"knative-service": {
+						Configuration: map[string]string{
+							"enabled": "true",
+							"auto":    "false",
+						},
+					},
+					"container": {
+						Configuration: map[string]string{
+							"name": "my-container-name",
+						},
+					},
+				},
+			},
+		},
+		IntegrationKit: &v1alpha1.IntegrationKit{
+			Status: v1alpha1.IntegrationKitStatus{
+				Phase: v1alpha1.IntegrationKitPhaseReady,
+			},
+		},
+		Platform: &v1alpha1.IntegrationPlatform{
+			Spec: v1alpha1.IntegrationPlatformSpec{
+				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
+				Build: v1alpha1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1alpha1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1alpha1.IntegrationPlatformRegistrySpec{Address: "registry"},
+				},
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+		Classpath:      strset.New(),
+	}
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(ID("knative-service")))
+	assert.NotNil(t, environment.GetTrait(ID("container")))
+
+	s := environment.Resources.GetKnativeService(func(service *serving.Service) bool {
+		return service.Name == KnativeServiceTestName
+	})
+
+	assert.NotNil(t, s)
+	assert.Equal(
+		t,
+		environment.Integration.Spec.Traits["container"].Configuration["name"],
+		s.Spec.RunLatest.Configuration.RevisionTemplate.Spec.Container.Name,
+	)
+}
diff --git a/pkg/trait/service_test.go b/pkg/trait/service_test.go
index 4e14f66ff..fb5f6f53b 100644
--- a/pkg/trait/service_test.go
+++ b/pkg/trait/service_test.go
@@ -224,3 +224,76 @@ func TestService(t *testing.T) {
 	assert.Equal(t, int32(8081), d.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort)
 	assert.Equal(t, "http-8081", d.Spec.Template.Spec.Containers[0].Ports[0].Name)
 }
+
+func TestServiceWithCustomContainerName(t *testing.T) {
+	catalog, err := test.DefaultCatalog()
+	assert.Nil(t, err)
+
+	traitCatalog := NewCatalog(context.TODO(), nil)
+
+	environment := Environment{
+		CamelCatalog: catalog,
+		Catalog:      traitCatalog,
+		Integration: &v1alpha1.Integration{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      ServiceTestName,
+				Namespace: ServiceTestNamespace,
+			},
+			Status: v1alpha1.IntegrationStatus{
+				Phase: v1alpha1.IntegrationPhaseDeploying,
+			},
+			Spec: v1alpha1.IntegrationSpec{
+				Profile: v1alpha1.TraitProfileKubernetes,
+				Traits: map[string]v1alpha1.TraitSpec{
+					"service": {
+						Configuration: map[string]string{
+							"enabled": "true",
+							"auto":    "false",
+						},
+					},
+					"container": {
+						Configuration: map[string]string{
+							"name": "my-container-name",
+						},
+					},
+				},
+			},
+		},
+		IntegrationKit: &v1alpha1.IntegrationKit{
+			Status: v1alpha1.IntegrationKitStatus{
+				Phase: v1alpha1.IntegrationKitPhaseReady,
+			},
+		},
+		Platform: &v1alpha1.IntegrationPlatform{
+			Spec: v1alpha1.IntegrationPlatformSpec{
+				Cluster: v1alpha1.IntegrationPlatformClusterOpenShift,
+				Build: v1alpha1.IntegrationPlatformBuildSpec{
+					PublishStrategy: v1alpha1.IntegrationPlatformBuildPublishStrategyS2I,
+					Registry:        v1alpha1.IntegrationPlatformRegistrySpec{Address: "registry"},
+				},
+			},
+		},
+		EnvVars:        make([]corev1.EnvVar, 0),
+		ExecutedTraits: make([]Trait, 0),
+		Resources:      kubernetes.NewCollection(),
+		Classpath:      strset.New(),
+	}
+
+	err = traitCatalog.apply(&environment)
+
+	assert.Nil(t, err)
+	assert.NotEmpty(t, environment.ExecutedTraits)
+	assert.NotNil(t, environment.GetTrait(ID("deployment")))
+	assert.NotNil(t, environment.GetTrait(ID("service")))
+	assert.NotNil(t, environment.GetTrait(ID("container")))
+
+	d := environment.Resources.GetDeploymentForIntegration(environment.Integration)
+	assert.NotNil(t, d)
+
+	assert.Len(t, d.Spec.Template.Spec.Containers, 1)
+	assert.Equal(
+		t,
+		environment.Integration.Spec.Traits["container"].Configuration["name"],
+		d.Spec.Template.Spec.Containers[0].Name,
+	)
+}