You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pc...@apache.org on 2023/08/30 11:03:25 UTC

[camel-k] 02/02: feat(#1656) : jib publish strategy

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

commit 0429052fb9ff830258e924b601353b4234e93067
Author: Gaelle Fournier <ga...@gmail.com>
AuthorDate: Wed May 31 10:37:23 2023 +0200

    feat(#1656) : jib publish strategy
    
    * Add publish jib strategy compatible with incremental build and native build
    * Use google jib maven plugin
    * Use builder maven profiles trait to configure jib plugin
     * The ConfigMap is created with:
       * maven jib plugin profile content in profile.xml
       * kit as an owner
     * The Jib Profile is used in the Jib published strategy
---
 .github/workflows/builder.yml                      |   2 +-
 config/crd/bases/camel.apache.org_builds.yaml      |  37 +++
 config/samples/patch-integration-platform.yaml     |   4 +-
 docs/modules/ROOT/partials/apis/camel-k-crds.adoc  | 353 +++++++++++++++++++++
 helm/camel-k/crds/crd-build.yaml                   |  37 +++
 pkg/apis/camel/v1/build_types.go                   |   8 +
 pkg/apis/camel/v1/common_types.go                  |  11 +
 pkg/apis/camel/v1/integrationkit_types_support.go  |   2 +
 pkg/apis/camel/v1/integrationplatform_types.go     |   4 +
 pkg/apis/camel/v1/maven_types.go                   |  51 +++
 pkg/apis/camel/v1/zz_generated.deepcopy.go         | 200 ++++++++++++
 pkg/builder/jib.go                                 | 137 ++++++++
 pkg/builder/project.go                             |   7 +-
 pkg/builder/tasks.go                               |  12 +
 .../camel/applyconfiguration/camel/v1/jibtask.go   |  73 +++++
 .../camel/applyconfiguration/camel/v1/task.go      |   9 +
 pkg/client/camel/applyconfiguration/utils.go       |   2 +
 pkg/controller/build/build_pod.go                  |   2 +
 pkg/controller/build/monitor_routine.go            |   7 +
 pkg/trait/builder.go                               |  26 +-
 pkg/trait/builder_test.go                          |  23 ++
 pkg/trait/quarkus.go                               |   4 +-
 pkg/util/jib/configuration.go                      | 159 ++++++++++
 pkg/util/jib/configuration_test.go                 |  74 +++++
 pkg/util/maven/maven_command.go                    |  22 +-
 pkg/util/maven/maven_log.go                        |   2 +-
 pkg/util/maven/maven_log_test.go                   |   2 +-
 pkg/util/maven/maven_types.go                      |  11 +-
 pkg/util/util.go                                   |  11 +-
 29 files changed, 1269 insertions(+), 23 deletions(-)

diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml
index d301d1f61..2f38b31b6 100644
--- a/.github/workflows/builder.yml
+++ b/.github/workflows/builder.yml
@@ -74,7 +74,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        publisher: ["Buildah", "Spectrum", "Kaniko"]
+        publisher: ["Buildah", "Spectrum", "Kaniko", "Jib"]
 
     steps:
     - name: Checkout code
diff --git a/config/crd/bases/camel.apache.org_builds.yaml b/config/crd/bases/camel.apache.org_builds.yaml
index d5fff8964..bc1981b71 100644
--- a/config/crd/bases/camel.apache.org_builds.yaml
+++ b/config/crd/bases/camel.apache.org_builds.yaml
@@ -696,6 +696,43 @@ spec:
                           description: name of the task
                           type: string
                       type: object
+                    jib:
+                      description: a JibTask, for Jib strategy
+                      properties:
+                        baseImage:
+                          description: base image layer
+                          type: string
+                        contextDir:
+                          description: can be useful to share info with other tasks
+                          type: string
+                        image:
+                          description: final image name
+                          type: string
+                        name:
+                          description: name of the task
+                          type: string
+                        registry:
+                          description: where to publish the final image
+                          properties:
+                            address:
+                              description: the URI to access
+                              type: string
+                            ca:
+                              description: the configmap which stores the Certificate
+                                Authority
+                              type: string
+                            insecure:
+                              description: if the container registry is insecure (ie,
+                                http only)
+                              type: boolean
+                            organization:
+                              description: the registry organization
+                              type: string
+                            secret:
+                              description: the secret where credentials are stored
+                              type: string
+                          type: object
+                      type: object
                     kaniko:
                       description: a KanikoTask, for Kaniko strategy
                       properties:
diff --git a/config/samples/patch-integration-platform.yaml b/config/samples/patch-integration-platform.yaml
index f53bd4783..e7ea4f540 100644
--- a/config/samples/patch-integration-platform.yaml
+++ b/config/samples/patch-integration-platform.yaml
@@ -44,9 +44,9 @@ spec:
   #
   #
   # Build publish strategy for integrations
-  # ie. Buildah, Kaniko, S2I, Spectrum
+  # ie. Buildah, Kaniko, S2I, Spectrum, Jib
   #
-  #  publishStrategy: Buildah | Kaniko | S2I | Spectrum
+  #  publishStrategy: Buildah | Kaniko | S2I | Spectrum | Jib
   #
   # Set the camel-k runtime version
   #
diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
index 1db2f63ea..a97959a30 100644
--- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
+++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc
@@ -330,6 +330,30 @@ AddonTrait represents the configuration of an addon trait
 Generic raw message, typically a map containing the keys (trait parameters) and the values (either single text or array)
 
 
+|===
+
+[#_camel_apache_org_v1_Args]
+=== Args
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_Container, Container>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`arg` +
+string
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_Artifact]
@@ -385,6 +409,7 @@ a checksum (SHA1) of the content
 
 * <<#_camel_apache_org_v1_BuildahTask, BuildahTask>>
 * <<#_camel_apache_org_v1_BuilderTask, BuilderTask>>
+* <<#_camel_apache_org_v1_JibTask, JibTask>>
 * <<#_camel_apache_org_v1_KanikoTask, KanikoTask>>
 * <<#_camel_apache_org_v1_S2iTask, S2iTask>>
 * <<#_camel_apache_org_v1_SpectrumTask, SpectrumTask>>
@@ -1366,6 +1391,37 @@ string
 the value to assign to the configuration (syntax may vary depending on the `Type`)
 
 
+|===
+
+[#_camel_apache_org_v1_Container]
+=== Container
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_PluginConfiguration, PluginConfiguration>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`entrypoint` +
+string
+|
+
+
+
+
+|`args` +
+*xref:#_camel_apache_org_v1_Args[Args]*
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_DataSpec]
@@ -1848,6 +1904,37 @@ string
 
 
 
+|===
+
+[#_camel_apache_org_v1_ExtraDirectories]
+=== ExtraDirectories
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_PluginConfiguration, PluginConfiguration>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`paths>path` +
+*xref:#_camel_apache_org_v1_Path[[\]Path]*
+|
+
+
+
+
+|`permissions>permission` +
+*xref:#_camel_apache_org_v1_Permission[[\]Permission]*
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_Failure]
@@ -1925,6 +2012,37 @@ maximum number of attempts
 time of the attempt execution
 
 
+|===
+
+[#_camel_apache_org_v1_Filter]
+=== Filter
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_PluginExtensionConfiguration, PluginExtensionConfiguration>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`glob` +
+string
+|
+
+
+
+
+|`toLayer` +
+string
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_Flow]
@@ -3420,6 +3538,37 @@ string
 JSONSchemaURL represents a schema url.
 
 
+[#_camel_apache_org_v1_JibTask]
+=== JibTask
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_Task, Task>>
+
+JibTask is used to configure Jib
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`BaseTask` +
+*xref:#_camel_apache_org_v1_BaseTask[BaseTask]*
+|(Members of `BaseTask` are embedded into this type.)
+
+
+
+
+|`PublishTask` +
+*xref:#_camel_apache_org_v1_PublishTask[PublishTask]*
+|(Members of `PublishTask` are embedded into this type.)
+
+
+
+
+
+|===
+
 [#_camel_apache_org_v1_KameletCondition]
 === KameletCondition
 
@@ -3891,6 +4040,75 @@ e.g., `-V,--no-transfer-progress,-Dstyle.color=never`.
 See https://maven.apache.org/ref/3.8.4/maven-embedder/cli.html.
 
 
+|===
+
+[#_camel_apache_org_v1_Path]
+=== Path
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_ExtraDirectories, ExtraDirectories>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`from` +
+string
+|
+
+
+
+
+|`into` +
+string
+|
+
+
+
+
+|`excludes>exclude` +
+[]string
+|
+
+
+
+
+
+|===
+
+[#_camel_apache_org_v1_Permission]
+=== Permission
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_ExtraDirectories, ExtraDirectories>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`file` +
+string
+|
+
+
+
+
+|`mode` +
+string
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_PipeCondition]
@@ -4095,6 +4313,133 @@ string
 Selector allows to identify pods belonging to the pipe
 
 
+|===
+
+[#_camel_apache_org_v1_PluginConfiguration]
+=== PluginConfiguration
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`container` +
+*xref:#_camel_apache_org_v1_Container[Container]*
+|
+
+
+
+
+|`allowInsecureRegistries` +
+string
+|
+
+
+
+
+|`extraDirectories` +
+*xref:#_camel_apache_org_v1_ExtraDirectories[ExtraDirectories]*
+|
+
+
+
+
+|`pluginExtensions` +
+*xref:#_camel_apache_org_v1_PluginExtensions[PluginExtensions]*
+|
+
+
+
+
+
+|===
+
+[#_camel_apache_org_v1_PluginExtension]
+=== PluginExtension
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_PluginExtensions, PluginExtensions>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`implementation` +
+string
+|
+
+
+
+
+|`configuration` +
+*xref:#_camel_apache_org_v1_PluginExtensionConfiguration[PluginExtensionConfiguration]*
+|
+
+
+
+
+
+|===
+
+[#_camel_apache_org_v1_PluginExtensionConfiguration]
+=== PluginExtensionConfiguration
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_PluginExtension, PluginExtension>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`filters>Filter` +
+*xref:#_camel_apache_org_v1_Filter[[\]Filter]*
+|
+
+
+
+
+|`_implementation` +
+string
+|
+
+
+
+
+
+|===
+
+[#_camel_apache_org_v1_PluginExtensions]
+=== PluginExtensions
+
+*Appears on:*
+
+* <<#_camel_apache_org_v1_PluginConfiguration, PluginConfiguration>>
+
+
+
+[cols="2,2a",options="header"]
+|===
+|Field
+|Description
+
+|`pluginExtension` +
+*xref:#_camel_apache_org_v1_PluginExtension[PluginExtension]*
+|
+
+
+
+
+
 |===
 
 [#_camel_apache_org_v1_PluginProperties]
@@ -4277,6 +4622,7 @@ the specification
 *Appears on:*
 
 * <<#_camel_apache_org_v1_BuildahTask, BuildahTask>>
+* <<#_camel_apache_org_v1_JibTask, JibTask>>
 * <<#_camel_apache_org_v1_KanikoTask, KanikoTask>>
 * <<#_camel_apache_org_v1_SpectrumTask, SpectrumTask>>
 
@@ -4836,6 +5182,13 @@ a SpectrumTask, for Spectrum strategy
 
 a S2iTask, for S2I strategy
 
+|`jib` +
+*xref:#_camel_apache_org_v1_JibTask[JibTask]*
+|
+
+
+a JibTask, for Jib strategy
+
 |`custom` +
 *xref:#_camel_apache_org_v1_UserTask[UserTask]*
 |
diff --git a/helm/camel-k/crds/crd-build.yaml b/helm/camel-k/crds/crd-build.yaml
index d5fff8964..bc1981b71 100644
--- a/helm/camel-k/crds/crd-build.yaml
+++ b/helm/camel-k/crds/crd-build.yaml
@@ -696,6 +696,43 @@ spec:
                           description: name of the task
                           type: string
                       type: object
+                    jib:
+                      description: a JibTask, for Jib strategy
+                      properties:
+                        baseImage:
+                          description: base image layer
+                          type: string
+                        contextDir:
+                          description: can be useful to share info with other tasks
+                          type: string
+                        image:
+                          description: final image name
+                          type: string
+                        name:
+                          description: name of the task
+                          type: string
+                        registry:
+                          description: where to publish the final image
+                          properties:
+                            address:
+                              description: the URI to access
+                              type: string
+                            ca:
+                              description: the configmap which stores the Certificate
+                                Authority
+                              type: string
+                            insecure:
+                              description: if the container registry is insecure (ie,
+                                http only)
+                              type: boolean
+                            organization:
+                              description: the registry organization
+                              type: string
+                            secret:
+                              description: the secret where credentials are stored
+                              type: string
+                          type: object
+                      type: object
                     kaniko:
                       description: a KanikoTask, for Kaniko strategy
                       properties:
diff --git a/pkg/apis/camel/v1/build_types.go b/pkg/apis/camel/v1/build_types.go
index e928c66c9..5c8dcb2d5 100644
--- a/pkg/apis/camel/v1/build_types.go
+++ b/pkg/apis/camel/v1/build_types.go
@@ -67,6 +67,8 @@ type Task struct {
 	Spectrum *SpectrumTask `json:"spectrum,omitempty"`
 	// a S2iTask, for S2I strategy
 	S2i *S2iTask `json:"s2i,omitempty"`
+	// a JibTask, for Jib strategy
+	Jib *JibTask `json:"jib,omitempty"`
 
 	// User customizable task execution
 
@@ -154,6 +156,12 @@ type KanikoTaskCache struct {
 	PersistentVolumeClaim string `json:"persistentVolumeClaim,omitempty"`
 }
 
+// JibTask is used to configure Jib
+type JibTask struct {
+	BaseTask    `json:",inline"`
+	PublishTask `json:",inline"`
+}
+
 // SpectrumTask is used to configure Spectrum
 type SpectrumTask struct {
 	BaseTask    `json:",inline"`
diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go
index 0f3e2c8a3..51b419305 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -302,6 +302,17 @@ type ValueSource struct {
 	SecretKeyRef *corev1.SecretKeySelector `json:"secretKeyRef,omitempty"`
 }
 
+// String returns a string representation of ValueSource
+func (o *ValueSource) String() string {
+	text := ""
+	if o.ConfigMapKeyRef != nil {
+		text = "configmap:" + o.ConfigMapKeyRef.Name + "/" + o.ConfigMapKeyRef.Key
+	} else if o.SecretKeyRef != nil {
+		text = "secret:" + o.SecretKeyRef.Name + "/" + o.SecretKeyRef.Key
+	}
+	return text
+}
+
 // RuntimeSpec represents the configuration for the Java runtime in charge to execute the Camel application
 type RuntimeSpec struct {
 	// Camel K Runtime version
diff --git a/pkg/apis/camel/v1/integrationkit_types_support.go b/pkg/apis/camel/v1/integrationkit_types_support.go
index 87d7667be..c4c10a608 100644
--- a/pkg/apis/camel/v1/integrationkit_types_support.go
+++ b/pkg/apis/camel/v1/integrationkit_types_support.go
@@ -24,6 +24,8 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+const IntegrationKitLabel = "camel.apache.org/integrationkit"
+
 func NewIntegrationKit(namespace string, name string) *IntegrationKit {
 	return &IntegrationKit{
 		TypeMeta: metav1.TypeMeta{
diff --git a/pkg/apis/camel/v1/integrationplatform_types.go b/pkg/apis/camel/v1/integrationplatform_types.go
index d87737358..65dbbfdb8 100644
--- a/pkg/apis/camel/v1/integrationplatform_types.go
+++ b/pkg/apis/camel/v1/integrationplatform_types.go
@@ -165,6 +165,9 @@ const (
 	// IntegrationPlatformBuildPublishStrategySpectrum uses Spectrum project (https://github.com/container-tools/spectrum)
 	// in order to push the incremental images to the image repository. It is the default choice on vanilla Kubernetes cluster
 	IntegrationPlatformBuildPublishStrategySpectrum IntegrationPlatformBuildPublishStrategy = "Spectrum"
+	// IntegrationPlatformBuildPublishStrategyJib uses Jib maven plugin (https://github.com/GoogleContainerTools/jib)
+	// in order to push the incremental images to the image repository.
+	IntegrationPlatformBuildPublishStrategyJib IntegrationPlatformBuildPublishStrategy = "Jib"
 )
 
 // IntegrationPlatformBuildPublishStrategies the list of all available publish strategies
@@ -173,6 +176,7 @@ var IntegrationPlatformBuildPublishStrategies = []IntegrationPlatformBuildPublis
 	IntegrationPlatformBuildPublishStrategyKaniko,
 	IntegrationPlatformBuildPublishStrategyS2I,
 	IntegrationPlatformBuildPublishStrategySpectrum,
+	IntegrationPlatformBuildPublishStrategyJib,
 }
 
 // IntegrationPlatformPhase is the phase of an IntegrationPlatform
diff --git a/pkg/apis/camel/v1/maven_types.go b/pkg/apis/camel/v1/maven_types.go
index 0650279e3..f2d0bb7b6 100644
--- a/pkg/apis/camel/v1/maven_types.go
+++ b/pkg/apis/camel/v1/maven_types.go
@@ -106,3 +106,54 @@ type StringOrProperties struct {
 
 type Properties map[string]string
 type PluginProperties map[string]StringOrProperties
+
+type PluginConfiguration struct {
+	Container               Container        `xml:"container" json:"container"`
+	AllowInsecureRegistries string           `xml:"allowInsecureRegistries" json:"allowInsecureRegistries"`
+	ExtraDirectories        ExtraDirectories `xml:"extraDirectories" json:"extraDirectories"`
+	PluginExtensions        PluginExtensions `xml:"pluginExtensions" json:"pluginExtensions"`
+}
+
+type Container struct {
+	Entrypoint string `xml:"entrypoint" json:"entrypoint"`
+	Args       Args   `xml:"args" json:"args"`
+}
+
+type Args struct {
+	Arg string `xml:"arg" json:"arg"`
+}
+
+type ExtraDirectories struct {
+	Paths       []Path       `xml:"paths>path" json:"paths>path"`
+	Permissions []Permission `xml:"permissions>permission,omitempty" json:"permissions>permission,omitempty"`
+}
+
+type Path struct {
+	From     string   `xml:"from" json:"from"`
+	Into     string   `xml:"into" json:"into"`
+	Excludes []string `xml:"excludes>exclude,omitempty" json:"excludes>exclude,omitempty"`
+}
+
+type Permission struct {
+	File string `xml:"file" json:"file"`
+	Mode string `xml:"mode" json:"mode"`
+}
+
+type PluginExtensions struct {
+	PluginExtension PluginExtension `xml:"pluginExtension" json:"pluginExtension"`
+}
+
+type PluginExtension struct {
+	Implementation string                       `xml:"implementation" json:"implementation"`
+	Configuration  PluginExtensionConfiguration `xml:"configuration" json:"configuration"`
+}
+
+type PluginExtensionConfiguration struct {
+	Filters        []Filter `xml:"filters>Filter" json:"filters>Filter"`
+	Implementation string   `xml:"implementation,attr" json:"_implementation"`
+}
+
+type Filter struct {
+	Glob    string `xml:"glob" json:"glob"`
+	ToLayer string `xml:"toLayer,omitempty" json:"toLayer,omitempty"`
+}
diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go b/pkg/apis/camel/v1/zz_generated.deepcopy.go
index cc0853d90..533002897 100644
--- a/pkg/apis/camel/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go
@@ -33,6 +33,21 @@ func (in *AddonTrait) DeepCopy() *AddonTrait {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Args) DeepCopyInto(out *Args) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Args.
+func (in *Args) DeepCopy() *Args {
+	if in == nil {
+		return nil
+	}
+	out := new(Args)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Artifact) DeepCopyInto(out *Artifact) {
 	*out = *in
@@ -608,6 +623,22 @@ func (in *ConfigurationSpec) DeepCopy() *ConfigurationSpec {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Container) DeepCopyInto(out *Container) {
+	*out = *in
+	out.Args = in.Args
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container.
+func (in *Container) DeepCopy() *Container {
+	if in == nil {
+		return nil
+	}
+	out := new(Container)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *DataSpec) DeepCopyInto(out *DataSpec) {
 	*out = *in
@@ -894,6 +925,33 @@ func (in *ExternalDocumentation) DeepCopy() *ExternalDocumentation {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ExtraDirectories) DeepCopyInto(out *ExtraDirectories) {
+	*out = *in
+	if in.Paths != nil {
+		in, out := &in.Paths, &out.Paths
+		*out = make([]Path, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	if in.Permissions != nil {
+		in, out := &in.Permissions, &out.Permissions
+		*out = make([]Permission, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraDirectories.
+func (in *ExtraDirectories) DeepCopy() *ExtraDirectories {
+	if in == nil {
+		return nil
+	}
+	out := new(ExtraDirectories)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Failure) DeepCopyInto(out *Failure) {
 	*out = *in
@@ -927,6 +985,21 @@ func (in *FailureRecovery) DeepCopy() *FailureRecovery {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Filter) DeepCopyInto(out *Filter) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter.
+func (in *Filter) DeepCopy() *Filter {
+	if in == nil {
+		return nil
+	}
+	out := new(Filter)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Flow) DeepCopyInto(out *Flow) {
 	*out = *in
@@ -1735,6 +1808,23 @@ func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *JibTask) DeepCopyInto(out *JibTask) {
+	*out = *in
+	out.BaseTask = in.BaseTask
+	out.PublishTask = in.PublishTask
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JibTask.
+func (in *JibTask) DeepCopy() *JibTask {
+	if in == nil {
+		return nil
+	}
+	out := new(JibTask)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Kamelet) DeepCopyInto(out *Kamelet) {
 	*out = *in
@@ -2038,6 +2128,41 @@ func (in *MavenSpec) DeepCopy() *MavenSpec {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Path) DeepCopyInto(out *Path) {
+	*out = *in
+	if in.Excludes != nil {
+		in, out := &in.Excludes, &out.Excludes
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Path.
+func (in *Path) DeepCopy() *Path {
+	if in == nil {
+		return nil
+	}
+	out := new(Path)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Permission) DeepCopyInto(out *Permission) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Permission.
+func (in *Permission) DeepCopy() *Permission {
+	if in == nil {
+		return nil
+	}
+	out := new(Permission)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Pipe) DeepCopyInto(out *Pipe) {
 	*out = *in
@@ -2187,6 +2312,76 @@ func (in *PipeStatus) DeepCopy() *PipeStatus {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PluginConfiguration) DeepCopyInto(out *PluginConfiguration) {
+	*out = *in
+	out.Container = in.Container
+	in.ExtraDirectories.DeepCopyInto(&out.ExtraDirectories)
+	in.PluginExtensions.DeepCopyInto(&out.PluginExtensions)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfiguration.
+func (in *PluginConfiguration) DeepCopy() *PluginConfiguration {
+	if in == nil {
+		return nil
+	}
+	out := new(PluginConfiguration)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PluginExtension) DeepCopyInto(out *PluginExtension) {
+	*out = *in
+	in.Configuration.DeepCopyInto(&out.Configuration)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginExtension.
+func (in *PluginExtension) DeepCopy() *PluginExtension {
+	if in == nil {
+		return nil
+	}
+	out := new(PluginExtension)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PluginExtensionConfiguration) DeepCopyInto(out *PluginExtensionConfiguration) {
+	*out = *in
+	if in.Filters != nil {
+		in, out := &in.Filters, &out.Filters
+		*out = make([]Filter, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginExtensionConfiguration.
+func (in *PluginExtensionConfiguration) DeepCopy() *PluginExtensionConfiguration {
+	if in == nil {
+		return nil
+	}
+	out := new(PluginExtensionConfiguration)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PluginExtensions) DeepCopyInto(out *PluginExtensions) {
+	*out = *in
+	in.PluginExtension.DeepCopyInto(&out.PluginExtension)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginExtensions.
+func (in *PluginExtensions) DeepCopy() *PluginExtensions {
+	if in == nil {
+		return nil
+	}
+	out := new(PluginExtensions)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in PluginProperties) DeepCopyInto(out *PluginProperties) {
 	{
@@ -2584,6 +2779,11 @@ func (in *Task) DeepCopyInto(out *Task) {
 		*out = new(S2iTask)
 		**out = **in
 	}
+	if in.Jib != nil {
+		in, out := &in.Jib, &out.Jib
+		*out = new(JibTask)
+		**out = **in
+	}
 	if in.Custom != nil {
 		in, out := &in.Custom, &out.Custom
 		*out = new(UserTask)
diff --git a/pkg/builder/jib.go b/pkg/builder/jib.go
new file mode 100644
index 000000000..6ae130d00
--- /dev/null
+++ b/pkg/builder/jib.go
@@ -0,0 +1,137 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+   http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package builder
+
+import (
+	"context"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/client"
+	"github.com/apache/camel-k/v2/pkg/util"
+	"github.com/apache/camel-k/v2/pkg/util/jib"
+	"github.com/apache/camel-k/v2/pkg/util/log"
+	"github.com/apache/camel-k/v2/pkg/util/maven"
+)
+
+type jibTask struct {
+	c     client.Client
+	build *v1.Build
+	task  *v1.JibTask
+}
+
+var _ Task = &jibTask{}
+
+func (t *jibTask) Do(ctx context.Context) v1.BuildStatus {
+	status := v1.BuildStatus{}
+
+	baseImage := t.build.Status.BaseImage
+	if baseImage == "" {
+		baseImage = t.task.BaseImage
+		status.BaseImage = baseImage
+	}
+
+	contextDir := t.task.ContextDir
+	if contextDir == "" {
+		// Use the working directory.
+		// This is useful when the task is executed in-container,
+		// so that its WorkingDir can be used to share state and
+		// coordinate with other tasks.
+		pwd, err := os.Getwd()
+		if err != nil {
+			return status.Failed(err)
+		}
+		contextDir = filepath.Join(pwd, ContextDir)
+	}
+
+	exists, err := util.DirectoryExists(contextDir)
+	if err != nil {
+		return status.Failed(err)
+	}
+	empty, err := util.DirectoryEmpty(contextDir)
+	if err != nil {
+		return status.Failed(err)
+	}
+	if !exists || empty {
+		// this can only indicate that there are no more resources to add to the base image,
+		// because transitive resolution is the same even if spec differs.
+		log.Infof("No new image to build, reusing existing image %s", baseImage)
+		status.Image = baseImage
+		return status
+	}
+	mavenDir := strings.ReplaceAll(contextDir, ContextDir, "maven")
+
+	log.Debugf("Registry address: %s", t.task.Registry.Address)
+	log.Debugf("Base image: %s", baseImage)
+
+	registryConfigDir := ""
+	if t.task.Registry.Secret != "" {
+		registryConfigDir, err = MountSecret(ctx, t.c, t.build.Namespace, t.task.Registry.Secret)
+		if err != nil {
+			return status.Failed(err)
+		}
+	}
+
+	if registryConfigDir != "" {
+		if err := os.RemoveAll(registryConfigDir); err != nil {
+			return status.Failed(err)
+		}
+	}
+
+	// TODO refactor maven code to avoid creating a file to pass command args
+	mavenCommand, err := util.ReadFile(filepath.Join(mavenDir, "MAVEN_CONTEXT"))
+	if err != nil {
+		return status.Failed(err)
+	}
+
+	mavenArgs := make([]string, 0)
+	mavenArgs = append(mavenArgs, jib.JibMavenGoal)
+	mavenArgs = append(mavenArgs, strings.Split(string(mavenCommand), " ")...)
+	mavenArgs = append(mavenArgs, "-P", "jib")
+	mavenArgs = append(mavenArgs, jib.JibMavenToImageParam+t.task.Image)
+	mavenArgs = append(mavenArgs, jib.JibMavenFromImageParam+baseImage)
+	if t.task.Registry.Insecure {
+		mavenArgs = append(mavenArgs, jib.JibMavenInsecureRegistries+"true")
+	}
+
+	mvnCmd := "./mvnw"
+	if c, ok := os.LookupEnv("MAVEN_CMD"); ok {
+		mvnCmd = c
+	}
+	cmd := exec.CommandContext(ctx, mvnCmd, mavenArgs...)
+	cmd.Dir = mavenDir
+
+	myerror := util.RunAndLog(ctx, cmd, maven.MavenLogHandler, maven.MavenLogHandler)
+	if myerror != nil {
+		log.Errorf(myerror, "jib integration image containerization did not run successfully")
+		return status.Failed(myerror)
+	} else {
+		log.Debug("jib integration image containerization did run successfully")
+		status.Image = t.task.Image
+
+		// retrieve image digest
+		mavenDigest, errDigest := util.ReadFile(filepath.Join(mavenDir, jib.JibDigestFile))
+		if errDigest != nil {
+			return status.Failed(errDigest)
+		}
+		status.Digest = string(mavenDigest)
+	}
+
+	return status
+}
diff --git a/pkg/builder/project.go b/pkg/builder/project.go
index e31e25a56..41e44263e 100644
--- a/pkg/builder/project.go
+++ b/pkg/builder/project.go
@@ -20,6 +20,7 @@ package builder
 import (
 	"bytes"
 	"encoding/xml"
+	"fmt"
 	"os"
 	"regexp"
 	"strings"
@@ -198,10 +199,10 @@ func sanitizeDependencies(ctx *builderContext) error {
 func injectProfiles(ctx *builderContext) error {
 	if ctx.Build.Maven.Profiles != nil {
 		profiles := ""
-		for _, profile := range ctx.Build.Maven.Profiles {
-			val, err := kubernetes.ResolveValueSource(ctx.C, ctx.Client, ctx.Namespace, &profile)
+		for i := range ctx.Build.Maven.Profiles {
+			val, err := kubernetes.ResolveValueSource(ctx.C, ctx.Client, ctx.Namespace, &ctx.Build.Maven.Profiles[i])
 			if err != nil {
-				return err
+				return fmt.Errorf("could not load profile : %s: %w. ", ctx.Build.Maven.Profiles[i].String(), err)
 			}
 			if val != "" {
 				profiles += val
diff --git a/pkg/builder/tasks.go b/pkg/builder/tasks.go
index 00e575e0e..054fe3552 100644
--- a/pkg/builder/tasks.go
+++ b/pkg/builder/tasks.go
@@ -62,6 +62,12 @@ func (b *Build) Task(task v1.Task) Task {
 			build: b.build,
 			task:  task.S2i,
 		}
+	case task.Jib != nil:
+		return &jibTask{
+			c:     b.builder.client,
+			build: b.build,
+			task:  task.Jib,
+		}
 	}
 
 	return &emptyTask{
@@ -138,6 +144,12 @@ func (b *Build) TaskByName(name string) Task {
 				build: b.build,
 				task:  task.S2i,
 			}
+		case task.Jib != nil && task.Jib.Name == name:
+			return &jibTask{
+				c:     b.builder.client,
+				build: b.build,
+				task:  task.Jib,
+			}
 		}
 	}
 	return &missingTask{
diff --git a/pkg/client/camel/applyconfiguration/camel/v1/jibtask.go b/pkg/client/camel/applyconfiguration/camel/v1/jibtask.go
new file mode 100644
index 000000000..1e87d4281
--- /dev/null
+++ b/pkg/client/camel/applyconfiguration/camel/v1/jibtask.go
@@ -0,0 +1,73 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1
+
+// JibTaskApplyConfiguration represents an declarative configuration of the JibTask type for use
+// with apply.
+type JibTaskApplyConfiguration struct {
+	BaseTaskApplyConfiguration    `json:",inline"`
+	PublishTaskApplyConfiguration `json:",inline"`
+}
+
+// JibTaskApplyConfiguration constructs an declarative configuration of the JibTask type for use with
+// apply.
+func JibTask() *JibTaskApplyConfiguration {
+	return &JibTaskApplyConfiguration{}
+}
+
+// WithName sets the Name field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Name field is set to the value of the last call.
+func (b *JibTaskApplyConfiguration) WithName(value string) *JibTaskApplyConfiguration {
+	b.Name = &value
+	return b
+}
+
+// WithContextDir sets the ContextDir field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the ContextDir field is set to the value of the last call.
+func (b *JibTaskApplyConfiguration) WithContextDir(value string) *JibTaskApplyConfiguration {
+	b.ContextDir = &value
+	return b
+}
+
+// WithBaseImage sets the BaseImage field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the BaseImage field is set to the value of the last call.
+func (b *JibTaskApplyConfiguration) WithBaseImage(value string) *JibTaskApplyConfiguration {
+	b.BaseImage = &value
+	return b
+}
+
+// WithImage sets the Image field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Image field is set to the value of the last call.
+func (b *JibTaskApplyConfiguration) WithImage(value string) *JibTaskApplyConfiguration {
+	b.Image = &value
+	return b
+}
+
+// WithRegistry sets the Registry field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Registry field is set to the value of the last call.
+func (b *JibTaskApplyConfiguration) WithRegistry(value *RegistrySpecApplyConfiguration) *JibTaskApplyConfiguration {
+	b.Registry = value
+	return b
+}
diff --git a/pkg/client/camel/applyconfiguration/camel/v1/task.go b/pkg/client/camel/applyconfiguration/camel/v1/task.go
index 01fd1aa5a..a4b7912c2 100644
--- a/pkg/client/camel/applyconfiguration/camel/v1/task.go
+++ b/pkg/client/camel/applyconfiguration/camel/v1/task.go
@@ -27,6 +27,7 @@ type TaskApplyConfiguration struct {
 	Kaniko   *KanikoTaskApplyConfiguration   `json:"kaniko,omitempty"`
 	Spectrum *SpectrumTaskApplyConfiguration `json:"spectrum,omitempty"`
 	S2i      *S2iTaskApplyConfiguration      `json:"s2i,omitempty"`
+	Jib      *JibTaskApplyConfiguration      `json:"jib,omitempty"`
 	Custom   *UserTaskApplyConfiguration     `json:"custom,omitempty"`
 }
 
@@ -76,6 +77,14 @@ func (b *TaskApplyConfiguration) WithS2i(value *S2iTaskApplyConfiguration) *Task
 	return b
 }
 
+// WithJib sets the Jib field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Jib field is set to the value of the last call.
+func (b *TaskApplyConfiguration) WithJib(value *JibTaskApplyConfiguration) *TaskApplyConfiguration {
+	b.Jib = value
+	return b
+}
+
 // WithCustom sets the Custom field in the declarative configuration to the given value
 // and returns the receiver, so that objects can be built by chaining "With" function invocations.
 // If called multiple times, the Custom field is set to the value of the last call.
diff --git a/pkg/client/camel/applyconfiguration/utils.go b/pkg/client/camel/applyconfiguration/utils.go
index 1e0497534..3ce316c0e 100644
--- a/pkg/client/camel/applyconfiguration/utils.go
+++ b/pkg/client/camel/applyconfiguration/utils.go
@@ -136,6 +136,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
 		return &camelv1.IntegrationSpecApplyConfiguration{}
 	case v1.SchemeGroupVersion.WithKind("IntegrationStatus"):
 		return &camelv1.IntegrationStatusApplyConfiguration{}
+	case v1.SchemeGroupVersion.WithKind("JibTask"):
+		return &camelv1.JibTaskApplyConfiguration{}
 	case v1.SchemeGroupVersion.WithKind("JSON"):
 		return &camelv1.JSONApplyConfiguration{}
 	case v1.SchemeGroupVersion.WithKind("JSONSchemaProp"):
diff --git a/pkg/controller/build/build_pod.go b/pkg/controller/build/build_pod.go
index bb5fe31a7..686152ab3 100644
--- a/pkg/controller/build/build_pod.go
+++ b/pkg/controller/build/build_pod.go
@@ -170,6 +170,8 @@ func newBuildPod(ctx context.Context, c ctrl.Reader, client client.Client, build
 			addBuildTaskToPod(ctx, client, build, task.S2i.Name, pod)
 		case task.Spectrum != nil:
 			addBuildTaskToPod(ctx, client, build, task.Spectrum.Name, pod)
+		case task.Jib != nil:
+			addBuildTaskToPod(ctx, client, build, task.Jib.Name, pod)
 		case task.Custom != nil:
 			addCustomTaskToPod(build, task.Custom, pod)
 		}
diff --git a/pkg/controller/build/monitor_routine.go b/pkg/controller/build/monitor_routine.go
index 1d1486a38..adc566d04 100644
--- a/pkg/controller/build/monitor_routine.go
+++ b/pkg/controller/build/monitor_routine.go
@@ -148,6 +148,13 @@ tasks:
 					break tasks
 				}
 				t.ContextDir = filepath.Join(buildDir, builder.ContextDir)
+
+			} else if t := task.Jib; t != nil && t.ContextDir == "" {
+				if buildDir == "" {
+					status.Failed(fmt.Errorf("cannot determine context directory for task %s", t.Name))
+					break tasks
+				}
+				t.ContextDir = filepath.Join(buildDir, builder.ContextDir)
 			}
 
 			// Execute the task
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index 16bc17cd5..9d878661f 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -28,6 +28,7 @@ import (
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
 	"github.com/apache/camel-k/v2/pkg/builder"
+	"github.com/apache/camel-k/v2/pkg/util/jib"
 	mvn "github.com/apache/camel-k/v2/pkg/util/maven"
 	"github.com/apache/camel-k/v2/pkg/util/property"
 )
@@ -120,6 +121,18 @@ func (t *builderTrait) Apply(e *Environment) error {
 			},
 		}})
 
+	case v1.IntegrationPlatformBuildPublishStrategyJib:
+		pipelineTasks = append(pipelineTasks, v1.Task{Jib: &v1.JibTask{
+			BaseTask: v1.BaseTask{
+				Name: "jib",
+			},
+			PublishTask: v1.PublishTask{
+				BaseImage: e.Platform.Status.Build.BaseImage,
+				Image:     getImageName(e),
+				Registry:  e.Platform.Status.Build.Registry,
+			},
+		}})
+
 	case v1.IntegrationPlatformBuildPublishStrategyS2I:
 		pipelineTasks = append(pipelineTasks, v1.Task{S2i: &v1.S2iTask{
 			BaseTask: v1.BaseTask{
@@ -181,6 +194,7 @@ func (t *builderTrait) Apply(e *Environment) error {
 			ExecutorImage: executorImage,
 		}})
 	}
+
 	// add local pipeline tasks to env pipeline
 	e.Pipeline = append(e.Pipeline, pipelineTasks...)
 	return nil
@@ -284,12 +298,18 @@ func (t *builderTrait) builderTask(e *Environment) (*v1.BuilderTask, error) {
 		}
 	}
 
+	if e.Platform.Status.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategyJib {
+		if err := jib.CreateProfileConfigmap(e.Ctx, e.Client, e.IntegrationKit); err != nil {
+			return nil, fmt.Errorf("could not create default maven jib profile: %w. ", err)
+		}
+		t.MavenProfiles = append(t.MavenProfiles, "configmap:"+e.IntegrationKit.Name+"-publish-jib-profile/profile.xml")
+	}
+
 	// User provides a maven profile
 	if t.MavenProfiles != nil {
 		mavenProfiles := make([]v1.ValueSource, 0)
 		for _, v := range t.MavenProfiles {
 			if v != "" {
-				// TODO parametrize message with input
 				mavenProfile, err := v1.DecodeValueSource(v, "profile.xml",
 					"illegal profile definition, syntax: configmap|secret:resource-name[/profile path]")
 				if err != nil {
@@ -300,10 +320,6 @@ func (t *builderTrait) builderTask(e *Environment) (*v1.BuilderTask, error) {
 		}
 		task.Maven.Profiles = mavenProfiles
 	}
-	// add jib profile
-	/*if e.Platform.Status.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategyJib {
-		t.L.Info("GFO - You should add jib profile")
-	}*/
 
 	steps := make([]builder.Step, 0)
 	steps = append(steps, builder.Project.CommonSteps...)
diff --git a/pkg/trait/builder_test.go b/pkg/trait/builder_test.go
index 4ccd434d6..54151db29 100644
--- a/pkg/trait/builder_test.go
+++ b/pkg/trait/builder_test.go
@@ -126,6 +126,9 @@ func createBuilderTestEnv(cluster v1.IntegrationPlatformCluster, strategy v1.Int
 			Status: v1.IntegrationKitStatus{
 				Phase: v1.IntegrationKitPhaseBuildSubmitted,
 			},
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "my-kit",
+			},
 		},
 		Platform: &v1.IntegrationPlatform{
 			Spec: v1.IntegrationPlatformSpec{
@@ -290,5 +293,25 @@ func TestInvalidMavenProfilesBuilderTrait(t *testing.T) {
 	err := builderTrait.Apply(env)
 
 	assert.NotNil(t, err)
+	assert.Equal(t, env.IntegrationKit.Status.Phase, v1.IntegrationKitPhaseError)
+	assert.Equal(t, env.IntegrationKit.Status.Conditions[0].Status, corev1.ConditionFalse)
+	assert.Contains(t, env.IntegrationKit.Status.Conditions[0].Message, "fakeprofile")
+}
+
+func TestMavenBuilderTraitJib(t *testing.T) {
+	env := createBuilderTestEnv(v1.IntegrationPlatformClusterKubernetes, v1.IntegrationPlatformBuildPublishStrategyJib, v1.BuildStrategyRoutine)
+	builderTrait := createNominalBuilderTraitTest()
+
+	err := builderTrait.Apply(env)
 
+	assert.Nil(t, err)
+
+	assert.Equal(t, v1.ValueSource{
+		ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
+			LocalObjectReference: corev1.LocalObjectReference{
+				Name: "my-kit-publish-jib-profile",
+			},
+			Key: "profile.xml",
+		},
+	}, env.Pipeline[0].Builder.Maven.MavenSpec.Profiles[0])
 }
diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go
index ae182e740..11c4fdfaf 100644
--- a/pkg/trait/quarkus.go
+++ b/pkg/trait/quarkus.go
@@ -319,14 +319,14 @@ func (t *quarkusTrait) applyWhenBuildSubmitted(e *Environment) error {
 		}
 		steps = append(steps, builder.Image.NativeImageContext)
 		// Spectrum does not rely on Dockerfile to assemble the image
-		if e.Platform.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategySpectrum {
+		if e.Platform.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategySpectrum && e.Platform.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategyJib {
 			steps = append(steps, builder.Image.ExecutableDockerfile)
 		}
 	} else {
 		build.Maven.Properties["quarkus.package.type"] = string(traitv1.FastJarPackageType)
 		steps = append(steps, builder.Quarkus.ComputeQuarkusDependencies, builder.Image.IncrementalImageContext)
 		// Spectrum does not rely on Dockerfile to assemble the image
-		if e.Platform.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategySpectrum {
+		if e.Platform.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategySpectrum && e.Platform.Status.Build.PublishStrategy != v1.IntegrationPlatformBuildPublishStrategyJib {
 			steps = append(steps, builder.Image.JvmDockerfile)
 		}
 	}
diff --git a/pkg/util/jib/configuration.go b/pkg/util/jib/configuration.go
new file mode 100644
index 000000000..4497f9c8d
--- /dev/null
+++ b/pkg/util/jib/configuration.go
@@ -0,0 +1,159 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package jib contains utilities for jib strategy builds.
+package jib
+
+import (
+	"context"
+	"encoding/xml"
+	"fmt"
+
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/client"
+	"github.com/apache/camel-k/v2/pkg/util"
+	"github.com/apache/camel-k/v2/pkg/util/maven"
+
+	corev1 "k8s.io/api/core/v1"
+	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const JibMavenGoal = "jib:build"
+const JibMavenToImageParam = "-Djib.to.image="
+const JibMavenFromImageParam = "-Djib.from.image="
+const JibMavenInsecureRegistries = "-Djib.allowInsecureRegistries="
+const JibDigestFile = "target/jib-image.digest"
+
+type JibBuild struct {
+	Plugins []maven.Plugin `xml:"plugins>plugin,omitempty"`
+}
+
+type JibProfile struct {
+	XMLName xml.Name
+	ID      string   `xml:"id"`
+	Build   JibBuild `xml:"build,omitempty"`
+}
+
+// Create a Configmap containing the default jib profile.
+func CreateProfileConfigmap(ctx context.Context, c client.Client, kit *v1.IntegrationKit) error {
+	profile, err := jibMavenProfile()
+	if err != nil {
+		return fmt.Errorf("error generating default maven jib profile: %w. ", err)
+	}
+
+	annotations := util.CopyMap(kit.Annotations)
+	controller := true
+	blockOwnerDeletion := true
+	jibProfileConfigMap := &corev1.ConfigMap{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "ConfigMap",
+			APIVersion: "v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:        kit.Name + "-publish-jib-profile",
+			Namespace:   kit.Namespace,
+			Annotations: annotations,
+			Labels: map[string]string{
+				v1.IntegrationKitLabel: kit.Name,
+			},
+			OwnerReferences: []metav1.OwnerReference{
+				{
+					APIVersion:         kit.APIVersion,
+					Kind:               kit.Kind,
+					Name:               kit.Name,
+					UID:                kit.UID,
+					Controller:         &controller,
+					BlockOwnerDeletion: &blockOwnerDeletion,
+				}},
+		},
+		Data: map[string]string{
+			"profile.xml": profile,
+		},
+	}
+
+	err = c.Create(ctx, jibProfileConfigMap)
+	if err != nil && !k8serrors.IsAlreadyExists(err) {
+		return fmt.Errorf("error creating the configmap containing the default maven jib profile: %s: %w. ", kit.Name+"-publish-jib-profile", err)
+	}
+	return nil
+}
+
+func jibMavenProfile() (string, error) {
+	jibPlugin := maven.Plugin{
+		GroupID:    "com.google.cloud.tools",
+		ArtifactID: "jib-maven-plugin",
+		Version:    "3.3.2",
+		Dependencies: []maven.Dependency{
+			{
+				GroupID:    "com.google.cloud.tools",
+				ArtifactID: "jib-layer-filter-extension-maven",
+				Version:    "0.3.0",
+			},
+		},
+		Configuration: v1.PluginConfiguration{
+			Container: v1.Container{
+				Entrypoint: "INHERIT",
+				Args: v1.Args{
+					Arg: "jshell",
+				},
+			},
+			AllowInsecureRegistries: "true",
+			ExtraDirectories: v1.ExtraDirectories{
+				Paths: []v1.Path{
+					{
+						From: "../context",
+						Into: "/deployments",
+					},
+				},
+				Permissions: []v1.Permission{
+					{
+						File: "/deployments/*",
+						Mode: "544",
+					},
+				},
+			},
+			PluginExtensions: v1.PluginExtensions{
+				PluginExtension: v1.PluginExtension{
+					Implementation: "com.google.cloud.tools.jib.maven.extension.layerfilter.JibLayerFilterExtension",
+					Configuration: v1.PluginExtensionConfiguration{
+						Implementation: "com.google.cloud.tools.jib.maven.extension.layerfilter.Configuration",
+						Filters: []v1.Filter{
+							{
+								Glob: "/app/**",
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	jibMavenPluginProfile := JibProfile{
+		XMLName: xml.Name{Local: "profile"},
+		ID:      "jib",
+		Build: JibBuild{
+			Plugins: []maven.Plugin{jibPlugin},
+		},
+	}
+	content, err := util.EncodeXMLWithoutHeader(jibMavenPluginProfile)
+	if err != nil {
+		return "", err
+	}
+	return string(content), nil
+
+}
diff --git a/pkg/util/jib/configuration_test.go b/pkg/util/jib/configuration_test.go
new file mode 100644
index 000000000..159382237
--- /dev/null
+++ b/pkg/util/jib/configuration_test.go
@@ -0,0 +1,74 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package jib
+
+import (
+	"context"
+	"strings"
+	"testing"
+
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/util/test"
+	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
+	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+func TestJibMavenProfile(t *testing.T) {
+	profile, err := jibMavenProfile()
+
+	assert.NoError(t, err)
+	assert.True(t, strings.HasPrefix(profile, "<profile>"))
+	assert.True(t, strings.HasSuffix(profile, "</profile>"))
+
+}
+
+func TestJibConfigMap(t *testing.T) {
+	ctx := context.TODO()
+	c, _ := test.NewFakeClient()
+	kit := &v1.IntegrationKit{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: v1.SchemeGroupVersion.String(),
+			Kind:       v1.IntegrationKitKind,
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "test",
+			Namespace: "ns",
+			UID:       types.UID("8dc44a2b-063c-490e-ae02-1fab285ac70a"),
+		},
+		Status: v1.IntegrationKitStatus{
+			Phase: v1.IntegrationKitPhaseBuildSubmitted,
+		},
+	}
+
+	err := CreateProfileConfigmap(ctx, c, kit)
+	assert.NoError(t, err)
+
+	key := ctrl.ObjectKey{
+		Namespace: "ns",
+		Name:      "test-publish-jib-profile",
+	}
+	cm := &corev1.ConfigMap{}
+	err = c.Get(ctx, key, cm)
+	assert.NoError(t, err)
+	assert.Equal(t, cm.OwnerReferences[0].Name, "test")
+	assert.Equal(t, cm.OwnerReferences[0].UID, types.UID("8dc44a2b-063c-490e-ae02-1fab285ac70a"))
+	assert.NotNil(t, cm.Data["profile.xml"])
+
+}
diff --git a/pkg/util/maven/maven_command.go b/pkg/util/maven/maven_command.go
index 9ba23b1b7..5c01a36fd 100644
--- a/pkg/util/maven/maven_command.go
+++ b/pkg/util/maven/maven_command.go
@@ -142,7 +142,12 @@ func (c *Command) Do(ctx context.Context) error {
 
 	Log.WithValues("MAVEN_OPTS", mavenOptions).Infof("executing: %s", strings.Join(cmd.Args, " "))
 
-	return util.RunAndLog(ctx, cmd, mavenLogHandler, mavenLogHandler)
+	// generate maven file
+	if err := generateMavenContext(c.context.Path, args); err != nil {
+		return err
+	}
+
+	return util.RunAndLog(ctx, cmd, MavenLogHandler, MavenLogHandler)
 }
 
 func NewContext(buildDir string) Context {
@@ -243,7 +248,7 @@ func generateProjectStructure(context Context, project Project) error {
 func (c *Command) prepareMavenWrapper(ctx context.Context) error {
 	cmd := exec.CommandContext(ctx, "cp", "--recursive", "/usr/share/maven/mvnw/.", ".")
 	cmd.Dir = c.context.Path
-	return util.RunAndLog(ctx, cmd, mavenLogHandler, mavenLogHandler)
+	return util.RunAndLog(ctx, cmd, MavenLogHandler, MavenLogHandler)
 }
 
 // ParseGAV decodes the provided Maven GAV into the corresponding Dependency.
@@ -279,3 +284,16 @@ func ParseGAV(gav string) (Dependency, error) {
 
 	return dep, nil
 }
+
+// Create a MAVEN_CONTEXT file containing all arguments for a maven command.
+func generateMavenContext(path string, args []string) error {
+	// TODO refactor maven code to avoid creating a file to pass command args
+	commandArgs := make([]string, 0)
+	for _, arg := range args {
+		if arg != "package" && len(strings.TrimSpace(arg)) != 0 {
+			commandArgs = append(commandArgs, strings.TrimSpace(arg))
+		}
+	}
+
+	return util.WriteToFile(filepath.Join(path, "MAVEN_CONTEXT"), strings.Join(commandArgs, " "))
+}
diff --git a/pkg/util/maven/maven_log.go b/pkg/util/maven/maven_log.go
index 277c267d9..e47b15cd8 100644
--- a/pkg/util/maven/maven_log.go
+++ b/pkg/util/maven/maven_log.go
@@ -48,7 +48,7 @@ const (
 
 var mavenLogger = log.WithName("maven.build")
 
-func mavenLogHandler(s string) string {
+func MavenLogHandler(s string) string {
 	mavenLog, parseError := parseLog(s)
 	if parseError == nil {
 		normalizeLog(mavenLog)
diff --git a/pkg/util/maven/maven_log_test.go b/pkg/util/maven/maven_log_test.go
index 0cce7c61c..d31ba257a 100644
--- a/pkg/util/maven/maven_log_test.go
+++ b/pkg/util/maven/maven_log_test.go
@@ -34,7 +34,7 @@ func TestRunAndLogErrorMvn(t *testing.T) {
 	}
 
 	cmd := exec.CommandContext(context.Background(), mavenCmd, "package", "-B")
-	err := util.RunAndLog(context.Background(), cmd, mavenLogHandler, mavenLogHandler)
+	err := util.RunAndLog(context.Background(), cmd, MavenLogHandler, MavenLogHandler)
 
 	assert.NotNil(t, err)
 	assert.ErrorContains(t, err, "[ERROR] The goal you specified requires a project to execute but there is no POM in this directory")
diff --git a/pkg/util/maven/maven_types.go b/pkg/util/maven/maven_types.go
index 4a655a3ec..039dab1b2 100644
--- a/pkg/util/maven/maven_types.go
+++ b/pkg/util/maven/maven_types.go
@@ -37,11 +37,12 @@ type Build struct {
 }
 
 type Plugin struct {
-	GroupID      string       `xml:"groupId"`
-	ArtifactID   string       `xml:"artifactId"`
-	Version      string       `xml:"version,omitempty"`
-	Executions   []Execution  `xml:"executions>execution,omitempty"`
-	Dependencies []Dependency `xml:"dependencies>dependency,omitempty"`
+	GroupID       string                 `xml:"groupId"`
+	ArtifactID    string                 `xml:"artifactId"`
+	Version       string                 `xml:"version,omitempty"`
+	Executions    []Execution            `xml:"executions>execution,omitempty"`
+	Dependencies  []Dependency           `xml:"dependencies>dependency,omitempty"`
+	Configuration v1.PluginConfiguration `xml:"configuration,omitempty"`
 }
 
 type Execution struct {
diff --git a/pkg/util/util.go b/pkg/util/util.go
index 5d122dee1..c70c71e70 100644
--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@ -236,9 +236,18 @@ func RandomInt63() int64 {
 	return randomSourceUTC.Int63()
 }
 
+func EncodeXMLWithoutHeader(content interface{}) ([]byte, error) {
+	return encodeXML(content, "")
+}
+
 func EncodeXML(content interface{}) ([]byte, error) {
+
+	return encodeXML(content, xml.Header)
+}
+
+func encodeXML(content interface{}, xmlHeader string) ([]byte, error) {
 	w := &bytes.Buffer{}
-	w.WriteString(xml.Header)
+	w.WriteString(xmlHeader)
 
 	e := xml.NewEncoder(w)
 	e.Indent("", "  ")