This is an automated email from the ASF dual-hosted git repository.

pcongiusti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git


The following commit(s) were added to refs/heads/main by this push:
     new d62230572 feat(trait): service and container ports
d62230572 is described below

commit d62230572e1cbbbdf12e92a38ec32757d0a2963b
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Mon Sep 1 20:06:01 2025 +0200

    feat(trait): service and container ports
    
    Enable `container.ports` and `service.ports` to expose any generic port 
internally and externally (through Service),
    
    Close #6248
---
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  |  36 ++-
 docs/modules/traits/pages/container.adoc           |  18 +-
 docs/modules/traits/pages/service.adoc             |  24 +-
 e2e/common/traits/service_test.go                  |  33 +++
 helm/camel-k/crds/camel-k-crds.yaml                | 271 +++++++++++++++------
 pkg/apis/camel/v1/trait/container.go               |  16 +-
 pkg/apis/camel/v1/trait/service.go                 |  10 +-
 pkg/apis/camel/v1/trait/zz_generated.deepcopy.go   |  10 +
 .../camel.apache.org_integrationplatforms.yaml     |  78 ++++--
 .../camel.apache.org_integrationprofiles.yaml      |  78 ++++--
 .../crd/bases/camel.apache.org_integrations.yaml   |  78 ++++--
 .../config/crd/bases/camel.apache.org_pipes.yaml   |  37 ++-
 pkg/trait/container.go                             |  56 +++++
 pkg/trait/container_test.go                        |  65 +++++
 pkg/trait/service.go                               |  71 +++++-
 pkg/trait/service_test.go                          |  92 +++++++
 16 files changed, 812 insertions(+), 161 deletions(-)

diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc 
b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index d638befdc..ff9e79ee7 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -6670,40 +6670,51 @@ string
 
 The maximum amount of memory to be provided (default 512 Mi).
 
+|`ports` +
+[]string
+|
+
+
+List of container ports available in the container (syntax: 
<port-name>;<port-number>[;port-protocol]).
+When omitted, `port-protocol` (admitted values `TCP`, `UDP` or `SCTP`) is 
`TCP`.
+Don't use this for the primary http managed port (for which case you need to 
use `portName` and `port`).
+Don't use in Knative based environments.
+
 |`expose` +
 bool
 |
 
 
-Can be used to enable/disable exposure via kubernetes Service.
+Can be used to enable/disable http exposure via kubernetes Service.
 
 |`port` +
 int32
 |
 
 
-To configure a different port exposed by the container (default `8080`).
+To configure a different http port exposed by the container (default `8080`).
 
 |`portName` +
 string
 |
 
 
-To configure a different port name for the port exposed by the container. It 
defaults to `http` only when the `expose` parameter is true.
+To configure a different http port name for the port exposed by the container.
+It defaults to `http` only when the `expose` parameter is true.
 
 |`servicePort` +
 int32
 |
 
 
-To configure under which service port the container port is to be exposed 
(default `80`).
+To configure under which service port the http container port is to be exposed 
(default `80`).
 
 |`servicePortName` +
 string
 |
 
 
-To configure under which service port name the container port is to be exposed 
(default `http`).
+To configure under which service port name the http container port is to be 
exposed (default `http`).
 
 |`name` +
 string
@@ -8957,8 +8968,8 @@ List of Services in the form 
[[apigroup/]version:]kind:[namespace/]name
 
 * <<#_camel_apache_org_v1_Traits, Traits>>
 
-The Service trait exposes the integration with a Service resource so that it 
can be accessed by other applications
-(or integrations) in the same namespace.
+The Service trait exposes the Integration with a Service resource so that it 
can be accessed by other applications
+(or Integrations) in the same namespace.
 
 NOTE: this trait is automatically disabled if the Knative Service trait is 
enabled.
 
@@ -9013,6 +9024,17 @@ map[string]string
 
 The labels added to the Service object.
 
+|`ports` +
+[]string
+|
+
+
+List of container ports available in the container to expose
+(syntax: <port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+When omitted, `port-protocol` (admitted values `TCP`, `UDP` or `SCTP`) is 
`TCP`.
+Don't use this for the primary http managed port (which is managed by 
container trait).
+Don't use in Knative based environments.
+
 
 |===
 
diff --git a/docs/modules/traits/pages/container.adoc 
b/docs/modules/traits/pages/container.adoc
index 3b5774c0e..cc9c10658 100755
--- a/docs/modules/traits/pages/container.adoc
+++ b/docs/modules/traits/pages/container.adoc
@@ -51,25 +51,33 @@ The following configuration options are available:
 | string
 | The maximum amount of memory to be provided (default 512 Mi).
 
