How to configure a Kamelet

Speaking technically, a Kamelet is a resource that can be installed on any Kubernetes cluster or used as a plain yaml configuration in Apache Camel runtimes. The following is an example of a Kamelet source which can be programmed to trigger events with a timer. This is coming directly from Apache Camel Kamelets catalog:

timer-source.kamelet.yaml
apiVersion: camel.apache.org/v1
kind: Kamelet
metadata:
  name: timer-source
  annotations:
    camel.apache.org/kamelet.support.level: "Stable"
    camel.apache.org/catalog.version: "4.16.0-SNAPSHOT"
    camel.apache.org/kamelet.icon: data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4w[...]
    camel.apache.org/provider: "Apache Software Foundation"
    camel.apache.org/kamelet.group: "Timer"
    camel.apache.org/kamelet.namespace: "Scheduling"
  labels:
    camel.apache.org/kamelet.type: "source"
    camel.apache.org/kamelet.verified: "true"
spec:
  definition:
    title: "Timer Source"
    description: Produces periodic messages with a custom payload.
    required:
      - message
    type: object
    properties:
      period:
        title: Period
        description: "The interval (in milliseconds) to wait between producing the next message."
        type: integer
        default: 1000
      message:
        title: Message
        description: The message to generate.
        type: string
        example: hello world
      contentType:
        title: Content Type
        description: The content type of the generated message.
        type: string
        default: text/plain
      repeatCount:
        title: Repeat Count
        description: Specifies a maximum limit of number of fires
        type: integer
  dependencies:
    - "camel:core"
    - "camel:timer"
    - "camel:kamelet"
  template:
    from:
      uri: timer:tick
      parameters:
        period: "{{period}}"
        repeatCount: "{{?repeatCount}}"
      steps:
        - setBody:
            constant: "{{message}}"
        - setHeader:
            name: "Content-Type"
            constant: "{{contentType}}"
        - to: kamelet:sink

From a user perspective it’s important to understand the parameter exposed (.spec.definition.properties) and the execution flow (.spec.template).

The flow defines the business logic and generally use the parameter that you, as a user have to provide in your integration.

The Kamelet can be installed on the cluster as a Kamelet custom resource, and the operator is already in charge to preinstall the Kamelets coming from the Apache Camel Kamelets bundled catalog. If you create your own Kamelet you can install it on the cluster in the following way:

kubectl apply -f timer-source.kamelet.yaml

Kamelets are standard YAML files, but their common extension is .kamelet.yaml to help IDEs to recognize them and possibly provide auto-completion.

Using Kamelets in Integrations

Kamelets can be used in integrations as if they were standard Camel components. For example, suppose that you’ve created the timer-source Kamelet in the default namespace on Kubernetes, then you can write the following integration to use the Kamelet:

kamlet-route.yaml
- from:
    uri: "kamelet:timer-source?message=Hello!"
    steps:
      - to: "log:info"
URI properties ("message") match the corresponding parameters in the Kamelet definition.

Kamelets can also be used multiple times in the same route definition. This happens usually with sink Kamelets. Suppose that you’ve defined a Kamelet named "my-company-log-sink" in your Kubernetes namespace, then you can write a route like this:

kamlet-multi-route.yaml
- from:
    uri: "kamelet:timer-source?message=Hello!"
    steps:
      - to: "kamelet:my-company-log-sink?bucket=general"
      - filter:
          simple: '${body} contains "Camel"'
      - to: "kamelet:my-company-log-sink?bucket=special"

The "my-company-log-sink" will obviously define what it means to write a log in the enterprise system and what is concretely a "bucket".

Binding Kamelets into a Pipe

Kamelets are the main reason why we have introduced the Pipe custom resource. They provide a very easy connector style approach as, each Kamelet, can be defined naturally as an event source or event sink. Usage of a Kamelet from a Pipe would be like:

pipe.yaml
apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
  name: timer-to-log
spec:
  source:
    ref:
      kind: Kamelet
      apiVersion: camel.apache.org/v1
      name: timer-source
    properties:
      message: Hello pipe!
  sink:
    ref:
      kind: Kamelet
      apiVersion: camel.apache.org/v1
      name: log-sink

Configuration

When using a Kamelet, the instance parameters (e.g. "message", "bucket") can be passed explicitly in the URI or you can use Camel properties. For example:

kamlet-route.yaml
- from:
    uri: "kamelet:timer-source?message={{my-message}}"
    steps:
      - to: "log:info"

The application should run with Camel properties set, such as my-message=Hello!.

Kamelet versioning

Kamelets provided in a catalog are generally meant to work with a given runtime version (the same for which they are released). However, when you create a Kamelet and publish to a cluster, you may want to store and use different versions. If the Kamelet is provided with more than the main version, then, you can specify which version to use in your Integration by adding the version parameter.

multiple version Kamelets is an exclusive feature of Camel K.

For instance, take the following multi version Kamelet:

kamlet-namedconfig-route.yaml
apiVersion: camel.apache.org/v1
kind: Kamelet
metadata:
  name: my-source
  labels:
    camel.apache.org/kamelet.type: "source"
spec:
  definition:
    title: "Timer Example"
    description: "Emit Kamelet Main body"
  types:
    out:
      mediaType: text/plain
  template:
    from:
      uri: timer:tick
      steps:
        - setBody:
            constant: "Kamelet Main"
        - to: "kamelet:sink"
  versions:
    v1:
      definition:
        title: "Timer Example 1"
        description: "Emit Kamelet V1 body"
      types:
        out:
          mediaType: text/plain
      template:
        from:
          uri: timer:tick
          steps:
            - setBody:
                constant: "Kamelet V1"
            - to: "kamelet:sink"
    v2:
      definition:
        title: "Timer Example 2"
        description: "Emit Kamelet V2 body"
      types:
        out:
          mediaType: text/plain
      template:
        from:
          uri: timer:tick
          steps:
            - setBody:
                constant: "Kamelet V2"
            - to: "kamelet:sink"

You can see it specifies the main specification, which it is the default to use. It also specifies two additional versions, v1 and v2. This is nice if you want to provide versioning changes maintaining the same resource. When you use it, you will therefore need to specify the version you want to adopt by setting the kameletVersion parameter. For example, you want to use the v2 version:

kamlet-namedconfig-route.yaml
- from:
    uri: "kamelet:my-source?kameletVersion=v2"
    steps:
      - to: "log:info"

The operator will be able to automatically pick the right version and use it at runtime. If no version is specified, then you will use the default one.

Kamelet namespace

A Kamelet can be installed in any cluster namespace. By default, the operator will expect the Kamelet to be in the same namespace of the Integration (or Pipe), the operator namespace (where the bundled kamelets are stored) or any other repository defined in the IntegrationPlatform. If you want to use a Kamelet stored in another namespace, you will need to use the kameletNamespace parameter. For example, say you have a dedicated namespace called kamelets where you’re installing your cluster Kamelets.

namespace Kamelets is an exclusive feature of Camel K.

Now, you can instruct the operator to find the Kamelet you’re using into such namespace, for example:

kamlet-namedconfig-route.yaml
- from:
    uri: "kamelet:my-source?kameletNamespace=kamelets"
    steps:
      - to: "log:info"

The operator will be therefore loading the Kamelets from that namespace, unless the same Kamelet exists in the same Integration namespace or the operator namespace.