Repository: apache/camel-k
Pull request #2143 (2021-03-17 10:00:52)

doc: added documentation about deploying Camel K on k3s
<!-- Description -->
Added documentation about installing Camel K on K3s


<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
NONE
```


Patch:
diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml
index 4a2267db8..8b7823003 100644
--- a/.github/workflows/builder.yml
+++ b/.github/workflows/builder.yml
@@ -82,7 +82,7 @@ jobs:
     - name: Build Operator
       run: |
         echo "Build project"
-        make build-kamel
+        make build-kamel bundle-kamelets
         echo "Adding maven artifacts to the image context"
         make PACKAGE_ARTIFACTS_STRATEGY=download package-artifacts
         echo "Copying binary file to docker dir"
diff --git a/.github/workflows/knative.yml b/.github/workflows/knative.yml
index c4d377ef1..008c0dbe8 100644
--- a/.github/workflows/knative.yml
+++ b/.github/workflows/knative.yml
@@ -123,7 +123,7 @@ jobs:
     - name: Build Operator
       run: |
         echo "Build project"
-        make build-kamel
+        make build-kamel bundle-kamelets
         echo "Adding maven artifacts to the image context"
         make PACKAGE_ARTIFACTS_STRATEGY=download package-artifacts
         echo "Copying binary file to docker dir"
@@ -248,7 +248,7 @@ jobs:
       - name: Build Operator
         run: |
           echo "Build project"
-          make build-kamel
+          make build-kamel bundle-kamelets
           echo "Adding maven artifacts to the image context"
           make PACKAGE_ARTIFACTS_STRATEGY=download package-artifacts
           echo "Copying binary file to docker dir"
diff --git a/.github/workflows/kubernetes.yml b/.github/workflows/kubernetes.yml
index 62873a70d..fdbe210b8 100644
--- a/.github/workflows/kubernetes.yml
+++ b/.github/workflows/kubernetes.yml
@@ -78,7 +78,7 @@ jobs:
     - name: Build Operator
       run: |
         echo "Build project"
-        make build-kamel
+        make build-kamel bundle-kamelets
         echo "Adding maven artifacts to the image context"
         make PACKAGE_ARTIFACTS_STRATEGY=download package-artifacts
         echo "Copying binary file to docker dir"
diff --git a/.github/workflows/openshift.yml b/.github/workflows/openshift.yml
index 5f254e9e6..c56a73e3c 100644
--- a/.github/workflows/openshift.yml
+++ b/.github/workflows/openshift.yml
@@ -140,7 +140,7 @@ jobs:
       run: |
         # Compute registry parameters
         echo "Build project"
-        make build-kamel
+        make build-kamel bundle-kamelets
 
         echo "Adding maven artifacts to the image context"
         make PACKAGE_ARTIFACTS_STRATEGY=download package-artifacts
diff --git a/.gitignore b/.gitignore
index 4a6a8c12c..46982078f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,9 +9,6 @@
 /kamel-config.yaml
 /.kamel/kamel-config.yaml
 
-# Kamelet catalog
-/deploy/kamelets
-
 # Released Packages
 *.tar.gz
 
@@ -35,6 +32,7 @@
 build/_output
 build/_test
 build/_maven_output
+build/_kamelets
 /api_*
 
 # envrc
diff --git a/build/Dockerfile b/build/Dockerfile
index 76e022db7..dcb408337 100644
--- a/build/Dockerfile
+++ b/build/Dockerfile
@@ -27,11 +27,14 @@ RUN mkdir -p /usr/share/maven \
     && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
 
 ADD build/_maven_output /tmp/artifacts/m2
+ADD build/_kamelets /kamelets
 
 USER 0
 
 RUN chgrp -R 0 /tmp/artifacts/m2 \
-    && chmod -R g=u /tmp/artifacts/m2
+    && chmod -R g=u /tmp/artifacts/m2 \
+    && chgrp -R 0 /kamelets \
+    && chmod -R g=u /kamelets
 
 USER 1000
 
diff --git a/cmd/util/vfs-gen/main.go b/cmd/util/vfs-gen/main.go
index 0e653d35f..6ad706045 100644
--- a/cmd/util/vfs-gen/main.go
+++ b/cmd/util/vfs-gen/main.go
@@ -93,6 +93,7 @@ func main() {
 	//
 	fs = filter.Skip(fs, filter.FilesWithExtensions(".go"))
 	fs = filter.Skip(fs, NamedFilesFilter("kustomization.yaml"))
+	fs = filter.Skip(fs, NamedFilesFilter("auto-generated.txt"))
 	fs = filter.Skip(fs, func(path string, fi os.FileInfo) bool {
 		for _, ex := range exclusions {
 			if strings.HasPrefix(path, ex) {
diff --git a/deploy/templates/kamelet.tmpl b/deploy/templates/kamelet.tmpl
index e1740e068..fa98b05ec 100644
--- a/deploy/templates/kamelet.tmpl
+++ b/deploy/templates/kamelet.tmpl
@@ -1,5 +1,3 @@
-# camel-k: language=kamelet
-
 apiVersion: camel.apache.org/v1alpha1
 kind: Kamelet
 metadata:
@@ -8,7 +6,7 @@ metadata:
     camel.apache.org/kamelet.type: "source"
 spec:
   definition:
-    title: "Timer"
+    title: "Timer Example"
     description: "Produces periodic events with a custom payload"
     required:
       - message
@@ -24,10 +22,7 @@ spec:
         type: string
   types:
     out:
-      mediaType: application/json
-      schema:
-        id: text.camel.apache.org
-        type: string
+      mediaType: text/plain
   flow:
     from:
       uri: timer:tick
@@ -36,4 +31,7 @@ spec:
       steps:
         - set-body:
             constant: {{`"{{message}}"`}}
+        - set-header:
+            name: "Content-Type"
+            constant: "text/plain"
         - to: "kamelet:sink"
diff --git a/docs/modules/ROOT/pages/installation/installation.adoc b/docs/modules/ROOT/pages/installation/installation.adoc
index 4b22499b6..a2b578134 100644
--- a/docs/modules/ROOT/pages/installation/installation.adoc
+++ b/docs/modules/ROOT/pages/installation/installation.adoc
@@ -16,6 +16,7 @@ before installing it. Customized instructions are needed for the following clust
 - xref:installation/gke.adoc[Google Kubernetes Engine (GKE)]
 - xref:installation/openshift.adoc[OpenShift]
 - xref:installation/iks.adoc[IBM Kubernetes Services (IKS)]
+- xref:installation/k3s.adoc[K3s]
 
 Other cluster types (such as OpenShift clusters) should *not need* prior configuration.
 
diff --git a/docs/modules/ROOT/pages/installation/k3s.adoc b/docs/modules/ROOT/pages/installation/k3s.adoc
new file mode 100644
index 000000000..8d45d1a3b
--- /dev/null
+++ b/docs/modules/ROOT/pages/installation/k3s.adoc
@@ -0,0 +1,4 @@
+[[installation-on-k3s]]
+= Installing Camel K on K3s
+
+Because K3s does not come with a builtin registry, you should follow the steps described on xref:installation/registry/k3s.adoc[Installing Camel K on K3s] to deploy it configure it to use a public or a private registry.
\ No newline at end of file
diff --git a/docs/modules/ROOT/pages/installation/registry/k3s.adoc b/docs/modules/ROOT/pages/installation/registry/k3s.adoc
new file mode 100644
index 000000000..8b38aeb51
--- /dev/null
+++ b/docs/modules/ROOT/pages/installation/registry/k3s.adoc
@@ -0,0 +1,52 @@
+[[installation-on-k3s]]
+= Installing Camel K on K3s
+
+This guide assumes you've already deployed a https://k3s.io[K3s] cluster and have installed and configured the kubectl command to manage the cluster.
+
+You can create a namespace to install Camel K on:
+
+```
+kubectl create namespace camel-k-test || true
+```
+
+Camel K needs a xref:installation/registry/registry.adoc[registry] to push the integrations it builds. For K3s you have to possibilities:
+
+* You can configure Camel K installation to use the Docker registry, Quay.io or a similar publicly available registry, or;
+* You can deploy your own private repository in the cluster or on your network.
+
+[[public-registry]]
+== Using a Public Registry
+
+Most of the those registries require authentication to push images. Therefore, we have to create a secret the namespace that will contain the credentials to access it. To do so, you can execute:
+
+*Note*: before running the command below, please make sure that you are logged in to the registry you are planning to use.
+
+```
+kubectl -n camel-k-test create secret generic my-registry-secret --from-file=$HOME/.docker/config.json
+```
+
+You can follow the steps described in the xref:installation/registry/registry.adoc[registry] documentation if you are deploying using a public registry, such as the https://hub.docker.com[DockerHub] or https://quay.io[Quay].
+
+
+[[private-registry]]
+== Using a Private Registry
+
+Although K3s does not come with a private registry, one can be installed by following the steps described in the https://rancher.com/docs/k3s/latest/en/installation/private-registry/[K3s' private registry] documentation.
+
+*Note*: installing your own registry gives you more flexibility to define how the registry should run, including the level of security required for it to run. More specifically, you can configure your registry to require or not credentials, to use HTTP instead of HTTPS, and so on. For the purpose of this guide and to present how Camel K can be installed on a seamless way, this guide demonstrates the installation using an insecure registry (unencrypted and without authentication).
+
+[[installation]]
+=== Installing Camel K on K3s with Private Registry
+
+With the secret created on the cluster, we can install Camel K and tell it to use those credentials when pushing the integrations.
+
+You can now download *kamel* CLI tool from https://github.com/apache/camel-k/releases[release page]
+and put it on your system path.
+
+After configure *kamel* CLI, you can execute the following command to install it on the namespace and configured to use your private registry:
+
+```
+kamel install -n camel-k-test --force --olm=false --registry address-of-the-registry --organization your-user-id-or-org --registry-insecure true
+```
+
+After doing that, you'll be ready to play with Camel K. Enjoy!
\ No newline at end of file
diff --git a/pkg/apis/camel/v1/knative/types.go b/pkg/apis/camel/v1/knative/types.go
index c4147d6a8..d9808b0d6 100644
--- a/pkg/apis/camel/v1/knative/types.go
+++ b/pkg/apis/camel/v1/knative/types.go
@@ -40,6 +40,7 @@ type CamelServiceDefinition struct {
 	// Deprecated: use URL instead
 	Port     *int              `json:"port,omitempty"`
 	URL      string            `json:"url,omitempty"`
+	Path     string            `json:"path,omitempty"`
 	Metadata map[string]string `json:"metadata,omitempty"`
 }
 
@@ -75,8 +76,6 @@ func (s CamelServiceType) ResourceDescription(subject string) string {
 
 // Meta Options
 const (
-	CamelMetaServicePath = "service.path"
-
 	CamelMetaKnativeKind       = "knative.kind"
 	CamelMetaKnativeAPIVersion = "knative.apiVersion"
 	CamelMetaKnativeReply      = "knative.reply"
diff --git a/pkg/install/kamelets.go b/pkg/install/kamelets.go
index 982583668..6d92b9db6 100644
--- a/pkg/install/kamelets.go
+++ b/pkg/install/kamelets.go
@@ -19,39 +19,57 @@ package install
 
 import (
 	"context"
+	"fmt"
+	"io/ioutil"
+	"os"
 	"path"
 	"strings"
 
 	"github.com/pkg/errors"
-
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/types"
 
-	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
-
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/client"
-	"github.com/apache/camel-k/pkg/resources"
 	"github.com/apache/camel-k/pkg/util/defaults"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 )
 
-const kameletDir = "/kamelets/"
+const kameletDirEnv = "KAMELET_CATALOG_DIR"
+const defaultKameletDir = "/kamelets/"
 const kameletBundledLabel = "camel.apache.org/kamelet.bundled"
 const kameletReadOnlyLabel = "camel.apache.org/kamelet.readonly"
 
 // KameletCatalog installs the bundled KameletCatalog into one namespace
 func KameletCatalog(ctx context.Context, c client.Client, namespace string) error {
-	if !resources.DirExists(kameletDir) {
+	kameletDir := os.Getenv(kameletDirEnv)
+	if kameletDir == "" {
+		kameletDir = defaultKameletDir
+	}
+	if d, err := os.Stat(kameletDir); err != nil && os.IsNotExist(err) {
 		return nil
+	} else if err != nil {
+		return err
+	} else if !d.IsDir() {
+		return fmt.Errorf("Kamelet directory %q is a file", kameletDir)
 	}
 
-	for _, res := range resources.Resources(kameletDir) {
-		if !strings.HasSuffix(res, ".yaml") && !strings.HasSuffix(res, ".yml") {
+	files, err := ioutil.ReadDir(kameletDir)
+	if err != nil {
+		return err
+	}
+
+	for _, file := range files {
+		if file.IsDir() || !(strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml")) {
 			continue
 		}
 
-		obj, err := kubernetes.LoadResourceFromYaml(c.GetScheme(), resources.ResourceAsString(path.Join(kameletDir, res)))
+		content, err := ioutil.ReadFile(path.Join(kameletDir, file.Name()))
+		if err != nil {
+			return err
+		}
+
+		obj, err := kubernetes.LoadResourceFromYaml(c.GetScheme(), string(content))
 		if err != nil {
 			return err
 		}
@@ -67,24 +85,24 @@ func KameletCatalog(ctx context.Context, c client.Client, namespace string) erro
 			}
 
 			if existing == nil || existing.Annotations[kamelVersionAnnotation] != defaults.Version {
-				err := Resource(ctx, c, namespace, true, func(o ctrl.Object) ctrl.Object {
-					if o.GetAnnotations() == nil {
-						o.SetAnnotations(make(map[string]string))
-					}
-					o.GetAnnotations()[kamelVersionAnnotation] = defaults.Version
-
-					if o.GetLabels() == nil {
-						o.SetLabels(make(map[string]string))
-					}
-					o.GetLabels()[kameletBundledLabel] = "true"
-					o.GetLabels()[kameletReadOnlyLabel] = "true"
-					return o
-				}, path.Join(kameletDir, res))
+				if k.GetAnnotations() == nil {
+					k.SetAnnotations(make(map[string]string))
+				}
+				k.GetAnnotations()[kamelVersionAnnotation] = defaults.Version
+
+				if k.GetLabels() == nil {
+					k.SetLabels(make(map[string]string))
+				}
+				k.GetLabels()[kameletBundledLabel] = "true"
+				k.GetLabels()[kameletReadOnlyLabel] = "true"
+
+				err := ObjectOrCollect(ctx, c, namespace, nil, true, k)
 
 				if err != nil {
-					return errors.Wrapf(err, "could not create resource %q", res)
+					return errors.Wrapf(err, "could not create resource from file %q", path.Join(kameletDir, file.Name()))
 				}
 			}
+
 		}
 	}
 
diff --git a/pkg/kamelet/repository/repository.go b/pkg/kamelet/repository/repository.go
index 721b887e8..6497acbc4 100644
--- a/pkg/kamelet/repository/repository.go
+++ b/pkg/kamelet/repository/repository.go
@@ -33,7 +33,7 @@ const (
 	NoneRepository = "none"
 )
 
-var DefaultRemoteRepository = "github:apache/camel-kamelets"
+var DefaultRemoteRepository = NoneRepository
 
 // KameletRepository can be used to obtain a Kamelet definition, looking it up in one or more physical locations
 type KameletRepository interface {
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index f27256211..f0946f1a5 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -432,9 +432,9 @@ var assets = func() http.FileSystem {
 		"/templates/kamelet.tmpl": &vfsgen۰CompressedFileInfo{
 			name:             "kamelet.tmpl",
 			modTime:          time.Time{},
-			uncompressedSize: 876,
+			uncompressedSize: 870,
 
-			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x52\x4b\x8e\xdb\x30\x0c\xdd\xfb\x14\x84\xbb\x4e\x26\xd9\x0a\xe8\x09\x8a\x16\xb3\x08\xba\x1e\x46\x62\x6c\xd6\xfa\x55\xa2\x93\x06\x46\xee\x5e\x58\x96\x93\xcc\x4c\xbb\xe4\xf3\xfb\x99\xe2\x17\xd0\xe8\xc8\x6e\x06\x05\x16\x7d\x37\x62\x47\x5f\x87\x19\x21\x69\x1a\x8c\xfc\x93\x52\xe6\xe0\xd5\x42\xdb\x62\x44\xdd\xd3\x36\xa4\xee\xe5\xbc\x47\x1b\x7b\xdc\x37\x03\x7b\xa3\xe0\x5b\x15\x39\x12\x34\x28\xa8\x1a\x00\x8f\x8e\x14\x4c\x13\x6c\x7f\xa0\x23\xb8\xdd\x1a\x00\x8b\x47\xb2\x79\xfe\x0a\x9f\x3d\x6b\xf2\x56\xae\x91\x14\xb4\x39\x8c\x49\x53\xdb\xe4\x48\x7a\x56\x18\x3a\xb1\x67\x99\xfb\x14\xbd\xb0\xd8\x99\x77\x60\x47\xa9\x2d\x90\xa1\xac\x13\xc7\xc2\x81\xf6\x35\x05\x33\x6a\xca\x10\x29\x71\x30\xac\x81\xce\xe4\x25\xc3\x85\xa5\x07\x04\x3d\x66\x09\x0e\x22\x5e\x6d\x40\xb3\x38\x24\xfa\x3d\x72\x22\xb3\x44\x00\x6c\xc0\x51\xce\xd8\x51\x99\x63\x0a\x91\x92\x30\xe5\xf5\xfb\x62\xbd\x4e\xf7\x52\xaf\x05\xbe\xa3\xef\x7a\x1d\x7a\x02\x61\x47\xc0\x5e\x28\x9d\xd1\xc2\x91\xe4\x42\xe4\x41\x2e\xa1\x56\x7c\xf8\x95\x5d\xcc\xcc\x8e\xd2\x93\xdf\x09\x47\x2b\x0a\xf6\xbb\xdd\xae\xa2\xb5\xe7\xa7\x2a\xdf\x9f\xfa\xff\xb3\x4b\x15\x82\x04\xe8\xc8\x53\x42\xa1\x0f\xf1\x59\x12\xfb\xae\x59\xc6\xfa\xeb\x61\x14\x75\x4f\x36\x8c\x87\xc2\xc4\x18\x2d\x6b\x9c\xcd\x5f\x7e\xe5\xe0\x2b\x23\xeb\x9e\x1c\x3e\xaa\xb1\x51\x20\xf4\x47\xb6\x1f\x6f\xe0\x7f\xc1\x27\x1b\x2e\x8b\xfc\x94\x82\x5b\x8d\xc6\xc4\xaa\xac\x32\x29\x61\x3d\xac\x4f\x82\x09\x1d\x09\xa5\xfc\x08\xac\xcf\x04\xd3\xf4\xd6\x4e\xd3\x32\xdd\x6e\xed\x5b\x39\xca\xd2\x50\x28\x3e\xf1\x37\x90\x49\x36\xc7\x60\xae\x0f\xac\xdc\x6c\xf0\x59\xd0\xcb\xea\x54\x77\xf7\xce\x6a\x56\x4b\x50\xd0\xd6\x7b\x56\x99\xfd\xd0\x36\x7f\x03\x00\x00\xff\xff\x59\xa0\x34\xe2\x6c\x03\x00\x00"),
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x52\x3b\x8f\x1b\x3d\x0c\xec\xf7\x57\x10\xea\xed\xbb\x6b\xd5\x7e\xf8\xaa\x20\xc1\x15\x46\xea\xa3\x57\x63\x5b\xb0\x5e\xa1\xb8\xf6\x19\x0b\xff\xf7\x60\x5f\x7e\xe4\x12\x75\x22\x67\x86\x33\x04\xb9\xf8\x9f\x90\xea\x73\xb2\xd4\x72\x44\x58\x73\xe1\xf6\x80\x75\x96\xfd\xcb\xe9\x8d\x43\x39\xf0\x5b\x73\xf4\xc9\x59\xfa\x36\xf4\xa1\x4d\x84\xb2\x63\x65\xdb\x10\x25\x8e\xb0\xd4\xf7\xb4\xfe\xc1\x11\x74\xbd\x36\x44\x81\xb7\x08\x75\xe8\xd2\x57\xcd\xe3\x24\xb2\xd6\x4b\x81\x25\x53\x73\x27\x2d\x4c\x53\x0b\xda\x81\xe1\xb0\xf3\xc9\xeb\xe0\x67\xe4\xab\xd7\x30\xe0\x36\x3e\x42\xe8\xff\x4f\x8e\x25\xc0\x8c\x2d\x87\xda\x8a\x2f\x23\x96\xcc\xbb\x64\xd7\xb5\xa8\x54\x20\x3e\x3b\xdf\x12\x4e\x48\x5a\xe9\xec\xf5\x40\x4c\x6d\x57\x35\x47\x2a\x7c\x09\x99\xdd\xa4\x20\xf8\xd5\x79\x81\x9b\x46\x11\xad\x28\xa2\x56\xde\x63\xfc\x17\xc9\x05\xa2\x1e\x75\xe9\x4f\xd2\xcb\xef\x66\xee\x7d\x2c\xdf\xaa\x4f\xbe\x36\x07\x90\xfa\x08\xf2\x49\x21\x27\x0e\xb4\x85\x9e\x81\x44\x7a\xce\xb3\xc5\xbb\xde\xb8\x93\x01\xb9\x87\x3c\xe8\xed\xb8\x0b\x6a\xe9\xed\xf5\xf5\x75\xae\xce\x3e\xbf\x58\xf9\xfe\xe0\xff\xaf\x5e\x66\x22\x69\xa6\x3d\x12\x84\x15\x7f\x8c\xaf\x2a\x3e\xed\x9b\xe9\x3b\x47\xcf\x9d\xda\xdb\x64\xe7\x79\x33\x22\x15\x9f\xfa\x52\x02\xfb\xd4\x10\xed\x42\x3e\x4f\x98\x9d\xe4\xb8\xa0\x3b\xf1\x76\xcc\x2f\x56\x7d\x7b\x5c\xf6\xc8\xc2\x11\x0a\xa9\xf7\x00\xf3\x6e\xa9\xef\x3f\x4c\xdf\x4f\xbf\xeb\xd5\x7c\x8c\x17\x35\xbc\xaa\x28\x0f\xf8\x15\x55\xe8\x6a\x9b\xdd\xe5\x5e\x1b\x0f\x2e\xa7\xaa\x9c\x74\x51\x9a\x03\x3f\x49\x2d\xec\x03\xd8\x41\x9e\xf9\xd3\x41\x9b\xff\x72\x52\x24\x5d\x0d\x49\xcd\x3f\x06\x98\xfb\x02\xcc\x83\xb2\x66\x4b\x66\x3e\x73\x5b\x7d\x3a\x9a\xe6\x77\x00\x00\x00\xff\xff\x6a\xca\xd0\xd3\x66\x03\x00\x00"),
 		},
 		"/templates/kts.tmpl": &vfsgen۰CompressedFileInfo{
 			name:             "kts.tmpl",
diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go
index f085f4722..56f673585 100644
--- a/pkg/trait/knative.go
+++ b/pkg/trait/knative.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"net/url"
 	"reflect"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -72,9 +73,8 @@ type knativeTrait struct {
 	// List of event types that the integration will produce.
 	// Can contain simple event types or full Camel URIs (to use a specific broker).
 	EventSinks []string `property:"event-sinks" json:"eventSinks,omitempty"`
-	// Enables filtering on events based on the header "ce-knativehistory". Since this is an experimental header
-	// that can be removed in a future version of Knative, filtering is enabled only when the integration is
-	// listening from more than 1 channel.
+	// Enables filtering on events based on the header "ce-knativehistory". Since this header has been removed in newer versions of
+	// Knative, filtering is disabled by default.
 	FilterSourceChannels *bool `property:"filter-source-channels" json:"filterSourceChannels,omitempty"`
 	// Enables Knative CamelSource pre 0.15 compatibility fixes (will be removed in future versions).
 	CamelSourceCompat *bool `property:"camel-source-compat" json:"camelSourceCompat,omitempty"`
@@ -192,11 +192,9 @@ func (t *knativeTrait) Configure(e *Environment) (bool, error) {
 
 			t.EventSinks = items
 		}
-		if len(t.ChannelSources) > 1 {
-			// Always filter channels when the integration subscribes to more than one
-			// Using Knative experimental header: https://github.com/knative/eventing/blob/7df0cc56c28d58223ff25d5ddfb487fa8c29a004/pkg/provisioners/message.go#L28
-			// TODO: filter automatically all source channels when the feature becomes stable
-			filter := true
+		if t.FilterSourceChannels == nil {
+			// Filtering is no longer used by default
+			filter := false
 			t.FilterSourceChannels = &filter
 		}
 		if t.SinkBinding == nil {
@@ -298,8 +296,8 @@ func (t *knativeTrait) configureChannels(e *Environment, env *knativeapi.CamelEn
 			if err != nil {
 				return err
 			}
+			path := fmt.Sprintf("/channels/%s", ref.Name)
 			meta := map[string]string{
-				knativeapi.CamelMetaServicePath:       "/",
 				knativeapi.CamelMetaEndpointKind:      string(knativeapi.CamelEndpointKindSource),
 				knativeapi.CamelMetaKnativeAPIVersion: ref.APIVersion,
 				knativeapi.CamelMetaKnativeKind:       ref.Kind,
@@ -311,11 +309,12 @@ func (t *knativeTrait) configureChannels(e *Environment, env *knativeapi.CamelEn
 			svc := knativeapi.CamelServiceDefinition{
 				Name:        ref.Name,
 				ServiceType: knativeapi.CamelServiceTypeChannel,
+				Path:        path,
 				Metadata:    meta,
 			}
 			env.Services = append(env.Services, svc)
 
-			if err := t.createSubscription(e, ref); err != nil {
+			if err := t.createSubscription(e, ref, path); err != nil {
 				return err
 			}
 
@@ -349,11 +348,11 @@ func (t *knativeTrait) configureChannels(e *Environment, env *knativeapi.CamelEn
 	return nil
 }
 
-func (t *knativeTrait) createSubscription(e *Environment, ref *corev1.ObjectReference) error {
+func (t *knativeTrait) createSubscription(e *Environment, ref *corev1.ObjectReference, path string) error {
 	if ref.Namespace == "" {
 		ref.Namespace = e.Integration.Namespace
 	}
-	sub := knativeutil.CreateSubscription(*ref, e.Integration.Name)
+	sub := knativeutil.CreateSubscription(*ref, e.Integration.Name, path)
 	e.Resources.Add(sub)
 	return nil
 }
@@ -373,8 +372,8 @@ func (t *knativeTrait) configureEndpoints(e *Environment, env *knativeapi.CamelE
 		svc := knativeapi.CamelServiceDefinition{
 			Name:        ref.Name,
 			ServiceType: knativeapi.CamelServiceTypeEndpoint,
+			Path:        "/",
 			Metadata: map[string]string{
-				knativeapi.CamelMetaServicePath:       "/",
 				knativeapi.CamelMetaEndpointKind:      string(knativeapi.CamelEndpointKindSource),
 				knativeapi.CamelMetaKnativeAPIVersion: serving.SchemeGroupVersion.String(),
 				knativeapi.CamelMetaKnativeKind:       "Service",
@@ -414,14 +413,19 @@ func (t *knativeTrait) configureEvents(e *Environment, env *knativeapi.CamelEnvi
 		func(ref *corev1.ObjectReference, serviceURI string, _ func() (*url.URL, error)) error {
 			// Iterate over all, without skipping duplicates
 			eventType := knativeutil.ExtractEventType(serviceURI)
-			t.createTrigger(e, ref, eventType)
+			serviceName := eventType
+			if serviceName == "" {
+				serviceName = "default"
+			}
+			servicePath := fmt.Sprintf("/events/%s", eventType)
+			t.createTrigger(e, ref, eventType, servicePath)
 
-			if !env.ContainsService(ref.Name, knativeapi.CamelEndpointKindSource, knativeapi.CamelServiceTypeEvent, ref.APIVersion, ref.Kind) {
+			if !env.ContainsService(serviceName, knativeapi.CamelEndpointKindSource, knativeapi.CamelServiceTypeEvent, ref.APIVersion, ref.Kind) {
 				svc := knativeapi.CamelServiceDefinition{
-					Name:        ref.Name,
+					Name:        serviceName,
 					ServiceType: knativeapi.CamelServiceTypeEvent,
+					Path:        servicePath,
 					Metadata: map[string]string{
-						knativeapi.CamelMetaServicePath:       "/",
 						knativeapi.CamelMetaEndpointKind:      string(knativeapi.CamelEndpointKindSource),
 						knativeapi.CamelMetaKnativeAPIVersion: ref.APIVersion,
 						knativeapi.CamelMetaKnativeKind:       ref.Kind,
@@ -549,18 +553,18 @@ func (t *knativeTrait) configureSinkBinding(e *Environment, env *knativeapi.Came
 	return err
 }
 
-func (t *knativeTrait) createTrigger(e *Environment, ref *corev1.ObjectReference, eventType string) {
+func (t *knativeTrait) createTrigger(e *Environment, ref *corev1.ObjectReference, eventType string, path string) {
 	// TODO extend to additional filters too, to filter them at source and not at destination
 	found := e.Resources.HasKnativeTrigger(func(trigger *eventing.Trigger) bool {
 		return trigger.Spec.Broker == ref.Name &&
 			trigger.Spec.Filter != nil &&
-			trigger.Spec.Filter.Attributes["type"] == eventType
+			trigger.Spec.Filter.Attributes["type"] == eventType // can be also missing
 	})
 	if !found {
 		if ref.Namespace == "" {
 			ref.Namespace = e.Integration.Namespace
 		}
-		trigger := knativeutil.CreateTrigger(*ref, e.Integration.Name, eventType)
+		trigger := knativeutil.CreateTrigger(*ref, e.Integration.Name, eventType, path)
 		e.Resources.Add(trigger)
 	}
 }
@@ -631,5 +635,6 @@ func (t *knativeTrait) extractServices(names []string, serviceType knativeapi.Ca
 			answer = append(answer, i)
 		}
 	}
+	sort.Strings(answer)
 	return answer
 }
diff --git a/pkg/util/knative/knative.go b/pkg/util/knative/knative.go
index 182f56640..7d90dafab 100644
--- a/pkg/util/knative/knative.go
+++ b/pkg/util/knative/knative.go
@@ -27,6 +27,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"knative.dev/pkg/apis"
 
 	ctrl "sigs.k8s.io/controller-runtime/pkg/client"
 
@@ -44,7 +45,7 @@ import (
 )
 
 // CreateSubscription ---
-func CreateSubscription(channelReference corev1.ObjectReference, serviceName string) *messaging.Subscription {
+func CreateSubscription(channelReference corev1.ObjectReference, serviceName string, path string) *messaging.Subscription {
 	return &messaging.Subscription{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: messaging.SchemeGroupVersion.String(),
@@ -66,13 +67,24 @@ func CreateSubscription(channelReference corev1.ObjectReference, serviceName str
 					Kind:       "Service",
 					Name:       serviceName,
 				},
+				URI: &apis.URL{
+					Path: path,
+				},
 			},
 		},
 	}
 }
 
 // CreateTrigger ---
-func CreateTrigger(brokerReference corev1.ObjectReference, serviceName string, eventType string) *eventing.Trigger {
+func CreateTrigger(brokerReference corev1.ObjectReference, serviceName string, eventType string, path string) *eventing.Trigger {
+	nameSuffix := ""
+	var attributes map[string]string
+	if eventType != "" {
+		nameSuffix = fmt.Sprintf("-%s", util.SanitizeLabel(eventType))
+		attributes = map[string]string{
+			"type": eventType,
+		}
+	}
 	return &eventing.Trigger{
 		TypeMeta: metav1.TypeMeta{
 			APIVersion: eventing.SchemeGroupVersion.String(),
@@ -80,13 +92,11 @@ func CreateTrigger(brokerReference corev1.ObjectReference, serviceName string, e
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: brokerReference.Namespace,
-			Name:      brokerReference.Name + "-" + serviceName + "-" + util.SanitizeLabel(eventType),
+			Name:      brokerReference.Name + "-" + serviceName + nameSuffix,
 		},
 		Spec: eventing.TriggerSpec{
 			Filter: &eventing.TriggerFilter{
-				Attributes: eventing.TriggerFilterAttributes{
-					"type": eventType,
-				},
+				Attributes: attributes,
 			},
 			Broker: brokerReference.Name,
 			Subscriber: duckv1.Destination{
@@ -95,6 +105,9 @@ func CreateTrigger(brokerReference corev1.ObjectReference, serviceName string, e
 					Kind:       "Service",
 					Name:       serviceName,
 				},
+				URI: &apis.URL{
+					Path: path,
+				},
 			},
 		},
 	}
diff --git a/script/Makefile b/script/Makefile
index aee8872aa..53f5ae610 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -35,9 +35,9 @@ STAGING_IMAGE_NAME := docker.io/camelk/camel-k
 STAGING_RUNTIME_REPO :=
 
 # Define here the repo containing the default Kamelet catalog (if any)
-KAMELET_CATALOG_REPO :=
-# Optional branch for the default Kamelet catalog
-KAMELET_CATALOG_REPO_BRANCH :=
+KAMELET_CATALOG_REPO := https://github.com/apache/camel-kamelets.git
+# Optional branch for the default Kamelet catalog (change this to a tag before release)
+KAMELET_CATALOG_REPO_BRANCH := master
 
 # When packaging artifacts into the docker image, you can "copy" them from local maven
 # or "download" them from Apache Snapshots and Maven Central
@@ -176,18 +176,22 @@ test-kamel-cli: build
 build-kamel:
 	go build $(GOFLAGS) -o kamel ./cmd/kamel/*.go
 
-build-resources: bundle-kamelets
+build-resources:
 	./script/build_catalog.sh $(RUNTIME_VERSION) -Dcatalog.file=camel-catalog-$(RUNTIME_VERSION).yaml -Dcatalog.runtime=quarkus -Dstaging.repo="$(STAGING_RUNTIME_REPO)"
 	go generate ./pkg/...
 
 bundle-kamelets:
+ifneq (,$(findstring release,$(MAKECMDGOALS)))
+ifneq (,$(findstring $(KAMELET_CATALOG_REPO_BRANCH), master main))
+	@echo "You cannot set KAMELET_CATALOG_REPO_BRANCH=$(KAMELET_CATALOG_REPO_BRANCH) when doing a release"
+	@exit 1
+endif
+endif
 	./script/bundle_kamelets.sh $(KAMELET_CATALOG_REPO) $(KAMELET_CATALOG_REPO_BRANCH)
 
 build-submodules:
 	./script/build_submodules.sh
 
-
-
 build-compile-integration-tests:
 	go test -c -tags="integration" ./e2e/common
 	go test -c -tags="integration" ./e2e/knative
@@ -221,7 +225,7 @@ lint-fix:
 check-licenses:
 	./script/check_licenses.sh
 
-images: test
+images: bundle-kamelets test
 	mkdir -p build/_maven_output
 	mkdir -p build/_output/bin
 ifneq ($(shell uname -s 2>/dev/null || echo Unknown),Linux)
@@ -231,7 +235,7 @@ else
 endif
 	docker build -t $(IMAGE_NAME):$(VERSION) -f build/Dockerfile .
 
-images-dev: test package-artifacts
+images-dev: bundle-kamelets test package-artifacts
 	mkdir -p build/_maven_output
 	mkdir -p build/_output/bin
 ifneq ($(shell uname -s 2>/dev/null || echo Unknown),Linux)
diff --git a/script/bundle_kamelets.sh b/script/bundle_kamelets.sh
index 36f56b8f9..b54a9d5ec 100755
--- a/script/bundle_kamelets.sh
+++ b/script/bundle_kamelets.sh
@@ -23,8 +23,11 @@ repo=$1
 branch=$2
 
 cd $location/../
-target=./deploy/kamelets
+target=./build/_kamelets
+
+# Always recreate the dir
 rm -rf $target
+mkdir $target
 
 if [ "$repo" = "" ]; then
 	echo "no kamelet catalog defined: skipping"
@@ -41,7 +44,6 @@ echo "Cloning repository $repo on branch $branch to bundle kamelets..."
 rm -rf ./tmp_kamelet_catalog
 git clone -b $branch --single-branch --depth 1 $repo ./tmp_kamelet_catalog
 
-mkdir $target
 cp ./tmp_kamelet_catalog/*.kamelet.yaml $target
 
 rm -rf ./tmp_kamelet_catalog


Test patch:
diff --git a/e2e/knative/knative_test.go b/e2e/knative/knative_test.go
index 33e11c3ca..cd655f0f8 100644
--- a/e2e/knative/knative_test.go
+++ b/e2e/knative/knative_test.go
@@ -95,29 +95,26 @@ func TestRunChannelComboGetToPost(t *testing.T) {
 	})
 }
 
-/*
-// FIXME: uncomment when https://github.com/apache/camel-k-runtime/issues/69 is resolved
 func TestRunMultiChannelChain(t *testing.T) {
-	withNewTestNamespace(t, func(ns string) {
-		Expect(createKnativeChannel(ns, "messages")()).To(Succeed())
-		Expect(createKnativeChannel(ns, "words")()).To(Succeed())
-		Expect(kamel("install", "-n", ns, "--trait-profile", "knative").Execute()).To(Succeed())
-		Expect(kamel("run", "-n", ns, "files/knativemultihop3.groovy").Execute()).To(Succeed())
-		Expect(kamel("run", "-n", ns, "files/knativemultihop2.groovy").Execute()).To(Succeed())
-		Expect(kamel("run", "-n", ns, "files/knativemultihop1.groovy").Execute()).To(Succeed())
-		Eventually(integrationPodPhase(ns, "knativemultihop3"), TestTimeoutLong).Should(Equal(v1.PodRunning))
-		Eventually(integrationPodPhase(ns, "knativemultihop2"), TestTimeoutLong).Should(Equal(v1.PodRunning))
-		Eventually(integrationPodPhase(ns, "knativemultihop1"), TestTimeoutLong).Should(Equal(v1.PodRunning))
-		Eventually(integrationLogs(ns, "knativemultihop3"), TestTimeoutMedium).Should(ContainSubstring(`From messages: message`))
-		Eventually(integrationLogs(ns, "knativemultihop3"), TestTimeoutMedium).Should(ContainSubstring(`From words: word`))
-		Eventually(integrationLogs(ns, "knativemultihop3"), TestTimeoutMedium).Should(ContainSubstring(`From words: transformed message`))
-		Eventually(integrationLogs(ns, "knativemultihop3"), 10*time.Second).ShouldNot(ContainSubstring(`From messages: word`))
-		Eventually(integrationLogs(ns, "knativemultihop3"), 10*time.Second).ShouldNot(ContainSubstring(`From words: message`))
-		Eventually(integrationLogs(ns, "knativemultihop3"), 10*time.Second).ShouldNot(ContainSubstring(`From messages: transformed message`))
-		Expect(kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+	WithNewTestNamespace(t, func(ns string) {
+		Expect(CreateKnativeChannelv1Beta1(ns, "messages")()).To(Succeed())
+		Expect(CreateKnativeChannelv1Beta1(ns, "words")()).To(Succeed())
+		Expect(Kamel("install", "-n", ns, "--trait-profile", "knative").Execute()).To(Succeed())
+		Expect(Kamel("run", "-n", ns, "files/knativemultihop3.groovy").Execute()).To(Succeed())
+		Expect(Kamel("run", "-n", ns, "files/knativemultihop2.groovy").Execute()).To(Succeed())
+		Expect(Kamel("run", "-n", ns, "files/knativemultihop1.groovy").Execute()).To(Succeed())
+		Eventually(IntegrationPodPhase(ns, "knativemultihop3"), TestTimeoutLong).Should(Equal(v1.PodRunning))
+		Eventually(IntegrationPodPhase(ns, "knativemultihop2"), TestTimeoutLong).Should(Equal(v1.PodRunning))
+		Eventually(IntegrationPodPhase(ns, "knativemultihop1"), TestTimeoutLong).Should(Equal(v1.PodRunning))
+		Eventually(IntegrationLogs(ns, "knativemultihop3"), TestTimeoutMedium).Should(ContainSubstring(`From messages: message`))
+		Eventually(IntegrationLogs(ns, "knativemultihop3"), TestTimeoutMedium).Should(ContainSubstring(`From words: word`))
+		Eventually(IntegrationLogs(ns, "knativemultihop3"), TestTimeoutMedium).Should(ContainSubstring(`From words: transformed message`))
+		Eventually(IntegrationLogs(ns, "knativemultihop3"), 10*time.Second).ShouldNot(ContainSubstring(`From messages: word`))
+		Eventually(IntegrationLogs(ns, "knativemultihop3"), 10*time.Second).ShouldNot(ContainSubstring(`From words: message`))
+		Eventually(IntegrationLogs(ns, "knativemultihop3"), 10*time.Second).ShouldNot(ContainSubstring(`From messages: transformed message`))
+		Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
 	})
 }
-*/
 
 func TestRunBroker(t *testing.T) {
 	WithNewTestNamespaceWithKnativeBroker(t, func(ns string) {
diff --git a/pkg/trait/knative_test.go b/pkg/trait/knative_test.go
index 4b9f815bb..6cc70e4d8 100644
--- a/pkg/trait/knative_test.go
+++ b/pkg/trait/knative_test.go
@@ -250,7 +250,7 @@ func TestKnativeEnvConfigurationFromSource(t *testing.T) {
 	assert.NotNil(t, channel)
 	assert.Equal(t, "false", channel.Metadata[knativeapi.CamelMetaKnativeReply])
 
-	broker := ne.FindService("default", knativeapi.CamelEndpointKindSource, knativeapi.CamelServiceTypeEvent, "", "")
+	broker := ne.FindService("evt.type", knativeapi.CamelEndpointKindSource, knativeapi.CamelServiceTypeEvent, "", "")
 	assert.NotNil(t, broker)
 	assert.Equal(t, "false", broker.Metadata[knativeapi.CamelMetaKnativeReply])
 }