+| container.ports
+| []string
+| List of container ports available in the container (syntax: 
<port-name>;<port-number>[;port-protocol]).
+When omitted, `port-protocol` (admitted values `TCP`, `UDP` or `SCTP`) is 
`TCP`.
+Don't use this for the primary http managed port (for which case you need to 
use `portName` and `port`).
+Don't use in Knative based environments.
+
 | container.expose
 | bool
-| Can be used to enable/disable exposure via kubernetes Service.
+| Can be used to enable/disable http exposure via kubernetes Service.
 
 | container.port
 | int32
-| To configure a different port exposed by the container (default `8080`).
+| To configure a different http port exposed by the container (default `8080`).
 
 | container.port-name
 | string
-| To configure a different port name for the port exposed by the container. It 
defaults to `http` only when the `expose` parameter is true.
+| To configure a different http port name for the port exposed by the 
container.
+It defaults to `http` only when the `expose` parameter is true.
 
 | container.service-port
 | int32
-| To configure under which service port the container port is to be exposed 
(default `80`).
+| To configure under which service port the http container port is to be 
exposed (default `80`).
 
 | container.service-port-name
 | string
-| To configure under which service port name the container port is to be 
exposed (default `http`).
+| To configure under which service port name the http container port is to be 
exposed (default `http`).
 
 | container.name
 | string
diff --git a/docs/modules/traits/pages/service.adoc 
b/docs/modules/traits/pages/service.adoc
index 6d72e7dce..57fb2aa3a 100755
--- a/docs/modules/traits/pages/service.adoc
+++ b/docs/modules/traits/pages/service.adoc
@@ -3,8 +3,8 @@
 // Start of autogenerated code - DO NOT EDIT! (badges)
 // End of autogenerated code - DO NOT EDIT! (badges)
 // Start of autogenerated code - DO NOT EDIT! (description)
-The Service trait exposes the integration with a Service resource so that it 
can be accessed by other applications
-(or integrations) in the same namespace.
+The Service trait exposes the Integration with a Service resource so that it 
can be accessed by other applications
+(or Integrations) in the same namespace.
 
 NOTE: this trait is automatically disabled if the Knative Service trait is 
enabled.
 
@@ -53,6 +53,26 @@ Deprecated: Use service type instead.
 | map[string]string
 | The labels added to the Service object.
 
+| service.ports
+| []string
+| List of container ports available in the container to expose
+(syntax: <port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+When omitted, `port-protocol` (admitted values `TCP`, `UDP` or `SCTP`) is 
`TCP`.
+Don't use this for the primary http managed port (which is managed by 
container trait).
+Don't use in Knative based environments.
+
 |===
 
 // End of autogenerated code - DO NOT EDIT! (configuration)
