You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2020/07/29 10:10:19 UTC

[camel-k-examples] 42/45: Add a more complex example showing how to use a custom AWS Kinesis configuration

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

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

commit 0145b51872d813f00aedd33c368fc4d08033dba1
Author: Otavio Rodolfo Piske <op...@redhat.com>
AuthorDate: Mon Jul 13 17:10:00 2020 +0200

    Add a more complex example showing how to use a custom AWS Kinesis
    configuration
---
 .../aws-kinesis-channel.yaml                       |   7 +
 .../aws-kinesis-consumer.groovy                    |  16 ++
 .../aws-kinesis-producer.groovy                    |  13 ++
 .../aws-kinesis-source.yaml                        |  52 ++++++
 .../aws-kinesis.properties                         |   2 +
 .../extra/custom-kinesis-configuration/pom.xml     |  52 ++++++
 .../k/examples/CustomKinesisConfiguration.java     | 125 +++++++++++++
 .../extra/localstack.yaml                          |  40 ++++
 .../readme.didact.md                               | 208 +++++++++++++++++++++
 90-aws-kinesis-customized-event-source/readme.md   |   1 +
 README.md                                          |   1 +
 11 files changed, 517 insertions(+)

diff --git a/90-aws-kinesis-customized-event-source/aws-kinesis-channel.yaml b/90-aws-kinesis-customized-event-source/aws-kinesis-channel.yaml
new file mode 100644
index 0000000..4381711
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/aws-kinesis-channel.yaml
@@ -0,0 +1,7 @@
+#
+# Knative Channel
+#
+apiVersion: messaging.knative.dev/v1alpha1
+kind: InMemoryChannel
+metadata:
+  name: aws-kinesis
\ No newline at end of file
diff --git a/90-aws-kinesis-customized-event-source/aws-kinesis-consumer.groovy b/90-aws-kinesis-customized-event-source/aws-kinesis-consumer.groovy
new file mode 100644
index 0000000..09dac08
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/aws-kinesis-consumer.groovy
@@ -0,0 +1,16 @@
+// camel-k: dependency=camel-aws-kinesis dependency=camel-base64
+//
+// Apache Camel Kinesis Consumer
+//
+
+// Typical data when using cbor looks like this:
+// {"sequenceNumber":"1222","approximateArrivalTimestamp":1123,"data":"SGVsbG8gQ2FtZWwgSw==","partitionKey":"p-01123"...}
+//
+// So we unmarshal it, extract the data element which is in base64 format and decode it
+from('knative:channel/aws-kinesis')
+    .unmarshal()
+        .json()
+    .setBody { it.in.body.data }
+    .unmarshal()
+        .base64()
+    .log('Received: ${body}')
diff --git a/90-aws-kinesis-customized-event-source/aws-kinesis-producer.groovy b/90-aws-kinesis-customized-event-source/aws-kinesis-producer.groovy
new file mode 100644
index 0000000..14b34d1
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/aws-kinesis-producer.groovy
@@ -0,0 +1,13 @@
+// camel-k: dependency=camel-aws-kinesis dependency=mvn:org.apache.camel.k.examples:custom-kinesis-configuration:1.0.1
+//
+// Apache Camel Kinesis Consumer
+//
+// This is just a sample producer for AWS that creates 100 messages every 3 seconds
+from('timer:java?period=3000&repeatCount=100')
+    .setHeader("CamelAwsKinesisPartitionKey")
+        .constant("p-01123")
+    .setHeader("CamelAwsKinesisSequenceNumber")
+        .constant(1)
+    .setBody()
+        .simple('Hello Camel K')
+    .to('aws-kinesis:stream?accessKey={{aws.kinesis.accessKey}}&secretKey={{aws.kinesis.accessKey}}')
diff --git a/90-aws-kinesis-customized-event-source/aws-kinesis-source.yaml b/90-aws-kinesis-customized-event-source/aws-kinesis-source.yaml
new file mode 100644
index 0000000..587cfb9
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/aws-kinesis-source.yaml
@@ -0,0 +1,52 @@
+#
+# Apache Camel AWS Kinesis Source
+#
+apiVersion: sources.knative.dev/v1alpha1
+kind: CamelSource
+metadata:
+  name: camel-aws-kinesis-source
+spec:
+  source:
+    integration:
+      configuration:
+        # What other types do we have?
+        - type: secret
+          value: aws-kinesis
+        - type: env
+          value: AWS_HOST=localstack:4568
+        - type: property
+          value: camel.component.aws-kinesis.configuration=#class:org.apache.camel.k.examples.CustomKinesisConfiguration
+      dependencies:
+        # Needed for the json part on the flow/steps below
+        - camel:jackson
+        # Needed for the component
+        #
+        # NOTE: the dependencies used by the source may change under different
+        # circumstances. In the case of this example, it is showing how to use a
+        # LocalStack instance to simulate a AWS Kinesis stream, which is useful for
+        # testing. In this case, one of the things that the custom client does is
+        # disabling cbor so that the response is parseable.
+        # However, when pointing to a real AWS Kinesis instance it may be necessary to
+        # adjust the dependencies so that jackson-dataformat-cbor is included on the
+        # dependencies. As a general recommendation, checking the example
+        # 04-aws-kinesis-source-basic which targets AWS Kinesis is also recommended to
+        # verify what dependencies, restrictions or requirements apply when using an
+        # actual AWS Kinesis instance.
+        - camel:camel-aws-kinesis
+        # Provides the custom Kinesis configuration
+        - mvn:org.apache.camel.k.examples/custom-kinesis-configuration:1.0.1
+    flow:
+      from:
+        uri: aws-kinesis:stream
+        parameters:
+          secretKey: "{{aws.kinesis.secretKey}}"
+          accessKey: "{{aws.kinesis.accessKey}}"
+        steps:
+        - to: "log:received?showAll=true&multiline=true"
+        - marshal:
+            json: {}
+  sink:
+    ref:
+      apiVersion: messaging.knative.dev/v1beta1
+      kind: InMemoryChannel
+      name: aws-kinesis
diff --git a/90-aws-kinesis-customized-event-source/aws-kinesis.properties b/90-aws-kinesis-customized-event-source/aws-kinesis.properties
new file mode 100644
index 0000000..446bf1d
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/aws-kinesis.properties
@@ -0,0 +1,2 @@
+aws.kinesis.accessKey=accesskey
+aws.kinesis.secretKey=secretkey
\ No newline at end of file
diff --git a/90-aws-kinesis-customized-event-source/extra/custom-kinesis-configuration/pom.xml b/90-aws-kinesis-customized-event-source/extra/custom-kinesis-configuration/pom.xml
new file mode 100644
index 0000000..1e158a5
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/extra/custom-kinesis-configuration/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.camel.k.examples</groupId>
+    <artifactId>custom-kinesis-configuration</artifactId>
+    <version>1.0.1</version>
+
+    <properties>
+        <version.maven.compiler>3.8.1</version.maven.compiler>
+        <version.java>1.8</version.java>
+        <version.camel>3.3.0</version.camel>
+        <version.aws-sdk>1.11.714</version.aws-sdk>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+            <version>${version.camel}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-aws-kinesis</artifactId>
+            <version>${version.camel}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-kinesis</artifactId>
+            <version>${version.aws-sdk}</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${version.maven.compiler}</version>
+                <configuration>
+                    <source>${version.java}</source>
+                    <target>${version.java}</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/90-aws-kinesis-customized-event-source/extra/custom-kinesis-configuration/src/main/java/org/apache/camel/k/examples/CustomKinesisConfiguration.java b/90-aws-kinesis-customized-event-source/extra/custom-kinesis-configuration/src/main/java/org/apache/camel/k/examples/CustomKinesisConfiguration.java
new file mode 100644
index 0000000..501e619
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/extra/custom-kinesis-configuration/src/main/java/org/apache/camel/k/examples/CustomKinesisConfiguration.java
@@ -0,0 +1,125 @@
+/*
+ * 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 org.apache.camel.k.examples;
+
+import com.amazonaws.ClientConfiguration;
+import com.amazonaws.Protocol;
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.client.builder.AwsClientBuilder;
+import com.amazonaws.regions.Regions;
+import com.amazonaws.services.kinesis.AmazonKinesis;
+import com.amazonaws.services.kinesis.AmazonKinesisClientBuilder;
+import com.amazonaws.services.kinesis.model.CreateStreamResult;
+import com.amazonaws.services.kinesis.model.DescribeStreamResult;
+import com.amazonaws.services.kinesis.model.ResourceNotFoundException;
+import org.apache.camel.component.aws.kinesis.KinesisConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CustomKinesisConfiguration extends KinesisConfiguration {
+    private static final Logger LOG = LoggerFactory.getLogger(CustomKinesisConfiguration.class);
+
+    private AmazonKinesis amazonKinesis;
+
+    static {
+        /* This makes the Localstack response parseable but is not necessary
+         * when using AWS Kinesis
+         */
+        System.setProperty("com.amazonaws.sdk.disableCbor", "true");
+    }
+
+    private void createStream() {
+        CreateStreamResult result = amazonKinesis.createStream(getStreamName(), 1);
+        if (result.getSdkHttpMetadata().getHttpStatusCode() != 200) {
+            LOG.error("Failed to create the stream");
+        } else {
+            LOG.info("Stream created successfully");
+        }
+    }
+
+    private AmazonKinesis buildClient() {
+        LOG.info("Creating a custom Kinesis client");
+
+        String amazonHost = System.getenv("AWS_HOST");
+
+        if (amazonHost == null || amazonHost.isEmpty()) {
+            LOG.info("Couldn't find an Amazon host via environment variable, trying with 'aws.host' property instead");
+
+            amazonHost = System.getProperty("aws.host");
+        }
+
+        LOG.info("Using Amazon host: {}", amazonHost);
+
+        ClientConfiguration clientConfiguration = new ClientConfiguration();
+        clientConfiguration.setProtocol(Protocol.HTTP);
+
+        String region = Regions.US_EAST_1.getName();
+
+        AmazonKinesisClientBuilder clientBuilder = AmazonKinesisClientBuilder.standard();
+        clientBuilder
+                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(amazonHost, region))
+                .withClientConfiguration(clientConfiguration)
+                .withCredentials(new AWSCredentialsProvider() {
+                    public AWSCredentials getCredentials() {
+                        return new AWSCredentials() {
+                            public String getAWSAccessKeyId() {
+                                return "accesskey";
+                            }
+
+                            public String getAWSSecretKey() {
+                                return "secretkey";
+                            }
+                        };
+                    }
+
+                    public void refresh() {
+
+                    }
+                });
+
+        LOG.info("Building the client");
+        return clientBuilder.build();
+    }
+
+    @Override
+    public AmazonKinesis getAmazonKinesisClient() {
+        if (amazonKinesis == null) {
+            amazonKinesis = buildClient();
+
+            final String streamName = getStreamName();
+            LOG.info("Checking if the stream {} exists", streamName);
+
+            try {
+                DescribeStreamResult describeStreamResult = amazonKinesis.describeStream(streamName);
+                if (describeStreamResult.getSdkHttpMetadata().getHttpStatusCode() != 200) {
+                    LOG.info("The stream does not exist, auto creating it ...");
+
+                    createStream();
+                } else {
+                    LOG.info("The stream already exists, therefore skipping auto-creation");
+                }
+            } catch (ResourceNotFoundException e) {
+                LOG.info("The stream does not exist, auto creating it ...");
+                createStream();
+            }
+        }
+
+        return amazonKinesis;
+    }
+}
diff --git a/90-aws-kinesis-customized-event-source/extra/localstack.yaml b/90-aws-kinesis-customized-event-source/extra/localstack.yaml
new file mode 100644
index 0000000..3cffce8
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/extra/localstack.yaml
@@ -0,0 +1,40 @@
+---
+# ------------------- Internal Services ------------------- #
+apiVersion: v1
+kind: Service
+metadata:
+  name: localstack
+spec:
+  type: ClusterIP
+  ports:
+    - port: 4568
+  selector:
+    app: localstack
+    component: localstack
+
+---
+# ------------------- Deployment ------------------- #
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: localstack
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      component: localstack
+      app: localstack
+  template:
+    metadata:
+      labels:
+        component: localstack
+        app: localstack
+    spec:
+      containers:
+        - name: localstack
+          image: localstack/localstack
+          ports:
+            - containerPort: 4568
+          env:
+            - name: SERVICES
+              value: kinesis
diff --git a/90-aws-kinesis-customized-event-source/readme.didact.md b/90-aws-kinesis-customized-event-source/readme.didact.md
new file mode 100644
index 0000000..4defe01
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/readme.didact.md
@@ -0,0 +1,208 @@
+# Camel Knative Source Basic Example
+
+This example demonstrates how to get started with Camel based Knative sources by showing you some of the most important
+features that you should know before trying to develop more complex examples. This extends the ideas presented on the [AWS Kinesis Source Basic](../04-aws-kinesis-source-basic) example and shows how to customize the Kinesis client. In this example we
+show how to configure a custom Kinesis client for testing using a [LocalStack](https://github.com/localstack/localstack) instance
+instead of a real AWS Kinesis instance. Although this example focuses on a general scenario aimed at testing, the overall idea and design is also applicable for scenarios when a custom client configuration is necessary.
+
+You can find more information about Apache Camel and Apache Camel K on the [official Camel website](https://camel.apache.org).
+
+## Before you begin
+
+Read the general instructions in the [root README.md file](../README.md) for setting up your environment and the Kubernetes cluster before looking at this example.
+
+Make sure you've read the [installation instructions](https://camel.apache.org/camel-k/latest/installation/installation.html) for your specific
+cluster before starting the example.
+
+You should open this file with [Didact](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-didact) if available on your IDE.
+
+You need a Maven repository where the custom client can be deployed.
+
+## Requirements
+
+<a href='didact://?commandId=vscode.didact.validateAllRequirements' title='Validate all requirements!'><button>Validate all Requirements at Once!</button></a>
+
+**Kubectl CLI**
+
+The Kubernetes `kubectl` CLI tool will be used to interact with the Kubernetes cluster.
+
+[Check if the Kubectl CLI is installed](didact://?commandId=vscode.didact.cliCommandSuccessful&text=kubectl-requirements-status$$kubectl%20help&completion=Checked%20kubectl%20tool%20availability "Tests to see if `kubectl help` returns a 0 return code"){.didact}
+
+*Status: unknown*{#kubectl-requirements-status}
+
+**Connection to a Kubernetes cluster**
+
+You need to connect to a Kubernetes cluster in order to run the example.
+
+[Check if you're connected to a Kubernetes cluster](didact://?commandId=vscode.didact.cliCommandSuccessful&text=cluster-requirements-status$$kubectl%20get%20pod&completion=Checked%20Kubernetes%20connection "Tests to see if `kubectl get pod` returns a 0 return code"){.didact}
+
+*Status: unknown*{#cluster-requirements-status}
+
+**Apache Camel K CLI ("kamel")**
+
+You need the Apache Camel K CLI ("kamel") in order to access all Camel K features.
+
+[Check if the Apache Camel K CLI ("kamel") is installed](didact://?commandId=vscode.didact.requirementCheck&text=kamel-requirements-status$$kamel%20version$$Camel%20K%20Client&completion=Checked%20if%20Camel%20K%20CLI%20is%20available%20on%20this%20system. "Tests to see if `kamel version` returns a result"){.didact}
+
+*Status: unknown*{#kamel-requirements-status}
+
+**Knative installed on the cluster**
+
+The cluster also needs to have Knative installed and working. Refer to the [official Knative documentation](https://knative.dev/docs/install/) for information on how to install it in your cluster.
+
+[Check if the Knative Serving is installed](didact://?commandId=vscode.didact.requirementCheck&text=kserving-project-check$$kubectl%20api-resources%20--api-group=serving.knative.dev$$kservice%2Cksvc&completion=Verified%20Knative%20services%20installation. "Verifies if Knative Serving is installed"){.didact}
+
+*Status: unknown*{#kserving-project-check}
+
+[Check if the Knative Eventing is installed](didact://?commandId=vscode.didact.requirementCheck&text=keventing-project-check$$kubectl%20api-resources%20--api-group=messaging.knative.dev$$inmemorychannels&completion=Verified%20Knative%20eventing%20services%20installation. "Verifies if Knative Eventing is installed"){.didact}
+
+*Status: unknown*{#keventing-project-check}
+
+**Knative Camel Source installed on the cluster**
+
+The cluster also needs to have installed the Knative Camel Source from the camel.yaml in the [Eventing Sources release page](https://github.com/knative/eventing-contrib/releases)
+
+[Check if the Knative Camel Source is installed](didact://?commandId=vscode.didact.requirementCheck&text=kservice-project-check$$kubectl%20api-resources%20--api-group=sources.knative.dev$$camelsources&completion=Verified%20Knative%20Camel%20Source%20installation. "Verifies if Knative Camel Source is installed"){.didact}
+
+*Status: unknown*{#kservice-project-check}
+
+### Optional Requirements
+
+The following requirements are optional. They don't prevent the execution of the demo, but may make it easier to follow.
+
+**VS Code Extension Pack for Apache Camel**
+
+The VS Code Extension Pack for Apache Camel provides a collection of useful tools for Apache Camel K developers,
+such as code completion and integrated lifecycle management. They are **recommended** for the tutorial, but they are **not**
+required.
+
+You can install it from the VS Code Extensions marketplace.
+
+[Check if the VS Code Extension Pack for Apache Camel by Red Hat is installed](didact://?commandId=vscode.didact.extensionRequirementCheck&text=extension-requirement-status$$redhat.apache-camel-extension-pack&completion=Camel%20extension%20pack%20is%20available%20on%20this%20system. "Checks the VS Code workspace to make sure the extension pack is installed"){.didact}
+
+*Status: unknown*{#extension-requirement-status}
+
+## 1. First steps
+
+Let's open a terminal and go to the example directory:
+
+```
+cd 90-aws-kinesis-customized-event-source
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$cd%2090-aws-kinesis-customized-event-source&completion=Executed%20command. "Opens a new terminal and sends the command above"){.didact})
+
+We're going to create a namespace named `aws-kinesis-customized-event-source` for running the example. To create it, execute the following command:
+
+```
+kubectl create namespace aws-kinesis-customized-event-source
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20create%20namespace%20aws-kinesis-customized-event-source&completion=New%20project%20creation. "Opens a new terminal and sends the command above"){.didact})
+
+Now we can set the `aws-kinesis-customized-event-source` namespace as default namespace for the following commands:
+
+```
+kubectl config set-context --current --namespace=aws-kinesis-customized-event-source
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20config%20set-context%20--current%20--namespace%3Daws-kinesis-customized-event-source&completion=New%20project%20creation. "Opens a new terminal and sends the command above"){.didact})
+
+You need to install Camel K in the `aws-kinesis-customized-event-source` namespace (or globally in the whole cluster).
+For this example to run, you must configure Camel K to include your Maven repository in its configuration, so that
+dependencies can be downloaded from it. To do so, execute the following command replacing `https://url.of.the.repository`
+with the actual URL of the repository:
+
+```
+kamel install --maven-repository https://url.of.the.repository
+```
+
+NOTE: The `kamel install` command requires some prerequisites to be successful in some situations, e.g. you need to enable the registry addon on Minikube. Refer to the [Camel K install guide](https://camel.apache.org/camel-k/latest/installation/installation.html) for cluster-specific instructions.
+
+To check that Camel K is installed we'll retrieve the IntegrationPlatform object from the namespace:
+
+```
+kubectl get integrationplatform
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20get%20integrationplatform&completion=Executed%20Command. "Opens a new terminal and sends the command above"){.didact})
+
+You should find an IntegrationPlatform in status `Ready`.
+
+You can now proceed to the next section.
+
+
+## 2. Deploy the custom client to a Maven repository
+
+
+Deploy the custom client to a maven repository, adjusting the command below so that the
+repository ID and the URL matches the ones used in your Maven repository.
+
+```
+mvn -f extra/custom-kinesis-configuration/pom.xml -DaltDeploymentRepository="id-of-the-repository::default::https://url.of.the.repository" deploy
+```
+
+## 3. Deploy LocalStack in the cluster
+
+Deploy the a LocalStack instance for testing:
+
+```
+kubectl apply -f extra/localstack.yaml
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20apply%20-f%20extra%2Flocalstack.yaml&completion=deployment%20%22localstack%22%20created. "Create a LocalStack deployment"){.didact})
+
+
+## 4. Preparing the environment
+
+This repository contains a simple [aws-kinesis.properties](didact://?commandId=vscode.openFolder&projectFilePath=05-aws-kinesis-source-advanced/aws-kinesis.properties&completion=Opened%20the%aws-kinesis.properties%20file "Opens the aws-kinesis.properties file"){.didact} that contains the access key and secret key for accessing the AWS Kinesis stream.
+
+```
+kubectl create secret generic aws-kinesis --from-file=aws-kinesis.properties
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20create%20secret%20generic%20aws-kinesis%20--from-file%3Daws-kinesis.properties&completion=secret%20%22aws-kinesis%22%20created. "Create a secret with AWS Kinesis credentials"){.didact})
+
+As the example levareges [Knative Eventing channels](https://knative.dev/docs/eventing/channels/), we need to create the one that the example will use:
+
+```
+kubectl apply -f aws-kinesis-channel.yaml
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20apply%20-f%20aws-kinesis-channel.yaml&completion=inmemorychannel.messaging.knative.dev/aws-kinesis$20created. "Create a Knative InMemoryChannel named aws-kinesis"){.didact})
+
+
+## 5. Running a Camel Source
+
+This repository contains a simple Camel Source based on the [AWS Kinesis component](https://camel.apache.org/components/latest/aws-kinesis-component.html) that forward streaming events received on the AWS Kinesis stream to a Knative channel named `aws-kinesis`.
+
+Use the following command to deploy the Camel Source:
+
+```
+kubectl apply -f aws-kinesis-source.yaml
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20apply%20-f%20aws-kinesis-source.yaml&completion=camelsource.sources.knative.dev/camel-aws-kinesis-source%20created. "Opens a new terminal and sends the command above"){.didact})
+
+## 6. Running a basic integration to create Kinesis events for consumption by the Camel Source
+
+You need a producer adding data to a Kinesis stream to try this example. This integration
+comes with a sample producer that will send 100 messages with the text `Hello Camel K`
+every 3 seconds.
+
+```
+kamel run --secret aws-kinesis --property camel.component.aws-kinesis.configuration=#class:org.apache.camel.k.examples.CustomKinesisConfiguration  --env AWS_HOST=localstack:4568 aws-kinesis-producer.groovy
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kamel%20run%20--secret%20aws-kinesis%20--dependency%20mvn:org.apache.camel.k.examples:custom-kinesis-configuration:1.0.1%20--property%20camel.component.aws-kinesis.configuration=%23class:org.apache.camel.k.examples.CustomKinesisConfiguration%20%20--env%20AWS_HOST=localstack:4568%20aws-kinesis-producer.groovy&completion=Ran%20the%20AWS%20Kinesis%20producer. "Opens a terminal and runs the command above" [...]
+
+If everything is ok, after the build phase finishes, you should see the Camel integration running.
+
+## 7. Running a basic integration to forward Kinesis events to the console
+
+```
+kamel run aws-kinesis-consumer.groovy --dev
+```
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kamel%20run%20aws-kinesis-consumer.groovy%20--dev&completion=Camel%20K%20aws-kinesis-consumer%20integration%20run%20in%20dev%20mode. "Opens a new terminal and sends the command above"){.didact})
+
+If everything is ok, after the build phase finishes, you should see the Camel integration running.
+
+
+## 8. Uninstall
+
+To cleanup everything, execute the following command:
+
+```kubectl delete namespace aws-kinesis-customized-event-source```
+
+([^ execute](didact://?commandId=vscode.didact.sendNamedTerminalAString&text=camelTerm$$kubectl%20delete%20namespace%20aws-kinesis-customized-event-source&completion=Removed%20the%20namespace%20from%20the%20cluster. "Cleans up the cluster after running the example"){.didact})
\ No newline at end of file
diff --git a/90-aws-kinesis-customized-event-source/readme.md b/90-aws-kinesis-customized-event-source/readme.md
new file mode 120000
index 0000000..c0bf82f
--- /dev/null
+++ b/90-aws-kinesis-customized-event-source/readme.md
@@ -0,0 +1 @@
+readme.didact.md
\ No newline at end of file
diff --git a/README.md b/README.md
index bdba4b3..5949284 100644
--- a/README.md
+++ b/README.md
@@ -52,3 +52,4 @@ This is the current list of examples:
 - [04 AWS Kinesis Source Basic](./04-aws-kinesis-source-basic): Learn how to consume AWS Kinesis events using Knative Camel Source.
 - [10 Knative Source Salesforce](./10-knative-source-salesforce): Learn how to create a Knative Camel Source for Salesforce.
 - [11 Knative Source Slack](./11-knative-source-slack): Getting started with Slack integration using Knative Camel Source.
+- [90 AWS Kinesis Source With a Custom Configuration](./90-aws-kinesis-customized-event-source): Learn how to use a custom AWS Kinesis configuration when consuming AWS Kinesis events using Knative Camel Source.