+
+== Examples
+
+* Expose a Service (we call it `hello`) on a port (`85``) which is used 
internally by your application (`8085`):
++
+[source,console]
+$ kamel run PlatformHttpServer.java -p quarkus.http.port=8085 -t 
container.ports=hello;8085 -t service.ports=hello;85;8085
+
+* Expose an UDP Service (we call it `udp`) on a port (`95`) which is used 
internally by your application (`9095`):
++
+[source,console]
+$ kamel run MyUDPServer.java -t container.ports=udp;95;UDP -t 
service.ports=udp;95;9095;UDP
\ No newline at end of file
diff --git a/e2e/common/traits/service_test.go 
b/e2e/common/traits/service_test.go
index 0aadb2fdd..386172fcf 100644
--- a/e2e/common/traits/service_test.go
+++ b/e2e/common/traits/service_test.go
@@ -24,13 +24,16 @@ package common
 
 import (
        "context"
+       "fmt"
        "testing"
+       "time"
 
        . "github.com/onsi/gomega"
 
        corev1 "k8s.io/api/core/v1"
 
        . "github.com/apache/camel-k/v2/e2e/support"
+       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 )
 
 func TestServiceTrait(t *testing.T) {
@@ -97,3 +100,33 @@ func TestServiceTrait(t *testing.T) {
                })
        })
 }
+
+func TestPortsServiceTrait(t *testing.T) {
+       t.Parallel()
+       WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns string) {
+               t.Run("Service on port 8085", func(t *testing.T) {
+                       name := RandomizedSuffixName("svc")
+                       g.Expect(KamelRun(t, ctx, ns, 
"files/PlatformHttpServer.java",
+                               "-p", "quarkus.http.port=8085",
+                               "-t", "container.ports=hello;8085",
+                               "-t", "service.ports=hello;85;8085",
+                               "--name", name,
+                       ).Execute()).To(Succeed())
+                       g.Eventually(IntegrationConditionStatus(t, ctx, ns, 
name, v1.IntegrationConditionReady)).
+                               Should(Equal(corev1.ConditionTrue))
+                       // We cannot use the health trait to make sure the 
application is ready to
+                       // get requests as we're sharing the service port.
+                       g.Eventually(IntegrationLogs(t, ctx, ns, name), 
TestTimeoutMedium).Should(ContainSubstring("Listening on: http://0.0.0.0:8085";))
+
+                       response, err := 
TestClient(t).CoreV1().RESTClient().Get().
+                               
AbsPath(fmt.Sprintf("/api/v1/namespaces/%s/services/%s:%d/proxy/hello/", ns, 
name, 85)).
+                               SetHeader("name", "service-test").
+                               Timeout(30 * time.Second).
+                               DoRaw(ctx)
+
+                       g.Expect(err).ToNot(HaveOccurred())
+                       g.Expect(string(response)).To(Equal("Hello 
service-test"))
+               })
+
+       })
+}
diff --git a/helm/camel-k/crds/camel-k-crds.yaml 
b/helm/camel-k/crds/camel-k-crds.yaml
index 79b9c0be1..2e44d3ed9 100644
--- a/helm/camel-k/crds/camel-k-crds.yaml
+++ b/helm/camel-k/crds/camel-k-crds.yaml
@@ -4000,8 +4000,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -4029,15 +4029,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -4064,13 +4073,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -5394,6 +5403,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -6232,8 +6251,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -6261,15 +6280,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -6296,13 +6324,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -7626,6 +7654,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -8366,8 +8404,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -8395,15 +8433,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -8430,13 +8477,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -9760,6 +9807,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -10477,8 +10534,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -10506,15 +10563,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -10541,13 +10607,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -11871,6 +11937,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -19042,8 +19118,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -19071,15 +19147,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -19106,13 +19191,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -20436,6 +20521,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -21102,8 +21197,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -21131,15 +21226,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -21166,13 +21270,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -22496,6 +22600,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -31025,8 +31139,8 @@ spec:
                             description: 'Deprecated: no longer in use.'
                             type: boolean
                           expose:
-                            description: Can be used to enable/disable 
exposure via
-                              kubernetes Service.
+                            description: Can be used to enable/disable http 
exposure
+                              via kubernetes Service.
                             type: boolean
                           image:
                             description: |-
@@ -31054,15 +31168,24 @@ spec:
                               by default.
                             type: string
                           port:
-                            description: To configure a different port exposed 
by
-                              the container (default `8080`).
+                            description: To configure a different http port 
exposed
+                              by the container (default `8080`).
                             format: int32
                             type: integer
                           portName:
-                            description: To configure a different port name 
for the
-                              port exposed by the container. It defaults to 
`http`
-                              only when the `expose` parameter is true.
+                            description: |-
+                              To configure a different http port name for the 
port exposed by the container.
+                              It defaults to `http` only when the `expose` 
parameter is true.
                             type: string
+                          ports:
+                            description: |-
+                              List of container ports available in the 
container (syntax: <port-name>;<port-number>[;port-protocol]).
+                              When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                              Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                              Don't use in Knative based environments.
+                            items:
+                              type: string
+                            type: array
                           requestCPU:
                             description: The minimum amount of CPU required 
(default
                               125 millicores).
@@ -31090,12 +31213,12 @@ spec:
                             type: string
                           servicePort:
                             description: To configure under which service port 
the
-                              container port is to be exposed (default `80`).
+                              http container port is to be exposed (default 
`80`).
                             format: int32
                             type: integer
                           servicePortName:
                             description: To configure under which service port 
name
-                              the container port is to be exposed (default 
`http`).
+                              the http container port is to be exposed 
(default `http`).
                             type: string
                         type: object
                       cron:
@@ -32422,6 +32545,16 @@ spec:
                               Enable Service to be exposed as NodePort 
(default `false`).
                               Deprecated: Use service type instead.
                             type: boolean
+                          ports:
+                            description: |-
+                              List of container ports available in the 
container to expose
+                              (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                              When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                              Don't use this for the primary http managed port 
(which is managed by container trait).
+                              Don't use in Knative based environments.
+                            items:
+                              type: string
+                            type: array
                           type:
                             description: The type of service to be used, 
either 'ClusterIP',
                               'NodePort' or 'LoadBalancer'.
diff --git a/pkg/apis/camel/v1/trait/container.go 
b/pkg/apis/camel/v1/trait/container.go
index cffa4f928..abdafac4e 100644
--- a/pkg/apis/camel/v1/trait/container.go
+++ b/pkg/apis/camel/v1/trait/container.go
@@ -36,15 +36,21 @@ type ContainerTrait struct {
        LimitCPU string `property:"limit-cpu" json:"limitCPU,omitempty"`
        // The maximum amount of memory to be provided (default 512 Mi).
        LimitMemory string `property:"limit-memory" 
json:"limitMemory,omitempty"`
-       // Can be used to enable/disable exposure via kubernetes Service.
+       // List of container ports available in the container (syntax: 
<port-name>;<port-number>[;port-protocol]).
+       // When omitted, `port-protocol` (admitted values `TCP`, `UDP` or 
`SCTP`) is `TCP`.
+       // Don't use this for the primary http managed port (for which case you 
need to use `portName` and `port`).
+       // Don't use in Knative based environments.
+       Ports []string `property:"ports" json:"ports,omitempty"`
+       // Can be used to enable/disable http exposure via kubernetes Service.
        Expose *bool `property:"expose" json:"expose,omitempty"`
-       // To configure a different port exposed by the container (default 
`8080`).
+       // To configure a different http port exposed by the container (default 
`8080`).
        Port int32 `property:"port" json:"port,omitempty"`
-       // To configure a different port name for the port exposed by the 
container. It defaults to `http` only when the `expose` parameter is true.
+       // To configure a different http port name for the port exposed by the 
container.
+       // It defaults to `http` only when the `expose` parameter is true.
        PortName string `property:"port-name" json:"portName,omitempty"`
-       // To configure under which service port the container port is to be 
exposed (default `80`).
+       // To configure under which service port the http container port is to 
be exposed (default `80`).
        ServicePort int32 `property:"service-port" json:"servicePort,omitempty"`
-       // To configure under which service port name the container port is to 
be exposed (default `http`).
+       // To configure under which service port name the http container port 
is to be exposed (default `http`).
        ServicePortName string `property:"service-port-name" 
json:"servicePortName,omitempty"`
        // The main container name. It's named `integration` by default.
        Name string `property:"name" json:"name,omitempty"`
diff --git a/pkg/apis/camel/v1/trait/service.go 
b/pkg/apis/camel/v1/trait/service.go
index ed3d53136..b57cb23d2 100644
--- a/pkg/apis/camel/v1/trait/service.go
+++ b/pkg/apis/camel/v1/trait/service.go
@@ -17,8 +17,8 @@ limitations under the License.
 
 package trait
 
-// The Service trait exposes the integration with a Service resource so that 
it can be accessed by other applications
-// (or integrations) in the same namespace.
+// The Service trait exposes the Integration with a Service resource so that 
it can be accessed by other applications
+// (or Integrations) in the same namespace.
 //
 // NOTE: this trait is automatically disabled if the Knative Service trait is 
enabled.
 //
@@ -39,6 +39,12 @@ type ServiceTrait struct {
        Annotations map[string]string `property:"annotations" 
json:"annotations,omitempty"`
        // The labels added to the Service object.
        Labels map[string]string `property:"labels" json:"labels,omitempty"`
+       // List of container ports available in the container to expose
+       // (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+       // When omitted, `port-protocol` (admitted values `TCP`, `UDP` or 
`SCTP`) is `TCP`.
+       // Don't use this for the primary http managed port (which is managed 
by container trait).
+       // Don't use in Knative based environments.
+       Ports []string `property:"ports" json:"ports,omitempty"`
 }
 
 type ServiceType string
diff --git a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go 
b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
index 85011d3c1..492853e99 100644
--- a/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/trait/zz_generated.deepcopy.go
@@ -181,6 +181,11 @@ func (in *ContainerTrait) DeepCopyInto(out 
*ContainerTrait) {
                *out = new(bool)
                **out = **in
        }
+       if in.Ports != nil {
+               in, out := &in.Ports, &out.Ports
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
        if in.Expose != nil {
                in, out := &in.Expose, &out.Expose
                *out = new(bool)
@@ -1252,6 +1257,11 @@ func (in *ServiceTrait) DeepCopyInto(out *ServiceTrait) {
                        (*out)[key] = val
                }
        }
+       if in.Ports != nil {
+               in, out := &in.Ports, &out.Ports
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new ServiceTrait.
diff --git 
a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
index 3fa5ea073..323f89d15 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationplatforms.yaml
@@ -769,8 +769,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -798,15 +798,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -833,13 +842,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -2163,6 +2172,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -3001,8 +3020,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -3030,15 +3049,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -3065,13 +3093,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -4395,6 +4423,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
diff --git 
a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
index 70b24286d..9a3f638f0 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml
@@ -637,8 +637,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -666,15 +666,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -701,13 +710,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -2031,6 +2040,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -2748,8 +2767,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -2777,15 +2796,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -2812,13 +2840,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -4142,6 +4170,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
index d2f1275ce..5079a866f 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml
@@ -7071,8 +7071,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -7100,15 +7100,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -7135,13 +7144,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -8465,6 +8474,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
@@ -9131,8 +9150,8 @@ spec:
                         description: 'Deprecated: no longer in use.'
                         type: boolean
                       expose:
-                        description: Can be used to enable/disable exposure 
via kubernetes
-                          Service.
+                        description: Can be used to enable/disable http 
exposure via
+                          kubernetes Service.
                         type: boolean
                       image:
                         description: |-
@@ -9160,15 +9179,24 @@ spec:
                           by default.
                         type: string
                       port:
-                        description: To configure a different port exposed by 
the
-                          container (default `8080`).
+                        description: To configure a different http port 
exposed by
+                          the container (default `8080`).
                         format: int32
                         type: integer
                       portName:
-                        description: To configure a different port name for 
the port
-                          exposed by the container. It defaults to `http` only 
when
-                          the `expose` parameter is true.
+                        description: |-
+                          To configure a different http port name for the port 
exposed by the container.
+                          It defaults to `http` only when the `expose` 
parameter is true.
                         type: string
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
(syntax: <port-name>;<port-number>[;port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       requestCPU:
                         description: The minimum amount of CPU required 
(default 125
                           millicores).
@@ -9195,13 +9223,13 @@ spec:
                         - RuntimeDefault
                         type: string
                       servicePort:
-                        description: To configure under which service port the 
container
-                          port is to be exposed (default `80`).
+                        description: To configure under which service port the 
http
+                          container port is to be exposed (default `80`).
                         format: int32
                         type: integer
                       servicePortName:
                         description: To configure under which service port 
name the
-                          container port is to be exposed (default `http`).
+                          http container port is to be exposed (default 
`http`).
                         type: string
                     type: object
                   cron:
@@ -10525,6 +10553,16 @@ spec:
                           Enable Service to be exposed as NodePort (default 
`false`).
                           Deprecated: Use service type instead.
                         type: boolean
+                      ports:
+                        description: |-
+                          List of container ports available in the container 
to expose
+                          (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                          When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                          Don't use this for the primary http managed port 
(which is managed by container trait).
+                          Don't use in Knative based environments.
+                        items:
+                          type: string
+                        type: array
                       type:
                         description: The type of service to be used, either 
'ClusterIP',
                           'NodePort' or 'LoadBalancer'.
diff --git a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml 
b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
index e8f8fbb0f..bc114c70e 100644
--- a/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
+++ b/pkg/resources/config/crd/bases/camel.apache.org_pipes.yaml
@@ -7123,8 +7123,8 @@ spec:
                             description: 'Deprecated: no longer in use.'
                             type: boolean
                           expose:
-                            description: Can be used to enable/disable 
exposure via
-                              kubernetes Service.
+                            description: Can be used to enable/disable http 
exposure
+                              via kubernetes Service.
                             type: boolean
                           image:
                             description: |-
@@ -7152,15 +7152,24 @@ spec:
                               by default.
                             type: string
                           port:
-                            description: To configure a different port exposed 
by
-                              the container (default `8080`).
+                            description: To configure a different http port 
exposed
+                              by the container (default `8080`).
                             format: int32
                             type: integer
                           portName:
-                            description: To configure a different port name 
for the
-                              port exposed by the container. It defaults to 
`http`
-                              only when the `expose` parameter is true.
+                            description: |-
+                              To configure a different http port name for the 
port exposed by the container.
+                              It defaults to `http` only when the `expose` 
parameter is true.
                             type: string
+                          ports:
+                            description: |-
+                              List of container ports available in the 
container (syntax: <port-name>;<port-number>[;port-protocol]).
+                              When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                              Don't use this for the primary http managed port 
(for which case you need to use `portName` and `port`).
+                              Don't use in Knative based environments.
+                            items:
+                              type: string
+                            type: array
                           requestCPU:
                             description: The minimum amount of CPU required 
(default
                               125 millicores).
@@ -7188,12 +7197,12 @@ spec:
                             type: string
                           servicePort:
                             description: To configure under which service port 
the
-                              container port is to be exposed (default `80`).
+                              http container port is to be exposed (default 
`80`).
                             format: int32
                             type: integer
                           servicePortName:
                             description: To configure under which service port 
name
-                              the container port is to be exposed (default 
`http`).
+                              the http container port is to be exposed 
(default `http`).
                             type: string
                         type: object
                       cron:
@@ -8520,6 +8529,16 @@ spec:
                               Enable Service to be exposed as NodePort 
(default `false`).
                               Deprecated: Use service type instead.
                             type: boolean
+                          ports:
+                            description: |-
+                              List of container ports available in the 
container to expose
+                              (syntax: 
<port-name>;<port-number>;<container-port-number>[;<port-protocol]).
+                              When omitted, `port-protocol` (admitted values 
`TCP`, `UDP` or `SCTP`) is `TCP`.
+                              Don't use this for the primary http managed port 
(which is managed by container trait).
+                              Don't use in Knative based environments.
+                            items:
+                              type: string
+                            type: array
                           type:
                             description: The type of service to be used, 
either 'ClusterIP',
                               'NodePort' or 'LoadBalancer'.
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index d29b57700..e4363af56 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -20,6 +20,8 @@ package trait
 import (
        "fmt"
        "path/filepath"
+       "strconv"
+       "strings"
 
        appsv1 "k8s.io/api/apps/v1"
        batchv1 "k8s.io/api/batch/v1"
@@ -61,6 +63,14 @@ const (
 type containerTrait struct {
        BasePlatformTrait
        traitv1.ContainerTrait `property:",squash"`
+       containerPorts         []containerPort
+}
+
+// containerPort is supporting port parsing.
+type containerPort struct {
+       name     string
+       port     int32
+       protocol string
 }
 
 func newContainerTrait() Trait {
@@ -89,6 +99,11 @@ func (t *containerTrait) Configure(e *Environment) (bool, 
*TraitCondition, error
        if !isValidPullPolicy(t.ImagePullPolicy) {
                return false, nil, fmt.Errorf("unsupported pull policy %s", 
t.ImagePullPolicy)
        }
+       containerPorts, err := t.parseContainerPorts()
+       if err != nil {
+               return false, nil, err
+       }
+       t.containerPorts = containerPorts
 
        return true, nil, nil
 }
@@ -189,6 +204,10 @@ func (t *containerTrait) configureContainer(e 
*Environment) error {
                return err
        }
        t.configureResources(&container)
+       if !knative {
+               // Knative does not like anybody touching the container ports
+               t.configurePorts(&container)
+       }
        if knative || ptr.Deref(t.Expose, false) {
                t.configureService(e, &container, knative)
        }
@@ -204,6 +223,43 @@ func (t *containerTrait) configureContainer(e 
*Environment) error {
        return nil
 }
 
+func (t *containerTrait) configurePorts(container *corev1.Container) {
+       for _, cp := range t.containerPorts {
+               containerPort := corev1.ContainerPort{
+                       Name:          cp.name,
+                       ContainerPort: cp.port,
+                       Protocol:      corev1.Protocol(cp.protocol),
+               }
+               container.Ports = append(container.Ports, containerPort)
+       }
+}
+
+func (t *containerTrait) parseContainerPorts() ([]containerPort, error) {
+       containerPorts := make([]containerPort, 0, len(t.Ports))
+       for _, port := range t.Ports {
+               portSplit := strings.Split(port, ";")
+               if len(portSplit) < 2 {
+                       return nil, fmt.Errorf("could not parse container port 
%s properly: expected format \"port-name;port-number[;port-protocol]\"", port)
+               }
+               portInt32, err := strconv.ParseInt(portSplit[1], 10, 32)
+               if err != nil {
+                       return nil, fmt.Errorf("could not parse container port 
number in %s properly: expected port-number as a number", port)
+               }
+               cp := containerPort{
+                       name: portSplit[0],
+                       port: int32(portInt32),
+               }
+               if len(portSplit) > 2 {
+                       cp.protocol = portSplit[2]
+               } else {
+                       cp.protocol = "TCP"
+               }
+               containerPorts = append(containerPorts, cp)
+       }
+
+       return containerPorts, nil
+}
+
 func (t *containerTrait) configureService(e *Environment, container 
*corev1.Container, isKnative bool) {
        name := t.PortName
        if name == "" {
diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go
index dbc7975b3..79c7e4a06 100644
--- a/pkg/trait/container_test.go
+++ b/pkg/trait/container_test.go
@@ -676,6 +676,71 @@ func TestUserDefaultResources(t *testing.T) {
        assert.Equal(t, resource.MustParse("128Mi"), 
*d.Spec.Template.Spec.Containers[0].Resources.Requests.Memory())
 }
 
+func TestContainerPorts(t *testing.T) {
+       environment := createSettingContextEnvironment(t, 
v1.TraitProfileKubernetes)
+       environment.Integration.Spec.Traits = v1.Traits{
+               Container: &traitv1.ContainerTrait{
+                       Ports: []string{"aPort;1234", "anotherPort;12345;UDP"},
+               },
+       }
+       traitCatalog := NewCatalog(nil)
+
+       conditions, traits, err := traitCatalog.apply(environment)
+
+       require.NoError(t, err)
+       assert.NotEmpty(t, traits)
+       assert.NotEmpty(t, conditions)
+       assert.NotEmpty(t, environment.ExecutedTraits)
+       assert.NotNil(t, environment.GetTrait("deployment"))
+       assert.NotNil(t, environment.GetTrait("container"))
+
+       d := 
environment.Resources.GetDeploymentForIntegration(environment.Integration)
+
+       assert.NotNil(t, d)
+       assert.Len(t, d.Spec.Template.Spec.Containers, 1)
+       assert.Len(t, d.Spec.Template.Spec.Containers[0].Ports, 2)
+       assert.Contains(t, d.Spec.Template.Spec.Containers[0].Ports, 
corev1.ContainerPort{
+               Name:          "aPort",
+               ContainerPort: 1234,
+               Protocol:      corev1.ProtocolTCP,
+       })
+       assert.Contains(t, d.Spec.Template.Spec.Containers[0].Ports, 
corev1.ContainerPort{
+               Name:          "anotherPort",
+               ContainerPort: 12345,
+               Protocol:      corev1.ProtocolUDP,
+       })
+}
+
+func TestContainerPortsSyntaxError(t *testing.T) {
+       environment := createSettingContextEnvironment(t, 
v1.TraitProfileKubernetes)
+       environment.Integration.Spec.Traits = v1.Traits{
+               Container: &traitv1.ContainerTrait{
+                       Ports: []string{"aPort;notAnInt"},
+               },
+       }
+       traitCatalog := NewCatalog(nil)
+       _, _, err := traitCatalog.apply(environment)
+
+       require.Error(t, err)
+       assert.Equal(t,
+               "container trait configuration failed: could not parse 
container port number in aPort;notAnInt properly: "+
+                       "expected port-number as a number",
+               err.Error())
+
+       environment.Integration.Spec.Traits = v1.Traits{
+               Container: &traitv1.ContainerTrait{
+                       Ports: []string{"wrong"},
+               },
+       }
+       _, _, err = traitCatalog.apply(environment)
+
+       require.Error(t, err)
+       assert.Equal(t,
+               "container trait configuration failed: could not parse 
container port wrong properly: "+
+                       "expected format 
\"port-name;port-number[;port-protocol]\"",
+               err.Error())
+}
+
 func createSettingContextEnvironment(t *testing.T, profile v1.TraitProfile) 
*Environment {
        catalog, err := camel.DefaultCatalog()
        require.NoError(t, err)
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index c531f8feb..4e8ddc9ff 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -19,9 +19,12 @@ package trait
 
 import (
        "fmt"
+       "strconv"
+       "strings"
 
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/util/intstr"
        "k8s.io/utils/ptr"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -37,6 +40,15 @@ const (
 type serviceTrait struct {
        BaseTrait
        traitv1.ServiceTrait `property:",squash"`
+       servicePorts         []servicePort
+}
+
+// servicePort is supporting port parsing.
+type servicePort struct {
+       name          string
+       containerPort int32
+       port          int32
+       protocol      string
 }
 
 func newServiceTrait() Trait {
@@ -90,7 +102,13 @@ func (t *serviceTrait) Configure(e *Environment) (bool, 
*TraitCondition, error)
                t.Enabled = ptr.To(exposeHTTPServices)
        }
 
-       return ptr.Deref(t.Enabled, false), nil, nil
+       servicePorts, err := t.parseServicePorts()
+       if err != nil {
+               return false, nil, err
+       }
+       t.servicePorts = servicePorts
+
+       return ptr.Deref(t.Enabled, false) || len(t.servicePorts) > 0, nil, nil
 }
 
 func (t *serviceTrait) Apply(e *Environment) error {
@@ -128,6 +146,7 @@ func (t *serviceTrait) getServiceFor(itName, itNamespace 
string) *corev1.Service
        for k, v := range t.Labels {
                labels[k] = v
        }
+       ports := t.getServicePorts()
        return &corev1.Service{
                TypeMeta: metav1.TypeMeta{
                        Kind:       "Service",
@@ -140,10 +159,58 @@ func (t *serviceTrait) getServiceFor(itName, itNamespace 
string) *corev1.Service
                        Annotations: t.Annotations,
                },
                Spec: corev1.ServiceSpec{
-                       Ports: []corev1.ServicePort{},
+                       Ports: ports,
                        Selector: map[string]string{
                                v1.IntegrationLabel: itName,
                        },
                },
        }
 }
+
+func (t *serviceTrait) parseServicePorts() ([]servicePort, error) {
+       servicePorts := make([]servicePort, 0, len(t.Ports))
+       for _, port := range t.Ports {
+               portSplit := strings.Split(port, ";")
+               if len(portSplit) < 3 {
+                       return nil, fmt.Errorf("could not parse service port %s 
properly: expected format "+
+                               
"\"port-name;port-number;container-port-number[;port-protocol]\"", port)
+               }
+               servicePortInt32, err := strconv.ParseInt(portSplit[1], 10, 32)
+               if err != nil {
+                       return nil, fmt.Errorf("could not parse port number in 
%s properly: expected port-number as a number", port)
+               }
+               containerPortInt32, err := strconv.ParseInt(portSplit[2], 10, 
32)
+               if err != nil {
+                       return nil, fmt.Errorf("could not parse container port 
number in %s properly: expected container-port-number as a number", port)
+               }
+               sp := servicePort{
+                       name:          portSplit[0],
+                       containerPort: int32(containerPortInt32),
+                       port:          int32(servicePortInt32),
+               }
+               protocol := "TCP"
+               if len(portSplit) > 3 {
+                       protocol = portSplit[3]
+               }
+               sp.protocol = protocol
+               servicePorts = append(servicePorts, sp)
+       }
+
+       return servicePorts, nil
+}
+
+func (t *serviceTrait) getServicePorts() []corev1.ServicePort {
+       ports := make([]corev1.ServicePort, 0, len(t.servicePorts))
+       for _, port := range t.servicePorts {
+               p := corev1.ServicePort{
+                       Name: port.name,
+                       Port: port.port,
+                       TargetPort: intstr.IntOrString{
+                               IntVal: port.containerPort,
+                       },
+                       Protocol: corev1.Protocol(port.protocol),
+               }
+               ports = append(ports, p)
+       }
+       return ports
+}
diff --git a/pkg/trait/service_test.go b/pkg/trait/service_test.go
index 7202112f6..e21930b9e 100644
--- a/pkg/trait/service_test.go
+++ b/pkg/trait/service_test.go
@@ -26,6 +26,7 @@ import (
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/util/intstr"
        "k8s.io/utils/ptr"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -831,3 +832,94 @@ func TestServiceAnnotationsAndLables(t *testing.T) {
        assert.Equal(t, "v2", s.Labels["label-2"])
        assert.Equal(t, ServiceTestName, s.Labels[v1.IntegrationLabel])
 }
+
+func TestServicePorts(t *testing.T) {
+       catalog, err := camel.DefaultCatalog()
+       require.NoError(t, err)
+
+       client, _ := internal.NewFakeClient()
+       traitCatalog := NewCatalog(nil)
+
+       compressedRoute, err := 
gzip.CompressBase64([]byte(`from("timer:test").log("hello")`))
+       require.NoError(t, err)
+
+       environment := Environment{
+               CamelCatalog: catalog,
+               Catalog:      traitCatalog,
+               Client:       client,
+               Integration: &v1.Integration{
+                       ObjectMeta: metav1.ObjectMeta{
+                               Name:      ServiceTestName,
+                               Namespace: "ns",
+                       },
+                       Status: v1.IntegrationStatus{
+                               Phase: v1.IntegrationPhaseDeploying,
+                       },
+                       Spec: v1.IntegrationSpec{
+                               Profile: v1.TraitProfileKubernetes,
+                               Sources: []v1.SourceSpec{
+                                       {
+                                               DataSpec: v1.DataSpec{
+                                                       Name:        
"routes.js",
+                                                       Content:     
string(compressedRoute),
+                                                       Compression: true,
+                                               },
+                                               Language: v1.LanguageJavaScript,
+                                       },
+                               },
+                               Traits: v1.Traits{
+                                       Service: &traitv1.ServiceTrait{
+                                               Ports: 
[]string{"my-port-1;1;8001", "my-port-udp;2;8002;UDP"},
+                                       },
+                               },
+                       },
+               },
+               IntegrationKit: &v1.IntegrationKit{
+                       Status: v1.IntegrationKitStatus{
+                               Phase: v1.IntegrationKitPhaseReady,
+                       },
+               },
+               Platform: &v1.IntegrationPlatform{
+                       Spec: v1.IntegrationPlatformSpec{
+                               Cluster: v1.IntegrationPlatformClusterOpenShift,
+                               Build: v1.IntegrationPlatformBuildSpec{
+                                       PublishStrategy: 
v1.IntegrationPlatformBuildPublishStrategyJib,
+                                       Registry:        
v1.RegistrySpec{Address: "registry"},
+                                       RuntimeVersion:  
catalog.Runtime.Version,
+                               },
+                       },
+                       Status: v1.IntegrationPlatformStatus{
+                               Phase: v1.IntegrationPlatformPhaseReady,
+                       },
+               },
+               EnvVars:        make([]corev1.EnvVar, 0),
+               ExecutedTraits: make([]Trait, 0),
+               Resources:      kubernetes.NewCollection(),
+       }
+       environment.Platform.ResyncStatusFullConfig()
+
+       _, _, err = traitCatalog.apply(&environment)
+
+       require.NoError(t, err)
+       s := environment.Resources.GetService(func(service *corev1.Service) 
bool {
+               return service.Name == ServiceTestName
+       })
+       assert.NotNil(t, s)
+       // TODO: while we don't deprecate the usage of container.port
+       // we must assume that the default port is exposed as there is no way to
+       // know if the managed port is available or not
+       //assert.Len(t, s.Spec.Ports, 2)
+       assert.Len(t, s.Spec.Ports, 3)
+       assert.Contains(t, s.Spec.Ports, corev1.ServicePort{
+               Name:       "my-port-1",
+               Port:       1,
+               TargetPort: intstr.FromInt32(8001),
+               Protocol:   corev1.ProtocolTCP,
+       })
+       assert.Contains(t, s.Spec.Ports, corev1.ServicePort{
+               Name:       "my-port-udp",
+               Port:       2,
+               TargetPort: intstr.FromInt32(8002),
+               Protocol:   corev1.ProtocolUDP,
+       })
+}


Reply via email to