<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nicola Ferraro</title><description>Yet another software developer. Ideas are my own. Writing about Apache Camel, Kubernetes, and cloud-native integration.</description><link>https://www.nicolaferraro.me</link><item><title>println(&quot;Hello World!&quot;)</title><link>https://www.nicolaferraro.me/posts/hello-world</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/hello-world</guid><pubDate>Sun, 14 Feb 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to my new blog. Cool things are coming up...&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Exception Handling in Apache Spark</title><link>https://www.nicolaferraro.me/posts/exception-handling-in-apache-spark</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/exception-handling-in-apache-spark</guid><pubDate>Thu, 18 Feb 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Apache Spark is a fantastic framework for writing highly scalable applications.
Data and execution code are spread from the driver to tons of worker machines for parallel processing.
But debugging this kind of applications is often a really hard task.&lt;/p&gt;
&lt;p&gt;Exceptions need to be treated carefully, because a simple runtime exception caused by dirty source data can easily
lead to the &lt;strong&gt;termination of the whole process&lt;/strong&gt;. Let’s see an example.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// source contains dirty data
val transformed = source
  .map(e =&amp;gt; myCustomFunction(e))
  // do some other actions
 
transformed.saveAsTextFile(&quot;xxx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above is quite common in a Spark application.
Data gets transformed in order to be joined and matched with other data and the transformation algorithms
are often provided by the application coder into a &lt;em&gt;map&lt;/em&gt; function.
It is clear that, when you need to transform a RDD into another, the &lt;em&gt;map&lt;/em&gt; function is the best option,
as it changes every element of the RDD, without changing its size.
But an exception thrown by the &lt;em&gt;myCustomFunction&lt;/em&gt; transformation algorithm causes the &lt;strong&gt;job to terminate&lt;/strong&gt; with error.&lt;/p&gt;
&lt;p&gt;In the real world, a RDD is composed of millions or billions of simple records coming from different sources.
The probability of having wrong/dirty data in such RDDs is really high. In these cases, instead of letting
the process terminate, it is &lt;strong&gt;more desirable to continue processing&lt;/strong&gt; the other data and analyze, at the end
of the process, what has been left behind, and &lt;strong&gt;then decide if it is worth spending some time to find the
root causes of the problem&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;How should the code above change to support this behaviour? A first trial:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;val transformed = source
  .flatMap(e =&amp;gt; Try{myCustomFunction(e)}.toOption)
  // other actions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the function &lt;em&gt;myCustomFunction&lt;/em&gt; is executed within a Scala &lt;em&gt;Try&lt;/em&gt; block, then converted into an &lt;em&gt;Option&lt;/em&gt;.
The code is put in the context of a &lt;em&gt;flatMap&lt;/em&gt;, so the result is that all the elements that can be converted
using the custom function will be present in the resulting &lt;em&gt;RDD&lt;/em&gt;. Elements whose transformation function throws
an exception will be automatically discarded. Pretty good, &lt;strong&gt;but we have lost information about the exceptions&lt;/strong&gt;.
Can we do better?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why don’t we collect all exceptions, alongside the input data that caused them?&lt;/strong&gt;
If the exception are (as the word suggests) not the default case, they could all be collected by the driver
and then printed out to the console for debugging. What I mean is explained by the following code excerpt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// define an accumulable collection for exceptions
val accumulable = sc.accumulableCollection(mutable.HashSet[(Any, Throwable)]())
 
val transformed = source.flatMap(e =&amp;gt; {
  val fe = Try{myCustomFunction(e)}
  val trial = fe match {
    case Failure(t) =&amp;gt;
      // push to an accumulable collection 
      // both the input data and the throwable
      accumulable += (e, t)
      fe
    case t: Try[U] =&amp;gt; t
  }
  trial.toOption
})
 
// call at least one action on &apos;transformed&apos; (eg. count)
transformed.count
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Probably it is more verbose than a simple &lt;em&gt;map&lt;/em&gt; call.
I will simplify it at the end. Now that you have collected all the exceptions, you can print them as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// at the end of the process, print the exceptions
accumulable.value.foreach{case (i, e) =&amp;gt; {
  println(s&quot;--- Exception on input: ($i)&quot;)
  // using org.apache.commons.lang3.exception.ExceptionUtils
  println(ExceptionUtils.getStackTrace(e))
}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, so good. Now you can &lt;strong&gt;generalize the behaviour and put it in a library&lt;/strong&gt;.
Or... you&apos;d better use mine: &lt;a href=&quot;https://github.com/nerdammer/spark-additions&quot;&gt;https://github.com/nerdammer/spark-additions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Spark Additions&lt;/strong&gt; way is a lot &lt;strong&gt;easier&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// import all implicit conversions
import it.nerdammer.spark.additions._
 
// ...
val transformed = source
  .tryMap(e =&amp;gt; myCustomFunction(e))
 
// call at least one action on &apos;transformed&apos; (eg. count)
transformed.count
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;tryMap&lt;/em&gt; method does everything for you.&lt;/p&gt;
&lt;p&gt;What you need to write is the code that gets the exceptions on the driver and prints them. Very easy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// sc is the SparkContext: now with a new method
sc.accumulatedExceptions()
  .foreach{case (i, e) =&amp;gt; {
    println(s&quot;--- Exception on input: ($i)&quot;)
    println(ExceptionUtils.getStackTrace(e))
  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More usage examples and tests &lt;a href=&quot;https://github.com/nerdammer/spark-additions/blob/master/core/src/test/scala/com/enterprise/integration/tests/tryfunctions/BasicTryFunctionsIT.scala&quot;&gt;here (BasicTryFunctionsIT)&lt;/a&gt;.
Look also at the &lt;a href=&quot;https://github.com/nerdammer/spark-additions/tree/master/core/src/main/scala/it/nerdammer/spark/additions/tryfunctions/&quot;&gt;package implementing the Try-Functions&lt;/a&gt; (there is also a &lt;strong&gt;tryFlatMap function&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;Contributions are always appreciated.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Using Non-Serializable Objects in Apache Spark</title><link>https://www.nicolaferraro.me/posts/using-non-serializable-objects-in-apache-spark</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/using-non-serializable-objects-in-apache-spark</guid><pubDate>Mon, 22 Feb 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Anyone who starts writing applications for Apache Spark encounters immediately an infamous exception...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;org.apache.spark.SparkException: Task not serializable
	at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:304)
	at org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:294)
	at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:122)
	at org.apache.spark.SparkContext.clean(SparkContext.scala:2055)
	at org.apache.spark.rdd.RDD$$anonfun$map$1.apply(RDD.scala:324)
	at org.apache.spark.rdd.RDD$$anonfun$map$1.apply(RDD.scala:323)
	at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:150)
	at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:111)
	at org.apache.spark.rdd.RDD.withScope(RDD.scala:316)
	at org.apache.spark.rdd.RDD.map(RDD.scala:323)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This happens whenever Spark tries to transmit the scheduled tasks to remote machines. Tasks are just pieces of application code that are sent from the driver to the workers.&lt;/p&gt;
&lt;p&gt;Given the frequency of that exception, &lt;strong&gt;one may think that any piece of code that is executed by a worker node must be serializable. Fortunately, that is not true&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The classpath of the driver and worker nodes are controlled by the user that is launching the application. This is the case when the application is launched in a standalone Spark cluster as well when an external cluster manager, like YARN, is used. If the deployment solution is an uber-jar, the jar will be shared among all machines. When the application is composed of multiple separate jars, the –jars option (supported in YARN mode) can be used to include them all in the classpaths of the worker JVMs.&lt;/p&gt;
&lt;p&gt;In this context, it is quite easy to use non-serializable objects in tasks.
The only requirement is that they have &lt;strong&gt;just a serializable initialization code&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s see an example. Suppose you want to connect from the remote worker machines to a JDBC data source (hope that connections are issued towards a NoSQL – a.k.a. NowSequel – database). Connection factories are often not serializable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// A pooled: org.apache.commons.dbcp2.BasicDataSource
val ds = new BasicDataSource() // Not serializable
ds.setDriverClassName(&quot;org.driver.Classname&quot;)
ds.setUrl(&quot;...&quot;)
// set username, options
 
sc.parallelize(1 to 10)
  .map(i =&amp;gt; {
    val conn = ds.getConnection
    // do something
    conn.close()
  })
  .count
 
// does it work?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, &lt;strong&gt;it will not work&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;org.apache.spark.SparkException: Task not serializable
...
...
Caused by: java.io.NotSerializableException: org.apache.commons.dbcp2.BasicDataSource
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It throws the infamous “Task not serializable” exception. But you can just wrap it in an object to make it available at the worker side.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Holds a reference to the datasource factory
object Holder {
 
  def ds() = {
    val ds = new BasicDataSource()
    ds.setDriverClassName(&quot;org.driver.Classname&quot;)
    ds.setUrl(&quot;...&quot;)
    // set username, options
    ds
  }
 
}
 
object SparkApplication {
 
  def main(args: Array[String]) {
    // init Spark Context sc
    sc.parallelize(1 to 10)
        .map(i =&amp;gt; {
          val conn = Holder.ds.getConnection
          // do something
          conn.close()
        })
        .count
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why does it work?&lt;/strong&gt;
Scala functions declared inside objects are equivalent to static Java methods. In order to call a static method, you don’t need to serialize the class, you need the declaring class to be reachable by the classloader (and it is the case, as the jar archives can be shared among driver and workers).&lt;/p&gt;
&lt;p&gt;Creating external objects can be tedious. I’ve included some utilities in the &lt;a href=&quot;https://github.com/nerdammer/spark-additions&quot;&gt;https://github.com/nerdammer/spark-additions&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;For example, to share the datasource one might write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Declare it as a shared variable
val dsv = SharedVariable {
  val ds = new BasicDataSource() // not serializable
  ds.setDriverClassName(&quot;org.driver.Classname&quot;)
  ds.setUrl(&quot;...&quot;)
  // set username, options
  ds
}
 
sc.parallelize(1 to 10)
  .map(i =&amp;gt; {
    val ds = dsv.get
    // do something
  })
  .count
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any call to &lt;em&gt;dsv.get&lt;/em&gt; that is executed at the worker side will create a new instance of the datasource.
Alternatively the library allows you to define a &lt;em&gt;SharedSingleton&lt;/em&gt;.
There will be at most one instance of the &lt;em&gt;SharedSingleton&lt;/em&gt; in each JVM of the Spark cluster.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// An object that acts as a singleton in each JVM of the cluster
val connectionPool = SharedSingleton {
  // initialization code
}
 
sc.parallelize(1 to 10)
  .map(i =&amp;gt; {
    val cp = connectionPool.get
    // use the local-JVM connection pool
  })
  .count
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both &lt;em&gt;SharedVariable&lt;/em&gt; and &lt;em&gt;SharedSingleton&lt;/em&gt; objects can be used to share non-serializable objects that need to be used in task closures.
There are other solutions that work in these circumstances, but boilerplate is reduced when using shared variables.
More info &lt;a href=&quot;https://github.com/nerdammer/spark-additions/tree/master/core/src/main/scala/it/nerdammer/spark/additions/variables&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Spark-HBase-Connector 1.0.2 is out</title><link>https://www.nicolaferraro.me/posts/spark-hbase-connector-1-0-2-is-out</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/spark-hbase-connector-1-0-2-is-out</guid><pubDate>Sun, 28 Feb 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The Spark-HBase-Connector project started as a 3-days programming marathon I made last year. At home, with the flu.
Now it is becoming one of the most popular drivers to read/write data to Apache HBase from Spark.&lt;/p&gt;
&lt;p&gt;The project is hosted on github: &lt;a href=&quot;https://github.com/nerdammer/spark-hbase-connector&quot;&gt;https://github.com/nerdammer/spark-hbase-connector&lt;/a&gt;.
The library is also available on Maven. You can find more information on the github page.&lt;/p&gt;
&lt;p&gt;Probably, its future will be limited by the advent of Apache Phoenix but, for now,
Phoenix is running slowly and the connector’s popularity is increasing.&lt;/p&gt;
&lt;p&gt;Some small improvements have been applied to the code base for version 1.0.2. Now Spark-HBase-Connector supports Spark 1.6.0+ and HBase 1.0.1.1+.
Support for tables with up to 22 columns has been added.&lt;/p&gt;
&lt;p&gt;Thanks for the contributions arrived so far. Pull requests are always appreciated.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>A Brief History of Big Data</title><link>https://www.nicolaferraro.me/posts/a-brief-history-of-big-data</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/a-brief-history-of-big-data</guid><pubDate>Fri, 04 Mar 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Why everybody talks about Big Data? Where does Hadoop come from? Which steps led to the diffusion of Spark? What’s next?&lt;/p&gt;
&lt;p&gt;This presentation will drive you through all the steps that brought to this “big” change.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/rT6NWvtd5jYAyV&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Logging to a NoSQL DB from Spark</title><link>https://www.nicolaferraro.me/posts/logging-to-nosql-from-spark</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/logging-to-nosql-from-spark</guid><pubDate>Mon, 07 Mar 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Logging effectively is often a hard task in standard applications. But when the application runs in a distributed environment, for instance, a Spark job in a big YARN cluster,
it becomes ten times harder.&lt;/p&gt;
&lt;p&gt;Jobs are split into thousands of tasks that run inside multiple worker machines,
so the classic &lt;strong&gt;console logging is not a good option&lt;/strong&gt;, because the logs get written to the standard output of
several remote machines, making it impossible to find useful information.&lt;/p&gt;
&lt;p&gt;One of the best options available in all modern data platforms is &lt;strong&gt;logging to a NoSQL database&lt;/strong&gt;.
Many data platforms support HBase and Phoenix as NoSQL layer, so why don’t using a Phoenix table to store the logs?&lt;/p&gt;
&lt;p&gt;First of all, the table must be created inside Phoenix, and it must be &lt;strong&gt;optimized for efficiently writing the log data&lt;/strong&gt;.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE LOG 
(
  LOG_DATE  TIMESTAMP  NOT NULL,
  LOG_ID    BIGINT     NOT NULL,
  LOGGER    VARCHAR(150),
  LEVEL     VARCHAR(10),
  MESSAGE   VARCHAR(8192)
  CONSTRAINT LOG_PK PRIMARY KEY (LOG_DATE, LOG_ID)
) SALT_BUCKETS = 50;
 
CREATE SEQUENCE SEQ_LOG_ID MINVALUE 1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;LOG&lt;/em&gt; table is defined as a &lt;strong&gt;salted table&lt;/strong&gt; with &lt;em&gt;50&lt;/em&gt; buckets
(the number can be increased/decreased, depending on the size of the cluster).
Bucketing is needed to spread the data across multiple region servers,
in order to balance the load across all the machines.
The &lt;em&gt;LOG&lt;/em&gt; table has a timestamp as first column of the primary key (that is a monotonically increasing field) so,
if salting buckets were not in place, only one machine at a time would be used to store the logs.
The &lt;em&gt;LOG_ID&lt;/em&gt; column is part of the primary key. It is useful to prevent collisions among log messages.&lt;/p&gt;
&lt;p&gt;Once the table is defined, we need to configure &lt;em&gt;log4j&lt;/em&gt; to store log messages inside it.
Phoenix is compliant with the JDBC API.
This allows using the &lt;code&gt;JDBCAppender&lt;/code&gt;.
Unfortunately, the standard &lt;code&gt;JDBCAppender&lt;/code&gt; is not perfect for being used with Phoenix,
just because &lt;strong&gt;it does not commit the transactions&lt;/strong&gt;.
Of course, &lt;strong&gt;I’m not saying that Phoenix supports transactions&lt;/strong&gt; (not now).
Phoenix requires that you commit the &lt;code&gt;UPSERT&lt;/code&gt; statements,
otherwise they will remain stuck in the driver’s cache.
So, we need to write a custom extension of the &lt;code&gt;JDBCAppender&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package it.nerdammer.log4j;
 
import org.apache.log4j.jdbc.JDBCAppender;
 
import java.sql.Connection;
import java.sql.SQLException;
 
public class PhoenixAppender extends JDBCAppender {
 
    protected Connection getConnection() throws SQLException {
        Connection connection = super.getConnection();
        connection.setAutoCommit(true);
 
        return connection;
    }
 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The class above just sets the &lt;code&gt;autocommit=true&lt;/code&gt; property on every connection created by the &lt;code&gt;JDBCAppender&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that we have an appender compatible with Phoenix, the next step is configuring it in the &lt;em&gt;log4j.properties&lt;/em&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Root logger option
log4j.rootLogger=INFO, stdout
 
log4j.logger.com.enterprise=INFO, phoenix
log4j.additivity.com.enterprise=true
 
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
 
 
log4j.appender.phoenix=it.nerdammer.log4j.PhoenixAppender
log4j.appender.phoenix.URL=jdbc:phoenix:phoenixhost
log4j.appender.phoenix.user=anyuser
log4j.appender.phoenix.password=anypassword
log4j.appender.phoenix.driver=org.apache.phoenix.jdbc.PhoenixDriver
log4j.appender.phoenix.sql=UPSERT INTO LOG (LOG_DATE, LOG_ID, LOGGER, LEVEL, MESSAGE) VALUES (&apos;%d&apos;, NEXT VALUE FOR SEQ_LOG_ID, &apos;%C&apos;, &apos;%p&apos;, &apos;%m&apos;)
log4j.appender.phoenix.layout=org.apache.log4j.PatternLayout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An appender named &lt;code&gt;phoenix&lt;/code&gt; has been created.
It has been associated with the logger named “com.enterprise”.
You can change it to the base package of your application, but &lt;strong&gt;note:
you cannot associate the phoenix appender to the root logger&lt;/strong&gt;. The reason is that &lt;strong&gt;Phoenix itself uses log4j
while initializing the connection to the database&lt;/strong&gt;.
If you allow the logger &lt;code&gt;org.apache.phoenix&lt;/code&gt; to append logs to the Phoenix table,
you will get soon a &lt;strong&gt;stackoverflow&lt;/strong&gt; error. One way of breaking the loop it is limiting the usage of the “phoenix”
appender to just few packages of your application (in the example &lt;code&gt;com.enterprise&lt;/code&gt; and all its sub-packages).&lt;/p&gt;
&lt;p&gt;In order to test locally, you can just run one docker container with everything preinstalled,
for example, &lt;strong&gt;my dockmob container for Phoenix&lt;/strong&gt; &lt;a href=&quot;https://hub.docker.com/r/dockmob/phoenix/&quot;&gt;https://hub.docker.com/r/dockmob/phoenix/&lt;/a&gt;,
using the following script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# 
# Before executing the script, add to /etc/hosts the following entry
# &amp;lt;docker-machine-ip&amp;gt; phoenixhost
#
# Where &amp;lt;docker-machine-ip&amp;gt; is the IP assigned to the docker machine on OSX (usually 192.168.99.100), 
# or 127.0.0.1 on Linux
 
MYPHOENIX_ID=$(docker run -d -p 2181:2181 -p 60000:60000 -p 60010:60010 -p 60020:60020 -p 60030:60030 -h phoenixhost dockmob/phoenix:4.5.2-1.0.1 -t pseudodistributed)
docker exec -it $MYPHOENIX_ID /usr/lib/phoenix/bin/sqlline.py localhost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last command starts a &lt;strong&gt;SQL console&lt;/strong&gt; on the Phoenix instance.
You need to paste the previous SQL commands to &lt;strong&gt;create the LOG table&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ensure you have put all the required libraries for writing to Phoenix in the Spark application classpath&lt;/strong&gt;.
Here is a simple test for verifying if it works:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.enterprise.test
 
import java.sql.{DriverManager}
 
import it.nerdammer.log4j.PhoenixAppender
import org.apache.log4j.Logger
import org.apache.spark.{SparkConf, SparkContext}
import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers}
 
class SparkJobTest extends FlatSpec with Matchers with BeforeAndAfterAll {
 
  lazy val sc: SparkContext = {
    val conf = new SparkConf()
      .setAppName(&quot;Console Test&quot;)
      .setMaster(&quot;local&quot;)
 
    new SparkContext(conf)
  }
 
  override protected def beforeAll(): Unit = sc
 
  override protected def afterAll(): Unit = sc.stop()
 
 
  &quot;the console logger &quot; should &quot;work&quot; in {
 
    val databaseURL = Logger.getLogger(&quot;com.enterprise&quot;).getAppender(&quot;phoenix&quot;).asInstanceOf[PhoenixAppender].getURL
    val conn = DriverManager.getConnection(databaseURL, &quot;any&quot;, &quot;any&quot;)
    conn.setAutoCommit(true)
    val pstm = conn.prepareStatement(&quot;delete from log&quot;)
    pstm.execute()
    pstm.close()
 
    sc.parallelize(1 to 10)
      .map(e =&amp;gt; {
        Logger.getLogger(classOf[SparkJobTest]).info(&quot;This is a log message&quot;)
        e
      })
      .count();
 
    val pstm2 = conn.prepareStatement(&quot;select count(*) from log&quot;)
    val rs = pstm2.executeQuery()
    rs.next()
    val count = rs.getInt(1)
    rs.close()
    pstm.close()
    conn.close()
 
    assert(count == 10)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the logs appear if you query the LOG table using the SQL console.
You can find the full code here: &lt;a href=&quot;https://github.com/nerdammer/spark-additions/tree/master/log4j-phoenix&quot;&gt;https://github.com/nerdammer/spark-additions/tree/master/log4j-phoenix&lt;/a&gt;.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Spash - Organizing your Big Data with SSH and Bash</title><link>https://www.nicolaferraro.me/posts/spash-organizing-your-big-data-with-ssh-and-bash</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/spash-organizing-your-big-data-with-ssh-and-bash</guid><pubDate>Sat, 16 Apr 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Spash is a command line tool for Big Data platforms that simulates a real Unix environment,
providing most of the commands of a typical Bash shell on top of YARN, HDFS and Apache Spark.&lt;/p&gt;
&lt;p&gt;Spash uses the HDFS APIs to execute simple file operations and Apache Spark to perform parallel computations on big datasets.
With Spash, managing a Big Data cluster becomes &lt;em&gt;as natural as writing bash commands&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Spash is an open source project from an idea of &lt;a href=&quot;http://nicola-barbieri.tumblr.com/&quot;&gt;Nicola Barbieri&lt;/a&gt;.
The code is here: &lt;a href=&quot;https://github.com/nerdammer/spash&quot;&gt;https://github.com/nerdammer/spash&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Architecture&lt;/h2&gt;
&lt;p&gt;The Spash daemon runs on an edge node of a Big Data cluster and listens for incoming SSH connections on port &lt;code&gt;2222&lt;/code&gt;.
Clients can connect using the OS native terminal application, or &lt;a href=&quot;http://www.putty.org/&quot;&gt;Putty&lt;/a&gt; on Windows.&lt;/p&gt;
&lt;p&gt;The Spash daemon will emulate a Unix OS and leverage the power of Spark to perform efficient computations on distributed data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/spash.png&quot; alt=&quot;Spash Architecture&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;The World Before Spash&lt;/h2&gt;
&lt;p&gt;For those who don’t remember the classic way of doing simple operations on HDFS, here’s a reminder:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash$ hdfs dfs -ls /
#
##
### [wait for the JVM to load and execute]
...
##########################################
bash$ hdfs dfs -copyFromLocal myFile /
#
##
### [wait for the JVM to load and execute]
...
##########################################
bash$
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Spash Makes It Easier&lt;/h2&gt;
&lt;p&gt;Just run the Spash daemon on a node of your Big Data cluster,
you can connect to it using &lt;code&gt;ssh user@hdfshost -p 2222&lt;/code&gt; (the password is &lt;code&gt;user&lt;/code&gt;) and then run all your favourite
bash commands to manipulate data.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user@spash:/$ echo &quot;Maybe I can provide a real life example...&quot;
Maybe I can provide a real life example...
 
user@spash:/$ echo &quot;My content&quot; &amp;gt; myFile
 
user@spash:/$ ls
myFile
 
user@spash:/$ cat myFile
My content
 
user@spash:/$ echo text2 &amp;gt; myFile2
 
user@spash:/$ ls -l
drwxr-xr-x 4 user supergroup 0 30 mar 18:34 myFile 
drwxr-xr-x 4 user supergroup 0 30 mar 18:35 myFile2
 
user@spash:/$ cat myFile myFile2 &amp;gt; myFile3
 
user@spash:/$ cat myFile3
My content
text2
 
user@spash:/$ cat myFile3 | grep -v 2
My content
 
user@spash:/$ exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is just the tip of the iceberg.
From your host, you can use scp (&lt;code&gt;scp myfile -P 2222 user@hdfshost:/&lt;/code&gt;) to copy a file into hdfs. You can even use FileZilla or WinSCP to browse HDFS.&lt;/p&gt;
&lt;p&gt;Spash works on Cloudera CDH 5 and many other platforms.&lt;/p&gt;
&lt;p&gt;Spash is a &lt;em&gt;proof of concept&lt;/em&gt; and needs contributions.
Look at how to contribute and get involved on the project home page: &lt;a href=&quot;https://github.com/nerdammer/spash&quot;&gt;https://github.com/nerdammer/spash&lt;/a&gt;.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Creating a Telegram Bot in 5 minutes with Apache Camel</title><link>https://www.nicolaferraro.me/posts/creating-a-telegram-bot-in-5-minutes-with-apache-camel</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/creating-a-telegram-bot-in-5-minutes-with-apache-camel</guid><pubDate>Fri, 27 May 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I started contributing to open source software of the Apache Software Foundation and I developed
&lt;strong&gt;camel-telegram&lt;/strong&gt;, a component that allows camel based applications to exchange data using the Telegram messaging network.
It has been released as of Apache Camel 2.18.0.&lt;/p&gt;
&lt;p&gt;The component is targeted to enterprise applications, to let them route chat messages within their ESB and communicate with users in a novel way.
Camel is a widely used integration layer, that forms the basis of production-grade enterprise platforms such as &lt;a href=&quot;http://www.jboss.org/products/fuse/overview/&quot;&gt;JBoss Fuse&lt;/a&gt;.
But there exists also a simpler and more ludic way of using it, to create a reactive &lt;strong&gt;messaging Bot&lt;/strong&gt;. I’ll explain how to create such a bot with a 5-mins step by step guide.
The full documentation is available in the &lt;a href=&quot;http://camel.apache.org/telegram.html&quot;&gt;Camel manual&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Creating the Telegram Bot&lt;/h2&gt;
&lt;p&gt;Before getting into the code, you first need to create the bot.
Telegram lets you create bots by chatting with the &lt;strong&gt;@BotFather&lt;/strong&gt;, the father of all Bots.
The procedure is simple and takes just a minute. Open the Telegram app &lt;strong&gt;with your smartphone&lt;/strong&gt;
(it is better using the web version at &lt;a href=&quot;https://web.telegram.org/&quot;&gt;https://web.telegram.org/&lt;/a&gt;, because you’ll have to copy/paste an access token) and start a chat with the &lt;strong&gt;@BotFather&lt;/strong&gt;.
So, just press the “write” button and type “@BotFather” (without quotes) as recipient, even if it does not appear at first in your contact list.&lt;/p&gt;
&lt;p&gt;Here is what you need to tell the @BotFather:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/newbot
the-bot-name
the-bot-id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just replace “the-bot-name” with a friendly name for your bot and “the-bot-id” with the unique name
(use your fantasy, a lot of names are already taken). Here I attach two screenshots to show the creation of a bot.&lt;/p&gt;
&lt;p&gt;| &lt;img src=&quot;/images/telegram-1.jpg&quot; alt=&quot;Bot Creation&quot; /&gt; | &lt;img src=&quot;/images/telegram-2.jpg&quot; alt=&quot;Choosing the name&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You need to annotate the authorization token given by the @BotFather in the last message.
It is the key that lets your application act as the Bot (don’t try using the one in the picture, I revoked it :D).&lt;/p&gt;
&lt;h2&gt;Looking at the Code&lt;/h2&gt;
&lt;p&gt;Now the programming part. Just clone the skeleton of the bot using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/nicolaferraro/telegram-quickstart.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Git will create the structure of the quickstart project. You need &lt;strong&gt;just to customize 2 files in order to create your own chat bot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;m now going to explain all the relevant parts, you can find the full code in the github repo &lt;a href=&quot;https://github.com/nicolaferraro/telegram-quickstart&quot;&gt;https://github.com/nicolaferraro/telegram-quickstart&lt;/a&gt;. First, the Maven &lt;em&gt;pom.xml&lt;/em&gt;,
that imports the camel-telegram-starter component and all the related libraries.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;!-- ... --&amp;gt;
    &amp;lt;properties&amp;gt;
        &amp;lt;camel.version&amp;gt;2.18.0&amp;lt;/camel.version&amp;gt;
        &amp;lt;spring-boot.version&amp;gt;1.4.1.RELEASE&amp;lt;/spring-boot.version&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;!-- Some dependency management --&amp;gt;
    &amp;lt;dependencyManagement&amp;gt;
        &amp;lt;dependencies&amp;gt;
            &amp;lt;dependency&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;camel-spring-boot-dependencies&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;${camel.version}&amp;lt;/version&amp;gt;
                &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
                &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
            &amp;lt;/dependency&amp;gt;
            &amp;lt;dependency&amp;gt;
                &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;spring-boot-dependencies&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;${spring-boot.version}&amp;lt;/version&amp;gt;
                &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
                &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
            &amp;lt;/dependency&amp;gt;
        &amp;lt;/dependencies&amp;gt;
    &amp;lt;/dependencyManagement&amp;gt;

    &amp;lt;dependencies&amp;gt;

        &amp;lt;!-- Import the camel-telegram dependency --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;camel-telegram-starter&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;

    &amp;lt;/dependencies&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Second, we define a camel route to describe how messages should flow inside the application. It is defined using the Java syntax in the &lt;strong&gt;CamelRoute&lt;/strong&gt; class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.example;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * This class is responsible for routing the messages from and to the Telegram chat.
 */
@Component
public class CamelRouter extends RouteBuilder {

    @Autowired
    private Bot bot;

    @Override
    public void configure() throws Exception {

        from(&quot;telegram:bots&quot;)
        .bean(bot)
        .to(&quot;telegram:bots&quot;);

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you see, all incoming messages are routed to a bean named Bot and the replies generated by the Bot are routed again to the source chat.
Note that the Telegram component (starter version) requires that you specify the Telegram authorization token inside the &lt;strong&gt;application.properties&lt;/strong&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# To keep the application alive
camel.springboot.main-run-controller=true

# Create a new bot using the BotFather, then put here your token
camel.component.telegram.authorization-token=replace-me-with-your-telegram-token
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;You must change the file to put your own authorization token&lt;/strong&gt;, the one given by the @BotFather.&lt;/p&gt;
&lt;p&gt;To complete the picture we just need to write down the &lt;strong&gt;Bot&lt;/strong&gt; logic, by implementing one method in the Bot class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * This class contains the chat-bot logic: use your fantasy to implement your own Bot.
 */
@Component
public class Bot {

    private Logger log = LoggerFactory.getLogger(getClass());

    /**
     * This method processes incoming messages and return responses.
     *
     * @param message a message coming from a human user in a chat
     * @return the reply of the bot. Return null if you don&apos;t want to answer
     */
    public String process(String message) {
        if (message == null) {
            return null; // skip non-text messages
        }

        log.info(&quot;Received message: {}&quot;, message);

        return &quot;Why did you say \&quot;&quot; + message.replace(&quot;\&quot;&quot;, &quot;-&quot;) + &quot;\&quot;?&quot;;
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can leave the current implementation as it is and the Bot will reply to every message with a question (&lt;strong&gt;just like a 3-years old baby!!&lt;/strong&gt;), but I’d better write something else :)&lt;/p&gt;
&lt;p&gt;You can change the signature of the method to be able to receive and send also media content (like &lt;strong&gt;photo and video&lt;/strong&gt;) to create a more interesting Bot.
Look at &lt;a href=&quot;http://camel.apache.org/telegram.html&quot;&gt;the documentation&lt;/a&gt; for more info.&lt;/p&gt;
&lt;h2&gt;Running the Bot&lt;/h2&gt;
&lt;p&gt;You just need Maven and Java 8 to run the Bot. From the &lt;strong&gt;root of the project&lt;/strong&gt; (where the &lt;em&gt;pom.xml&lt;/em&gt; is located), type the following command in a shell to run the application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn spring-boot:run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Maven will download all the dependencies and run your code.&lt;/p&gt;
&lt;p&gt;Leave the application running and &lt;strong&gt;contact your bot with your smartphone&lt;/strong&gt;
(just write a message to @your-bot-id, using your Telegram app), &lt;strong&gt;it will reply to all your messages&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you want to &lt;strong&gt;package the application&lt;/strong&gt; in a single jar, you can run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn package
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will create a single jar with all the dependent jars &lt;strong&gt;nested&lt;/strong&gt; inside it (note: this is different from a classic uber-jar, it is closer to a .war file).
You’ll find the packaged jar into the target directory and you can just &lt;strong&gt;run it&lt;/strong&gt; using:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java -jar target/telegram-quickstart-1.0.0-SNAPSHOT.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Have fun!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Apache Camel meets Spring-Boot</title><link>https://www.nicolaferraro.me/posts/apache-camel-meets-spring-boot</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/apache-camel-meets-spring-boot</guid><pubDate>Sun, 25 Sep 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Next version of Apache Camel (2.18.0) is about to come with a long list of new features and components.&lt;/p&gt;
&lt;p&gt;Even if previous release of Camel was &lt;code&gt;2.17.3&lt;/code&gt;, the new version is actually a major release, containing a
lot of improvements over previous version.&lt;/p&gt;
&lt;p&gt;Now Camel compiles against &lt;strong&gt;Java 8&lt;/strong&gt; and most part of the code has been allowed to use constructs like lambdas,
but also the API interfaces have been adapted to support lambdas in the user code, eg. in transformations.&lt;/p&gt;
&lt;p&gt;Camel &lt;code&gt;2.18.0&lt;/code&gt; comes with a new set of components ideal for building microservices. The list contains the new circuit breakers
in &lt;code&gt;camel-hystrix&lt;/code&gt;, load balancing with &lt;code&gt;camel-ribbon&lt;/code&gt;, distributed tracing with &lt;code&gt;camel-zipkin&lt;/code&gt;.
These are just some of the new components of a long list that include also my pet component &lt;code&gt;camel-telegram&lt;/code&gt;,
to quickly create applications integrated with the popular messaging app.&lt;/p&gt;
&lt;p&gt;A Camel Spring-Boot application now automatically provides reliable health checks at the endpoint &lt;code&gt;/health&lt;/code&gt;,
leveraging the Spring-Boot actuator module.
This is a fundamental requirement for any microservice living in a cloud environment, because it allows the cloud platform (eg. Kubernetes)
to detect any anomaly and take corrective actions.&lt;/p&gt;
&lt;p&gt;Indeed, one of the big news in the context of Microservices is that much effort has been made to improve Camel&apos;s compatibility with &lt;strong&gt;Spring-Boot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Spring-Boot is one of the top trending frameworks in the &lt;em&gt;Microservices&lt;/em&gt; era,
one of the fundamental building blocks for creating cloud enabled applications, at least in the Java universe.
Camel integration with Spring has ancient roots and recent releases included some features that simplified
the usage of Camel into Spring-Boot applications, but &lt;em&gt;this time we have done much more&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Camel Spring-Boot Starters&lt;/h2&gt;
&lt;p&gt;We have done a major refactoring of the code, separating the pure components from platform related features.
In the case of Spring-Boot, this led to the creation of &lt;strong&gt;Component Starters&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A component starter is just like a normal Camel component, but it&apos;s &lt;em&gt;optimized for the Spring-Boot framework&lt;/em&gt;.
Maven users should just add a &lt;code&gt;-starter&lt;/code&gt; suffix to the name of the component to switch to its starter version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...
  &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;camel-http-starter&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.18.0&amp;lt;/version&amp;gt;
  &amp;lt;/dependency&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;But, what does it mean being optimized for Spring-Boot?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Spring-Boot is an opinionated framework, meaning that developers using it are choosing a specific set of technologies,
products and patterns to develop their applications. One of the implications is that Spring-Boot &quot;requires&quot; you to use
specific versions of some third party artifacts to play well in the ecosystem.&lt;/p&gt;
&lt;p&gt;Starters bring with them a set of transitive dependencies perfectly compatible
with the ones expected by the Spring-Boot framework. Versions are aligned with latest version of Spring-Boot (currently &lt;code&gt;1.4.1.RELEASE&lt;/code&gt;),
logging is configured to match the Spring-Boot standard logging framework, and so on.
Starters are meant to be included in a &lt;code&gt;pom.xml&lt;/code&gt; and used, without hassle.&lt;/p&gt;
&lt;p&gt;A new BOM (Bill of Material) is provided with the new version of Camel: &lt;code&gt;camel-spring-boot-dependencies&lt;/code&gt;. It has no conflicts with the Spring framework&apos;s &lt;code&gt;spring-boot-dependencies&lt;/code&gt; BOM
and it replace the classical Camel BOM (&lt;code&gt;camel-parent&lt;/code&gt;) in Spring-Boot applications.&lt;/p&gt;
&lt;h2&gt;Configuration of Starters&lt;/h2&gt;
&lt;p&gt;One of the most important features included in the starters is the possibility to configure Camel components using the new Spring-Boot configuration mechanism.&lt;/p&gt;
&lt;p&gt;Once a starter is included in the &lt;code&gt;pom.xml&lt;/code&gt; file, the IDE will suggest all the configuration options available for that starter.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/spring-boot-configuration.gif&quot; alt=&quot;Auto Configuration&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This helps configuring the application easily, using the &lt;code&gt;application.properties&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;A related feature that spring-boot offers out of the box is the possibility to override such configuration using environment variables or
Java options. This is a great feature when you plan to run the application in a cloud platform like &lt;strong&gt;Kubernetes&lt;/strong&gt; or &lt;strong&gt;Openshift&lt;/strong&gt;,
since you can exploit it to override some environment related settings using environment variables set up by the cloud platform automatically (eg. external services).
A Kunernetes&apos; &lt;strong&gt;ConfigMap&lt;/strong&gt; can also be bound to environment variables, providing a way to inject external configuration into the application.&lt;/p&gt;
&lt;p&gt;Trends are changing but camels are creatures that can adapt well to every environment!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Hot Reconfiguration of Microservices on Kubernetes</title><link>https://www.nicolaferraro.me/posts/hot-reconfiguration-of-microservices-on-kubernetes</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/hot-reconfiguration-of-microservices-on-kubernetes</guid><pubDate>Sun, 23 Oct 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Spring Cloud Kubernetes is a fantastic project from the Fabric8 team that contains a lot of useful tools for building spring-boot based microservices.
Version &lt;em&gt;0.1.3&lt;/em&gt; includes a new feature that allows changing the configuration of a microservice at runtime using Kubernetes config maps.&lt;/p&gt;
&lt;p&gt;Spring-boot applications are much appreciated for their simple configuration mechanism, based on properties or yaml files.
There is plenty of ways to override the default settings of an application, usually provided in the bundled &quot;application.properties&quot; file.
Environment variables take precedence over the provided configuration and this is particularly useful to automatically configure hosts and ports of external services inside Kubernetes.
Other ways, like command line options or external configuration files, are supported &lt;a href=&quot;http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html&quot;&gt;out of the box&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By just including Spring Cloud Kubernetes into the microservice, the application configuration can be also provided using &lt;strong&gt;Kubernetes config maps&lt;/strong&gt;.
What&apos;s new is that the application can be configured to &lt;strong&gt;listen for changes in the Kubernetes namespace&lt;/strong&gt; and apply the new configuration at runtime as soon as the config map is updated.
Reconfiguration is applied immediately and only the configurable beans are reloaded to reflect the new settings.
Respect to other solutions, hot reload &lt;strong&gt;does not require downtime&lt;/strong&gt; because the application is not restarted (nor the application context).&lt;/p&gt;
&lt;p&gt;I&apos;ll show the usage of this new feature with a quickstart. Let&apos;s create a &lt;em&gt;Camel&lt;/em&gt; microservice (the feature works also without &lt;em&gt;Camel&lt;/em&gt;) with a simple route:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Component
public class Route extends RouteBuilder {

    @Autowired
    private RouteConfig config;

    @Override
    public void configure() throws Exception {

        from(&quot;timer://tick?period=3000&quot;)
                .id(&quot;generation&quot;)
                .transform().simple(&quot;message-${header.CamelTimerCounter}&quot;)
                .recipientList().method(config, &quot;getRecipients&quot;);

        from(&quot;direct:async-queue&quot;)
                .id(&quot;async-queue&quot;)
                .log(&quot;${body} pushed to the async queue&quot;);

        from(&quot;direct:mail&quot;)
                .id(&quot;mail&quot;)
                .log(&quot;${body} sent via mail&quot;);

        from(&quot;direct:file&quot;)
                .id(&quot;file&quot;)
                .log(&quot;${body} written to a file&quot;);

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ll show here only the relevant parts, but you can just clone or fork my &lt;a href=&quot;https://github.com/nicolaferraro/spring-boot-configmap-quickstart&quot;&gt;spring-boot-configmap-quickstart&lt;/a&gt; repository and run it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git@github.com:nicolaferraro/spring-boot-configmap-quickstart.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The route generates every &lt;em&gt;3&lt;/em&gt; seconds a dummy message and pushes it to a list of recipents (this EIP is indeed called &quot;recipent list&quot;).
Here there are 3 available endpoints where the message can be pushed to: &lt;code&gt;direct:async-queue&lt;/code&gt;, &lt;code&gt;direct:mail&lt;/code&gt; and &lt;code&gt;direct:file&lt;/code&gt;.
They are fake endpoints for the purposes of this example, as they just log every message with a different surrounding text.&lt;/p&gt;
&lt;p&gt;The list of recipents is chosen using the &lt;code&gt;getRecipients&lt;/code&gt; method of an external bean. Here&apos;s the bean:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
@ConfigurationProperties(prefix = &quot;route&quot;)
public class RouteConfig {

    /**
     * The recipient endpoint.
     */
    private String recipients;

    public RouteConfig() {
    }

    public String getRecipients() {
        return recipients;
    }

    public void setRecipients(String recipients) {
        this.recipients = recipients;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;RouteConfig&lt;/code&gt; bean is a typical spring-boot configuration bean with a property of type &lt;code&gt;String&lt;/code&gt; named &lt;code&gt;recipients&lt;/code&gt;
that contains the list of target endpoints for every message.&lt;/p&gt;
&lt;p&gt;I&apos;ve included the configuration in a bean &lt;strong&gt;annotated with &lt;em&gt;@ConfigurationProperties&lt;/em&gt;&lt;/strong&gt; because all the beans with such annotation &lt;strong&gt;will be refreshed automatically&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The list of recipients is given as &lt;strong&gt;comma separated value string&lt;/strong&gt;, as shown in the &lt;code&gt;application.properties&lt;/code&gt; file below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Application data
spring.application.name=configmap-example

# Enable auto-reload
spring.cloud.kubernetes.reload.enabled=true

# Using an internal port for health checks. 
# Always a good choice to avoid exposing sensitive paths.
management.port=8000

# Camel recipients default configuration.
# Can be overridden using configmaps.
route.recipients=direct:async-queue,direct:mail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;spring.application.name&lt;/code&gt; property serves to give a name to the application: the name is &lt;code&gt;configmap-example&lt;/code&gt;.
The reason why this is important is because the application is automatically configured to override the default configuration if a Kubernetes config map named &lt;code&gt;configmap-example&lt;/code&gt; is present.
A simple flag named &lt;code&gt;spring.cloud.kubernetes.reload.enabled&lt;/code&gt; &lt;strong&gt;enables the auto-reload feature on configmap change&lt;/strong&gt;.
With this property enabled, the config map can be added at a later time and the application will refresh its status.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;route.recipients&lt;/code&gt; property is the one we want to override with a configmap. The default value includes two target endpoints for the messages: &lt;code&gt;direct:async-queue&lt;/code&gt; and &lt;code&gt;direct:mail&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Running the example in Kubernetes&lt;/h2&gt;
&lt;p&gt;You need a running Kubernetes or Openshift cluster to run the example. If you don&apos;t already have one, I suggest you using &lt;a href=&quot;https://github.com/kubernetes/minikube/releases&quot;&gt;Minikube&lt;/a&gt;
or &lt;a href=&quot;https://github.com/jimmidyson/minishift/releases&quot;&gt;Minishift&lt;/a&gt;, to startup a development Kubernetes or Openshift cluster in 2 minutes.&lt;/p&gt;
&lt;h3&gt;Note for Openshift:&lt;/h3&gt;
&lt;p&gt;If you&apos;re using Openshift (any kind of cluster, also Minishift), you need to give permissions to the running application to listen for changes in the project.
This can be obtained by &lt;strong&gt;giving the view permission&lt;/strong&gt; to the &lt;code&gt;default&lt;/code&gt; service account. It is the service account responsible to run all the pods by default.
Just login, switch to the project where you want to deploy the application and type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;oc policy add-role-to-user view --serviceaccount=default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command above applies to the service account named &lt;code&gt;default&lt;/code&gt; in the current project only.&lt;/p&gt;
&lt;p&gt;Now just execute the following Maven goal to run the quickstart:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn clean install fabric8:run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;fabric8:run&lt;/code&gt; goal will deploy the quickstart to your local Kubernetes/Openshift instance and attach the console to the logs of the created pod.
The output should be something like this (after the initialization):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[           main] m.nicolaferraro.quickstarts.Application  : Started Application in 5.902 seconds (JVM running for 9.15)
[ - timer://tick] async-queue                              : message-1 pushed to the async queue
[ - timer://tick] mail                                     : message-1 sent via mail
[ - timer://tick] async-queue                              : message-2 pushed to the async queue
[ - timer://tick] mail                                     : message-2 sent via mail
[ - timer://tick] async-queue                              : message-3 pushed to the async queue
[ - timer://tick] mail                                     : message-3 sent via mail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leave the application running. We are going to change the routes dynamically.&lt;/p&gt;
&lt;h2&gt;Changing the configuration&lt;/h2&gt;
&lt;p&gt;Currently an application named &lt;code&gt;configmap-example&lt;/code&gt; is running in our Kubernetes and it is listening for config maps with the same name in the current namespace.
Let&apos;s create a config map with that name to see what happens.&lt;/p&gt;
&lt;p&gt;Create a file named &lt;code&gt;configmap.yml&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kind: ConfigMap
apiVersion: v1
metadata:
  # Must match the &apos;spring.application.name&apos; property of the application
  name: configmap-example
data:
  application.properties: |
    # Override the configuration properties here
    route.recipients=direct:async-queue,direct:file,direct:mail

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you see, we are going to change the &lt;code&gt;route.recipients&lt;/code&gt; property to add the &lt;code&gt;direct:file&lt;/code&gt; recipient. The config map is named after the spring application.
To create it, &lt;strong&gt;open a new terminal&lt;/strong&gt; and type the following command if you&apos;re using Kubernetes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl create -f configmap.yml

# For Openshift
# oc create -f configmap.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The config map should be created without problems. Now look at the program running in the other terminal. You have triggered a configuration change.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ - timer://tick] async-queue                              : message-22 pushed to the async queue
[ - timer://tick] mail                                     : message-22 sent via mail
[ - timer://tick] async-queue                              : message-23 pushed to the async queue
[ - timer://tick] mail                                     : message-23 sent via mail
[default.svc/...] .r.EventBasedConfigurationChangeDetector : Detected change in config maps
[default.svc/...] .r.EventBasedConfigurationChangeDetector : Reloading using strategy: REFRESH
[default.svc/...] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@71cadf38: startup date [Sun Oct 23 08:44:57 UTC 2016]; root of context hierarchy
[default.svc/...] trationDelegate$BeanPostProcessorChecker : Bean &apos;configurationPropertiesRebinderAutoConfiguration&apos; of type [class org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$bf2575c9] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
[default.svc/...] b.c.PropertySourceBootstrapConfiguration : Located property source: ConfigMapPropertySource [name=&apos;configmap.configmap-example.bbb&apos;]
[default.svc/...] b.c.PropertySourceBootstrapConfiguration : Located property source: SecretsPropertySource [name=&apos;secrets.configmap-example.bbb&apos;]
[default.svc/...] o.s.boot.SpringApplication               : The following profiles are active: kubernetes
[default.svc/...] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@18d995cf: startup date [Sun Oct 23 08:44:57 UTC 2016]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@71cadf38
[default.svc/...] o.s.boot.SpringApplication               : Started application in 0.469 seconds (JVM running for 92.617)
[default.svc/...] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@18d995cf: startup date [Sun Oct 23 08:44:57 UTC 2016]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@71cadf38
[ - timer://tick] async-queue                              : message-24 pushed to the async queue
[ - timer://tick] file                                     : message-24 written to a file
[ - timer://tick] mail                                     : message-24 sent via mail
[ - timer://tick] async-queue                              : message-25 pushed to the async queue
[ - timer://tick] file                                     : message-25 written to a file
[ - timer://tick] mail                                     : message-25 sent via mail

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now each message is also pushed to the &lt;code&gt;direct:file&lt;/code&gt; endpoint, as required by the config map. And the change happens &lt;strong&gt;on the fly&lt;/strong&gt; as soon as you create the config map and without any downtime.&lt;/p&gt;
&lt;p&gt;You can also change again the config map from the Openshift console or the command line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl edit configmap configmap-example

# For Openshift
# oc edit configmap configmap-example
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;vi-like editing screen&lt;/strong&gt; will appear and let you change the contents.&lt;/p&gt;
&lt;h2&gt;In a real scenario&lt;/h2&gt;
&lt;p&gt;A common use case for this feature is creating a &lt;em&gt;per-environment&lt;/em&gt; configuration, allowing you to use eg. different settings in the &lt;code&gt;testing&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; environments.
Plus, the feature allows you to change the configuration at runtime.&lt;/p&gt;
&lt;p&gt;It&apos;s unlikely that you want to change the configuration of an application using &lt;code&gt;vi&lt;/code&gt; in production (altough I&apos;ve done that multiple times in the past XD).&lt;/p&gt;
&lt;p&gt;Configuration management need a special care. For example, one might want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Track all the changes done to the configuration to be able to revert them;&lt;/li&gt;
&lt;li&gt;Track the users that changed the configuration;&lt;/li&gt;
&lt;li&gt;Authorize only certain users to change the configuration;&lt;/li&gt;
&lt;li&gt;Peer review all the changes to avoid mistakes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can obtain this level of control by including the configmap in a &lt;strong&gt;git repository&lt;/strong&gt;. There can be a single repository for all the configmaps, or one per configmap, you decide.&lt;/p&gt;
&lt;p&gt;For the current example, I&apos;ve provided an example of git repository with a config map ready to be deployed by the &lt;em&gt;Fabric8 Maven Plugin&lt;/em&gt;.
Instead of creating the config map file by yourself, you can just have cloned my repo and installed it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git@github.com:nicolaferraro/spring-boot-configmap-settings.git
cd spring-boot-configmap-settings
mvn clean install fabric8:deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this is not what you&apos;re going to do in production. You should instruct Jenkins to deploy the config map to your Kubernetes as soon as it changes.
There are multiple ways to do so. &lt;a href=&quot;https://fabric8.io/gitbook/&quot;&gt;Fabric8&lt;/a&gt; has a fully featured Jenkins pipeline system that can be configured to accomplish this task with 2 clicks.
Openshift Enterprise 3.3 is also able to use &lt;a href=&quot;https://blog.openshift.com/whats-new-openshift-3-3-developer-experience/&quot;&gt;Jenkins pipelines&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Settings and limitations&lt;/h2&gt;
&lt;p&gt;The reload feature can also be configured to completely &lt;em&gt;restart&lt;/em&gt; the application context for the cases where a &lt;em&gt;refresh&lt;/em&gt; is not enough.
It can also shutdown completely the pod to let the replication controller restart a new one (for the extreme cases).
Check the &lt;a href=&quot;https://github.com/fabric8io/spring-cloud-kubernetes#propertysource-reload&quot;&gt;documentation&lt;/a&gt; for the other available options.&lt;/p&gt;
&lt;p&gt;When using the &lt;em&gt;refresh&lt;/em&gt; mode, you should ensure no properties are deleted between two subsequent versions of a config map. Properties can be added, changed but not removed.
&lt;a href=&quot;https://github.com/spring-cloud/spring-cloud-config/issues/421&quot;&gt;This issue&lt;/a&gt; is related to the &lt;em&gt;refresh&lt;/em&gt; mechanism of Spring Cloud and prevents you from using lists in configuration (elements cannot be removed from a list).
If you want to use lists or to be able to remove properties, you need to change the reload level in the &lt;code&gt;application.properties&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spring.cloud.kubernetes.reload.strategy=restart_context
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This option causes a short downtime because the application context is restarted whenever the config map changes, but it&apos;s still better than restarting the JVM.&lt;/p&gt;
&lt;p&gt;The feature can be also used with &lt;strong&gt;Kubernetes secrets&lt;/strong&gt;. Take a look at &lt;a href=&quot;https://github.com/fabric8io/spring-cloud-kubernetes&quot;&gt;spring-cloud-kubernetes on Github&lt;/a&gt;.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Extending DevOps to Big Data Applications with Kubernetes</title><link>https://www.nicolaferraro.me/posts/voxxed-bucharest-extending-devops-to-big-data-applications-with-kubernetes</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/voxxed-bucharest-extending-devops-to-big-data-applications-with-kubernetes</guid><pubDate>Fri, 10 Mar 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve talked at &lt;strong&gt;Voxxed Days Buchares 2017&lt;/strong&gt; about how to apply some DevOps practices to Big Data applications by leveraging the power of Kubernetes and Openshift.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;DevOps, continuous delivery and modern architectural trends can incredibly speed up the software development process. Big Data applications cannot be an exception and need to keep the same pace. In this talk, Nicola Ferraro (Red Hat) will show an overview of the next generation cloud-native Big Data systems based on Docker and Kubernetes. Switching from static Big Data platforms to infrastructure as code allows releasing robust applications in minutes by minimizing the gap between all the environments (development, testing, staging and production), a typical problem in Big Data application development. The presentation goes through the full release cycle of a Spark application alongside a fleet of microservices exchanging data in near real time. A fully featured continuous delivery pipeline, provided by the Fabric8 platform, will automate every step of the build and release process. Spark clusters will come to life from nowhere and disappear when they are no longer needed...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The slides are available here:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/a0EJps7bci1Xgw&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;And here&apos;s the recording:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/tPsydjaPs0U&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Cloud Native Applications on Kubernetes: a DevOps Approach</title><link>https://www.nicolaferraro.me/posts/voxxed-ticino-cloud-native-applications-on-kubernetes-a-devops-approach</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/voxxed-ticino-cloud-native-applications-on-kubernetes-a-devops-approach</guid><pubDate>Sat, 06 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve talked at &lt;strong&gt;Voxxed Days Ticino 2017&lt;/strong&gt; about building Cloud Native applications on Kubernetes and Openshift.&lt;/p&gt;
&lt;p&gt;The slides are available here:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/kJYs2wzJRRAQZp&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;slides are in English&lt;/strong&gt;, but the talk&apos;s &lt;strong&gt;abstract is in Italian&lt;/strong&gt; (that is also the language used in the talk).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Kubernetes è la piattaforma open source per l’orchestrazione di container Docker, nata dall’esperienza Google, che sta diventando lo standard “de facto” per applicazioni cloud native. Lo sviluppo di applicazioni su Kubernetes offre dei vantaggi notevoli, poiché è la stessa piattaforma ad occuparsi di aspetti cruciali della vita del software: deployment, service discovery, load balancing, self-healing, auto-scaling, rolling upgrades e molto altro.&lt;/p&gt;
&lt;p&gt;Kubernetes, inoltre, è in grado di fornire questi servizi a qualsiasi tipo di applicazione: dal front-end web Node.js alle applicazioni Big Data sviluppate con Apache Spark!&lt;/p&gt;
&lt;p&gt;In questo talk vedrete gli aspetti più importanti dell’architettura di Kubernetes e le principali risorse che la piattaforma mette a disposizione. Vi saranno mostrati alcuni metodi pratici per sviluppare e distribuire applicazioni su Kubernetes e Openshift Origin (“Kubernetes on steroids” di Red Hat). Attraverso gli strumenti di sviluppo del progetto Fabric8, vedrete inoltre come sia possibile applicare delle pratiche DevOps, quali continuous integration e continuous delivery, per creare applicazioni cloud sempre più robuste e automatizzarne il processo di rilascio.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here&apos;s the recording (Italian):&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/dqgFDduVS9Q&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Integrating Applications: The Reactive Way</title><link>https://www.nicolaferraro.me/posts/jbcnconf-barcelona-integrating-applications-the-reactive-way</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/jbcnconf-barcelona-integrating-applications-the-reactive-way</guid><pubDate>Tue, 20 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It has been a pleasure to give a talk at JBCNConf, one of the biggest conferences about Java in Europe.&lt;/p&gt;
&lt;p&gt;I&apos;ve presented the work that we&apos;ve been doing recently on reactive streams in Apache Camel, with a fancy introduction on the reactor
pattern and a lot of reasoning on end-to-end backpressure.&lt;/p&gt;
&lt;p&gt;I&apos;ve been really happy to see my name in the &lt;strong&gt;&quot;top 10&quot; of speakers&lt;/strong&gt; at the end of the conference.
I feel that people liked the way I presented things, but this is also a confirmation that the
reactive topic is hot and Camel is going in the right direction.&lt;/p&gt;
&lt;p&gt;The slides are available here:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/tLfgLN4po23zAa&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;And here&apos;s the recording:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/1JtdUhLf5pE&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Creating Clustered Singleton Services on Kubernetes</title><link>https://www.nicolaferraro.me/posts/creating-clustered-singleton-services-on-kubernetes</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/creating-clustered-singleton-services-on-kubernetes</guid><pubDate>Tue, 17 Oct 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Creating a cluster of related containers is really easy with Openshift and Kubernetes.
Resources such as &lt;em&gt;Deployment&lt;/em&gt; support scaling to multiple instances natively. Services and load balancers are provided for free.
But any time you create a cluster of containers, as soon as your application becomes more complex than a &quot;Hello World!&quot;,
there&apos;s a question that often arises: &quot;How can I run a single instance of a component in the whole cluster?&quot;&lt;/p&gt;
&lt;h2&gt;Why do you need a singleton service?&lt;/h2&gt;
&lt;p&gt;Think to a common scenario where you have an application running on Openshift with &lt;code&gt;n&lt;/code&gt; replicas. It&apos;s not difficult to imagine cases where you need a singleton service.&lt;/p&gt;
&lt;h3&gt;Scenario 1&lt;/h3&gt;
&lt;p&gt;Suppose that you want to do &lt;strong&gt;scheduled operations on a database&lt;/strong&gt;. For sure, you don&apos;t want all the pods of the same application do the same batch operation together.&lt;/p&gt;
&lt;p&gt;For this task there are Kubernetes &lt;code&gt;CronJob&lt;/code&gt; resources, but if you don&apos;t want to &lt;em&gt;start a different pod for every task you create&lt;/em&gt;, they are not the perfect solution.
Think to the case where you need to schedule 10 different jobs. &lt;code&gt;CronJob&lt;/code&gt; resources require some additional effort from a management point of view that you may not want to spend.&lt;/p&gt;
&lt;p&gt;There are also many cases where you need to access your core business resources in the job, so if you package the scheduled operation into a external resource, you then need
a way to call your business logic from outside.&lt;/p&gt;
&lt;p&gt;Separating your application into multiple services is a core principle of the microservices architecture, but
you should &lt;em&gt;split your business logic according to domain rules, not technical reasons&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;You may want to schedule tasks in your application. E.g. in spring-boot you can use the &lt;code&gt;@Scheduled&lt;/code&gt; annotation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Component
public class ScheduledTasks {

    @Scheduled(fixedRate = 5000)
    public void doTask() {
        // do something
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if you do this, each running pod will call it&apos;s &lt;code&gt;doTask&lt;/code&gt; method. And you don&apos;t want this.&lt;/p&gt;
&lt;h3&gt;Scenario 2&lt;/h3&gt;
&lt;p&gt;Suppose that you need to &lt;strong&gt;poll data from a remote REST API&lt;/strong&gt; and process them. But you &lt;strong&gt;cannot do it concurrently&lt;/strong&gt;, because the API supports a &lt;strong&gt;single consumer&lt;/strong&gt;.
For example, &lt;a href=&quot;https://core.telegram.org/bots/api&quot;&gt;Telegram&lt;/a&gt; (the popular messaging app) has a polling api that does not support multiple consumers on the same chat id.&lt;/p&gt;
&lt;p&gt;The first solution you may think about is running another pod on a deployment with &lt;code&gt;replicas=1&lt;/code&gt;. It will consume data from Telegram and push messages to a queue/topic.&lt;/p&gt;
&lt;p&gt;But is &lt;code&gt;replicas=1&lt;/code&gt; &lt;strong&gt;equivalent to singleton&lt;/strong&gt; in the Kubernetes world? &lt;strong&gt;NO!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kubernetes will try to reach the goal of always having a single instance of your application, but &lt;em&gt;that is a target, not an invariant&lt;/em&gt;.
There are tons of situations where you can have multiple instances of your application, even if you asked for a single one.
For example, in case of network partition between a node that run your pod and the Kubernetes API server, Kubernetes
can decide (after a timeout) that the node is no more ready and reschedule the pod on another node: the result is 2 pods running concurrently,
even if you asked for one.&lt;/p&gt;
&lt;p&gt;These situations are common in case of failure of some pieces of the infrastructure. If having a &lt;strong&gt;singleton&lt;/strong&gt; instance of a service is a requirement, you cannot rely on the &lt;code&gt;replicas=1&lt;/code&gt; setting.&lt;/p&gt;
&lt;p&gt;You now may think that &lt;code&gt;StatefulSets&lt;/code&gt; solve the situation, but (&lt;strong&gt;first&lt;/strong&gt;) you end up running a stateless application on a stateful container model,
with its limitations (e.g. missing rolling upgrades, limited auto-scalability, limited...).
And (&lt;strong&gt;second&lt;/strong&gt;) you cannot scale out the &lt;code&gt;StatefulSet&lt;/code&gt; to multiple replicas, e.g. in order to speedup parts of your application while keeping only the REST-polling part singleton.&lt;/p&gt;
&lt;h3&gt;Scenario 3&lt;/h3&gt;
&lt;p&gt;Suppose that you want to expose &lt;strong&gt;multiple istances&lt;/strong&gt; of your REST services, but you want that &lt;strong&gt;certain operations are executed in serial order by a single piece of code&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Setting &lt;code&gt;replicas=1&lt;/code&gt; does not solve the problem, as you&apos;ve seen in scenario 2. So, how will you do?&lt;/p&gt;
&lt;p&gt;You can use a &lt;strong&gt;clustered singleton&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now use your imagination. There are a lot of other cases...&lt;/p&gt;
&lt;h2&gt;How can you create it?&lt;/h2&gt;
&lt;p&gt;Camel 2.20 has been released few days ago. If you have time, you can take a look at the &lt;a href=&quot;https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12337871&amp;amp;projectId=12311211&quot;&gt;huge list of release notes&lt;/a&gt;.
Or, for something more human friendly, there&apos;s &lt;a href=&quot;http://www.davsclaus.com/2017/10/apache-camel-220-released-whats-new.html&quot;&gt;this post by Claus Ibsen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the improvement introduced in Camel 2.20 is the new &lt;strong&gt;Camel Cluster Service&lt;/strong&gt; (thanks to &lt;a href=&quot;https://lburgazzoli.github.io/&quot;&gt;Luca Burgazzoli&lt;/a&gt;). We designed some general purpose interfaces that can be
used to &lt;strong&gt;receive simple notifications when your specific instance of a service becomes the leader/master of the whole cluster&lt;/strong&gt;.
The cluster here is an abstract term: you define it. But often in Kubernetes/Openshift, a cluster is made by all the pods that compose the same deployment.&lt;/p&gt;
&lt;p&gt;Camel supports multiple cluster services: atomix, consul, file, &lt;strong&gt;kubernetes&lt;/strong&gt; and zookeeper (and also jgroups, added at the last minute by Andrea Tarocci). The kubernetes cluster service is just one of them and we&apos;ll use it to create a clustered singleton easily.&lt;/p&gt;
&lt;h2&gt;I&apos;ve seen this before...&lt;/h2&gt;
&lt;p&gt;In case you were asking: this is the successor of the &lt;strong&gt;Camel Master Route&lt;/strong&gt; concept available in JBoss Fuse.
We&apos;ll see a &lt;em&gt;new&lt;/em&gt; Camel master route shortly. But the new service is much more powerful than the classic master component.&lt;/p&gt;
&lt;p&gt;Yes, it will be available in next version of Fuse (Fuse 7.0, most probably).&lt;/p&gt;
&lt;p&gt;And yes: the &lt;em&gt;initial&lt;/em&gt; code for the Kubernetes leader election has been &lt;a href=&quot;https://github.com/fabric8io/fabric8-ipaas/tree/master/camel-master&quot;&gt;donated to Apache Camel by the Fabric8 team from the camel-master project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And the original idea &lt;a href=&quot;https://github.com/kubernetes/kubernetes/blob/8c120dcf2f8c97da8143d36f26746c4f4685b828/staging/src/k8s.io/client-go/tools/leaderelection/leaderelection.go&quot;&gt;comes from the Kubernetes code&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Ok, now show me the code!&lt;/h2&gt;
&lt;p&gt;The complete code is present on my Github repo &lt;a href=&quot;https://github.com/nicolaferraro/camel-leader-election&quot;&gt;nicolaferraro/camel-leader-election&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You need just 3 dependencies in the pom.xml file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-starter&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;camel-master-starter&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.camel&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;camel-kubernetes-starter&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are running Camel on spring-boot and we also need the &lt;code&gt;camel-master-starter&lt;/code&gt; to run &lt;strong&gt;Camel master routes&lt;/strong&gt; and also &lt;code&gt;camel-kubernetes-starter&lt;/code&gt; to tell Camel that
we want to use the Kubernetes cluster service (that obviously works also on Openshift).&lt;/p&gt;
&lt;p&gt;A bit of configuration is necessary. Here&apos;s the &lt;code&gt;application.properties&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ...
camel.component.kubernetes.cluster.service.enabled=true

camel.component.kubernetes.cluster.service.cluster-labels[group]=${project.groupId}
camel.component.kubernetes.cluster.service.cluster-labels[app]=${project.artifactId}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; remember to &lt;a href=&quot;https://github.com/nicolaferraro/camel-leader-election/blob/35d789b176d1c15942f99112652a93e4f4662850/pom.xml#L57-L62&quot;&gt;enable resource filtering&lt;/a&gt; in the &lt;code&gt;pom.xml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first line enables the Kubernetes cluster service. The other lines tell the cluster service that the cluster is composed
of all pods having a Pod Label named &lt;code&gt;group&lt;/code&gt; equals to the current Maven project &lt;code&gt;groupId&lt;/code&gt; and a label named &lt;code&gt;app&lt;/code&gt; equals to the Maven &lt;code&gt;artifactId&lt;/code&gt;.
This is the &lt;strong&gt;default mapping used by the Fabric8 Maven Plugin when creating Kubernetes/Openshift resources&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now you can just write a Camel master route:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&quot;master:lock1:timer:clock&quot;)
  .log(&quot;Hello World!&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this is a simple Camel route prefixed with &lt;code&gt;master:lock1&lt;/code&gt;. Here &lt;code&gt;lock1&lt;/code&gt; is the lock name used for synchronization among all pods:
only the pod that is able to get the lock on &lt;code&gt;lock1&lt;/code&gt; will start the route (implementation details later).&lt;/p&gt;
&lt;p&gt;Singleton services are not limited to Camel routes: &lt;strong&gt;you can also create a generic singleton service!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, you can declare a service like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class CustomService {

    public void start() {
        // called on the leader pod to *start* the service
    }

    public void stop() {
        // called on the leader pod to *stop* the service
    }

    // ...
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can bind the service to the global &lt;code&gt;CamelClusterService&lt;/code&gt; instance on your application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
class BeanConfiguration {

    @Bean
    public CustomService customService(CamelClusterService clusterService) throws Exception {
        CustomService service = new CustomService();

        clusterService.getView(&quot;lock2&quot;).addEventListener((CamelClusterEventListener.Leadership) (view, leader) -&amp;gt; {
            // here we get a notification of a change in the leadership
            boolean weAreLeaders = leader.isPresent() &amp;amp;&amp;amp; leader.get().isLocal();
            
            if (weAreLeaders &amp;amp;&amp;amp; !service.isStarted()) {
                service.start();
            } else if (!weAreLeaders &amp;amp;&amp;amp; service.isStarted()) {
                service.stop();
            }
        });
        return service;
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;And that&apos;s all. The service will start only on one pod at time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note for Openshift users&lt;/strong&gt;: the lock mechanism assumes that you&apos;re able to modify Kubernetes resources from whithin your pod. This is normally forbidden, unless you give special permissions to the pod.
The quickstart is already configured with a special &lt;code&gt;ServiceAccount&lt;/code&gt; and &lt;code&gt;RoleBinding&lt;/code&gt; (see &lt;a href=&quot;https://github.com/nicolaferraro/camel-leader-election/tree/master/src/main/fabric8&quot;&gt;the fragments here&lt;/a&gt;),
so you don&apos;t need to add them manually.&lt;/p&gt;
&lt;h2&gt;Running the quickstart&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Connect to a Openshift instance. You can use &lt;a href=&quot;https://github.com/minishift/minishift/releases&quot;&gt;Minishift&lt;/a&gt; for local development.&lt;/li&gt;
&lt;li&gt;Clone the repo:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;git clone git@github.com:nicolaferraro/camel-leader-election.git
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Deploy:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# Enter the project dir
cd camel-leader-election
mvn fabric8:deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The deployment is already configured to run 3 istances of the application pod. If you enter the log (run &lt;code&gt;minishift console&lt;/code&gt; to se the logs in the UI),
you&apos;ll see that &quot;Hello World!&quot; is printed continuously in &lt;strong&gt;only one pod&lt;/strong&gt;.
&lt;strong&gt;If you kill that pod, after some seconds, another pod will start to print &quot;Hello World!&quot;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Where&apos;s the magic (implementation details)?&lt;/h2&gt;
&lt;p&gt;Leader Election is a special kind of consensus in distributed systems and you know that consensus is hard to achieve.
Fortunately Openshift and Kubernetes run a instance of Etcd and &lt;a href=&quot;https://aphyr.com/posts/316-call-me-maybe-etcd-and-consul&quot;&gt;Etcd implements Raft and takes consistency very seriously&lt;/a&gt;.
So the idea: &lt;strong&gt;why don&apos;t we use Etcd to do leader election?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not so easy&lt;/strong&gt;. We cannot use Etcd directly inside Kubernetes, it&apos;s not there for application purposes. But we can use Kubernetes API to create/change
resources such as &lt;code&gt;ConfigMaps&lt;/code&gt;... and &lt;code&gt;ConfigMaps&lt;/code&gt; are stored in Etcd...&lt;/p&gt;
&lt;p&gt;There&apos;s a kind of &lt;strong&gt;optimistic locking&lt;/strong&gt; mechanism in Kubernetes resources. Every resource has a &lt;code&gt;metadata.resourceVersion&lt;/code&gt; field that can be used to ensure that only one pod
changes a &lt;code&gt;ConfigMap&lt;/code&gt; at time. If two pods try to change the same ConfigMap, only one of them can complete the operation correctly.&lt;/p&gt;
&lt;h3&gt;So, how can we leverage this feature?&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;camel-kubernetes&lt;/code&gt; cluster service creates a &lt;code&gt;ConfigMap&lt;/code&gt; named &lt;code&gt;leaders&lt;/code&gt; (by default) and stores inside it the &lt;strong&gt;pod name of the current owner of each lock declared in the application&lt;/strong&gt; (we used &lt;code&gt;lock1&lt;/code&gt; for the master route and &lt;code&gt;lock2&lt;/code&gt; for the custom service).&lt;/p&gt;
&lt;p&gt;The protocol is (approximately) this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every pod tries continuously to acquire the lock&lt;/li&gt;
&lt;li&gt;A pod can acquire the lock if the lock has not been created yet, or the current owner is not in the set of pods alive in the cluster (filtered with the labels we&apos;ve set above)&lt;/li&gt;
&lt;li&gt;When a pod acquires the lock, it must wait for &lt;code&gt;x&lt;/code&gt; seconds before starting the clustered services&lt;/li&gt;
&lt;li&gt;The pod that owns a specific lock must continuously check if he&apos;s still the owner of the lock&lt;/li&gt;
&lt;li&gt;When a pod loses the lock because another pod acquired it, it must shutdown the clustered services immediately&lt;/li&gt;
&lt;li&gt;When a pod cannot check if it&apos;s still the owner of a lock (because of a network partition or any other error), it must shutdown the clustered services after a timeout &lt;code&gt;y &amp;lt; x&lt;/code&gt; from last successful check&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The protocol outlined above ensures that &lt;strong&gt;only one master is present in the cluster at time&lt;/strong&gt;.
&lt;strong&gt;Even in case of network partition&lt;/strong&gt; (e.g. a physical node is completely isolated from the rest of the cluster) of a Kubernetes node that was hosting the leader, &lt;strong&gt;the application will shut down the clustered services before a
new election&lt;/strong&gt; can take effect.&lt;/p&gt;
&lt;p&gt;For more details, &lt;a href=&quot;https://github.com/apache/camel/tree/master/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/ha&quot;&gt;look at the code!&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>The Saga Pattern in Apache Camel</title><link>https://www.nicolaferraro.me/posts/saga-pattern-in-apache-camel</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/saga-pattern-in-apache-camel</guid><pubDate>Wed, 25 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A new enterprise integration pattern has been added to Apache Camel (2.21.0): the &quot;Saga&quot; pattern. This article will show you why, when and how to use it
in order to build robust and consistent applications in the cloud.&lt;/p&gt;
&lt;h2&gt;What is a Saga?&lt;/h2&gt;
&lt;p&gt;Although the name &quot;Saga&quot; has been widely misused recently, especially in the field of front-end development,
in the context of distributed systems the term &quot;Saga&quot; always refers to a &lt;em&gt;pattern for coordinating
actions in remote services in order to obtain a consistent outcome&lt;/em&gt;. Achieving consistency is something
really useful in practice but also difficult, especially in microservice architectures that tend to split the processing
logic into multiple autonomous services, usually communicating over HTTP.&lt;/p&gt;
&lt;h2&gt;What do you mean by &quot;Consistency&quot;?&lt;/h2&gt;
&lt;p&gt;There&apos;s not a unique definition of the term &quot;consistency&quot;, but here I refer to the widely accepted notion of
&lt;em&gt;&quot;keeping the system as a whole in a valid state&quot;&lt;/em&gt; (and by &lt;em&gt;&quot;valid&quot;&lt;/em&gt; I mean: &lt;em&gt;&quot;respecting all business invariants&quot;&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Let&apos;s try to make it more concrete with an &lt;em&gt;example&lt;/em&gt;. Suppose you have designed a system for a travel agency
that allows you to buy a &lt;em&gt;trip from A to B&lt;/em&gt;, using two external (or internal) services to buy tickets for
&lt;em&gt;train&lt;/em&gt; (service 1) or &lt;em&gt;plane&lt;/em&gt; (service 2).&lt;/p&gt;
&lt;p&gt;From a business perspective, your main invariant here is simply stated:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For any trip from A to B, the agency should buy tickets for all sub-routes (train or flight) that take the customer from A to B, or none of them&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It means, in simple words, that when a user asks to go from London to Florence, the agency should buy a flight from London to Rome and a train from Rome to Florence.
But it should never buy a train from Rome to Florence if the flight from London to Rome is full (or too expensive).
We should buy the full trip or tell the user that the trip cannot be reserved.&lt;/p&gt;
&lt;p&gt;But the problem is that we have &lt;strong&gt;two distinct systems&lt;/strong&gt; for buying train tickets and reserving flights. How do we &lt;strong&gt;coordinate&lt;/strong&gt; them?&lt;/p&gt;
&lt;p&gt;Now, use your imagination, this is a &lt;strong&gt;very common problem&lt;/strong&gt; and happens in many contexts!&lt;/p&gt;
&lt;h2&gt;How did people use to solve this problem? (Transactions)&lt;/h2&gt;
&lt;p&gt;This is a classic problem in distributed systems and the traditional way to solve it is... with &lt;em&gt;transactions&lt;/em&gt;, of course!&lt;/p&gt;
&lt;p&gt;I&apos;ve been a consultant for many years and I can tell you that the most common architecture used by people is the big monolith
with a gigantic relational database where multiple application modules store data (and sometimes also communicate by writing and reading data from the DB).&lt;/p&gt;
&lt;p&gt;So if that is your architecture, the problem is simply solved by wrapping the calls to the &lt;em&gt;flight module&lt;/em&gt; and the &lt;em&gt;train module&lt;/em&gt; inside a transaction,
so that if one of the two calls fails, &lt;em&gt;the whole transaction is rolled back and your system preserves the invariant&lt;/em&gt; (transactions are indeed ACID, where the C means &quot;consistency&quot;).&lt;/p&gt;
&lt;p&gt;And what if the system is distributed? Well, there are &lt;em&gt;distributed transactions&lt;/em&gt;. One of the most widely used specification
for distributed transaction is &lt;em&gt;XA&lt;/em&gt; and it allows applications and resources to execute actions in the context of a
globally defined transaction that preserve the ACID properties. So you can have a ACID transaction that can span multiple databases or even
multiple distributed services (the transactional context can be propagated across services).&lt;/p&gt;
&lt;h2&gt;So, why don&apos;t we just use distributed transactions?&lt;/h2&gt;
&lt;p&gt;There are many drawbacks to using distributed transactions.&lt;/p&gt;
&lt;p&gt;The most evident one is that protocols and specifications for propagating a transaction context between two remote
services are missing or under-developed when we want to connect services developed using different languages. Java is probably the language that has the best support for local and distributed transactions,
but many &lt;strong&gt;other languages completely lack support for the most basic features&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But also in Java, if you use a &lt;strong&gt;NoSQL&lt;/strong&gt; database instead of a good old RDBMS, chances that you can use (ACID) transactions are pretty low.&lt;/p&gt;
&lt;p&gt;And what if you want to use an &lt;strong&gt;asynchronous toolkit&lt;/strong&gt; like Rx-Java on Vert.x or Project Reactor on Spring-Boot 2? Now &lt;strong&gt;chances&lt;/strong&gt; that you can use
transactions are &lt;strong&gt;close to zero&lt;/strong&gt; (although there&apos;s some work going on...).&lt;/p&gt;
&lt;p&gt;But there are other reasons why one would avoid using distributed transactions in the context of microservice architectures or distributed systems in general.
One reason is that a transaction often causes locks to be created on resources and when you have something unreliable between parts of your system, like the network,
it may be the case that the locks are kept for a time longer than expected, creating also issues to other parts of the application.&lt;/p&gt;
&lt;p&gt;This problem becomes more important when the two services that want to participate in a transaction belong to two &lt;em&gt;distinct organizations&lt;/em&gt;.
If you &lt;strong&gt;ask an architect&lt;/strong&gt; to connect two services in a way that a &lt;strong&gt;problem in one service may also propagate to the other&lt;/strong&gt;, that architect would probably think
twice before doing such choice (or better three times). And distributed transactions are a kind of &lt;strong&gt;heavyweight link&lt;/strong&gt; between services that one would like to avoid.
A service running slowly increases the duration of global transactions also in the other services.
A failure of one service may leave locks in the database of another service for too long.&lt;/p&gt;
&lt;p&gt;In summary, if you want to use distributed transactions, you also need to &lt;strong&gt;trust the other side..&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/post-saga-transactions-meme.jpg&quot; alt=&quot;Transactions may have unexpected consequences&quot;/&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;That&apos;s probably the main reason why people prefer to keep the boundaries of distributed transactions very narrow (and make use of distributed transactions only when necessary).&lt;/p&gt;
&lt;h2&gt;And now we have Sagas&lt;/h2&gt;
&lt;p&gt;You may have heard of sagas in a talk about domain-driven design (DDD) or event-sourcing. In fact sagas are a central part of both approaches.
But a saga is not necessarily linked to that context, it&apos;s a generic pattern that can be used to coordinate remote services.&lt;/p&gt;
&lt;p&gt;In fact, since version 2.21.0 of Apache Camel, it has become a &lt;strong&gt;enterprise integration pattern (EIP)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A Saga can be defined as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A series of actions that belong to a business activity that should be all executed correctly by (remote) participants or otherwise compensated&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sagas fit more naturally into the way the natural world works (at least, our understanding of it).
Let&apos;s take the previous example of the travel agency and suppose a user wants to reserve a trip that includes buying a
train ticket and a flight.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A system developed with &lt;strong&gt;transactions&lt;/strong&gt; would try to &lt;strong&gt;reserve both&lt;/strong&gt; the flight and the train ticket &lt;strong&gt;at the same time&lt;/strong&gt;. If
it doesn&apos;t succeed, none of them will be booked.&lt;/li&gt;
&lt;li&gt;A system using the &lt;strong&gt;saga pattern&lt;/strong&gt; will try to &lt;strong&gt;reserve the train and the flight independently. In case of failure&lt;/strong&gt; in one of the
two reservations, &lt;strong&gt;the other one will be canceled&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this reason, a &lt;strong&gt;saga does exactly what a human would do&lt;/strong&gt; in this scenario: check if the full trip can be reserved,
try to book, then cancel in the event of issues.&lt;/p&gt;
&lt;p&gt;On the other side:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is no such thing as a transaction in the real world&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, ask Walter White if you don&apos;t believe me...&lt;/p&gt;
&lt;h2&gt;Sagas in Apache Camel&lt;/h2&gt;
&lt;p&gt;Designing a saga is fairly easy in Apache Camel. Let&apos;s see an example.&lt;/p&gt;
&lt;p&gt;I&apos;ve designed a sample quickstart system with the following (microservice) architecture.&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/saga-quickstart-system.png&quot; alt=&quot;Saga Quickstart System&quot;/&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;The full example is available here: &lt;a href=&quot;https://github.com/nicolaferraro/camel-saga-quickstart&quot;&gt;https://github.com/nicolaferraro/camel-saga-quickstart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can see the following services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;: a sample camel app that is the main entry point (and will continuously start sagas simulating real users)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flight Service&lt;/strong&gt;: a service that sells flights&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Train Service&lt;/strong&gt;: a service that sells train tickets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Payment Service&lt;/strong&gt;: a service that allows both services to request payments&lt;/li&gt;
&lt;li&gt;The big &lt;strong&gt;&quot;C&quot;&lt;/strong&gt; in the middle is a &lt;strong&gt;LRA Coordinator&lt;/strong&gt; (see below!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The basic workflow is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The saga starts&lt;/li&gt;
&lt;li&gt;The gateway will reserve a flight (include payment)&lt;/li&gt;
&lt;li&gt;The gateway will buy a train ticket (include payment)&lt;/li&gt;
&lt;li&gt;Saga is completed (or compensated in case of issues)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But since &lt;strong&gt;I am evil&lt;/strong&gt;, I&apos;ve made the &lt;strong&gt;payment service to fail with 15% probability&lt;/strong&gt;.
This means that e.g. if the payment service fails during the flight reservation process, we should cancel the reservation.
But in any case (succeeded or not), we should also cancel the train reservation if it has happened in the meantime.&lt;/p&gt;
&lt;p&gt;It sounds complex to maintain all services (train, flight and payment) in a consistent state, but I&apos;ll show you it&apos;s &lt;strong&gt;fairly easy with the Saga EIP in Apache Camel&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;So, show me the code!&lt;/h2&gt;
&lt;h3&gt;Camel API gateway&lt;/h3&gt;
&lt;p&gt;Writing the main gateway route is straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&quot;timer:clock?period=5s&quot;) // &amp;lt;-- replace it with rest() definition to create a real gateway
  .saga() // &amp;lt;-- start a new saga
    .setHeader(&quot;id&quot;, header(Exchange.TIMER_COUNTER))
    .setHeader(Exchange.HTTP_METHOD, constant(&quot;POST&quot;))
    .log(&quot;Executing saga #${header.id}&quot;)
    .to(&quot;http4://camel-saga-train-service:8080/api/train/buy/seat&quot;) // &amp;lt;-- action 1
    .to(&quot;http4://camel-saga-flight-service:8080/api/flight/buy&quot;); // &amp;lt;-- action 2

// you can also .multicast() the two calls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this completes the saga definition.&lt;/p&gt;
&lt;p&gt;Ok, we need also to write the services, but writing them is also easy.&lt;/p&gt;
&lt;h3&gt;Camel Saga-aware Service&lt;/h3&gt;
&lt;p&gt;Let&apos;s take the train service as an example. A Camel saga-aware service can be implemented like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rest().post(&quot;/train/buy/seat&quot;)
    .param().type(RestParamType.header).name(&quot;id&quot;).required(true).endParam() // &amp;lt;- from caller
    .route()
    .saga() // &amp;lt;-- join the saga with &quot;supports&quot; propagation
        .propagation(SagaPropagation.SUPPORTS)
        .option(&quot;id&quot;, header(&quot;id&quot;))
        .compensation(&quot;direct:cancelPurchase&quot;) // &amp;lt;-- the compensation endpoint
    .log(&quot;Buying train seat #${header.id}&quot;)
    .to(&quot;http4://camel-saga-payment-service:8080/api/pay?bridgeEndpoint=true&amp;amp;type=train&quot;) // &amp;lt;-- propagate saga to payment service
    .log(&quot;Payment for train #${header.id} done&quot;);

from(&quot;direct:cancelPurchase&quot;) // &amp;lt;-- The compensation route
    .log(&quot;Train purchase #${header.id} has been cancelled&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s it.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;compensation endpoint&lt;/strong&gt; is just the endpoint that must be called in order to cancel a reservation.
It&apos;s declared in the main route and invoked by Camel when it&apos;s necessary to compensate (Camel detects failures in any point of the Saga and reacts accordingly).&lt;/p&gt;
&lt;p&gt;Look at the &lt;a href=&quot;https://github.com/apache/camel/blob/master/camel-core/src/main/docs/eips/saga-eip.adoc&quot;&gt;Camel Saga EIP documentation&lt;/a&gt;.
There are many other options and features you can use. E.g.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding timeouts for saga completion&lt;/li&gt;
&lt;li&gt;Receiving saga completion callbacks&lt;/li&gt;
&lt;li&gt;Asynchronous saga execution&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Running the example&lt;/h3&gt;
&lt;p&gt;The example can be run on Openshift. Just install &lt;a href=&quot;https://github.com/minishift/minishift/releases&quot;&gt;Minishift&lt;/a&gt;, connect to it and use the following commands to start everything.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git@github.com:nicolaferraro/camel-saga-quickstart.git
cd camel-saga-quickstart
oc create -f lra-coordinator.yaml
mvn clean fabric8:deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It leverages the &lt;a href=&quot;http://maven.fabric8.io/&quot;&gt;fabric8 maven plugin&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;How do Camel Saga and &quot;Long Running Actions&quot; work&lt;/h2&gt;
&lt;p&gt;If you arrived here you may be wondering how this saga machinery works under the hood.&lt;/p&gt;
&lt;p&gt;Saga is a Camel EIP and can have different implementations. The base implementation keeps all data about the status
of every saga in memory, so it&apos;s not fault-tolerant. If the application crashes, everything is lost.
Also, propagation across services cannot be used with the base implementation.&lt;/p&gt;
&lt;p&gt;But Camel 2.21.0 ships also a new module called &lt;strong&gt;camel-lra&lt;/strong&gt; and a spring-boot starter (camel-lra-starter).&lt;/p&gt;
&lt;p&gt;LRA stands for &quot;Long Running Action&quot;, that is the name of a Microprofile specification under-development (see &lt;a href=&quot;https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA&quot;&gt;microprofile-lra&lt;/a&gt;).
Its main implementation is already available and developed by the Narayana team in &lt;a href=&quot;https://github.com/jbosstm/narayana/tree/master/rts/lra&quot;&gt;https://github.com/jbosstm/narayana/tree/master/rts/lra&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;ve provided Openshift resources to install a basic LRA coordinator in the quickstart example (file &lt;code&gt;lra-coordinator.yaml&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In spring-boot, the &lt;code&gt;camel-lra&lt;/code&gt; service can be enabled by adding the &lt;code&gt;camel-lra-starter&lt;/code&gt; module to the &lt;code&gt;pom.xml&lt;/code&gt; file and the standard Spring-Boot &lt;code&gt;application.yml&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
camel:
  service:
    lra:
      enabled: true
      coordinator-url: http://lra-coordinator:8080
      local-participant-url: http://my-url-as-seen-by-coordinator:8080/context-path
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You need to set the &lt;code&gt;camel.service.lra.enabled=true&lt;/code&gt; flag (so it will be the backing implementation of the &lt;code&gt;.saga()&lt;/code&gt; EIP) and provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The coordinator base URL&lt;/li&gt;
&lt;li&gt;The participant (&lt;em&gt;this&lt;/em&gt; service) base url in order to receive callbacks from the coordinator&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that these two settings are &lt;a href=&quot;https://github.com/nicolaferraro/camel-saga-quickstart/blob/03edc9eab657c0bae145b4c97c2d05ddaf0bf794/camel-saga-train-service/src/main/fabric8/deployment.yml#L6-L9&quot;&gt;overridden when running the quickstart inside Openshift&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yes, in case you&apos;re wondering, &lt;strong&gt;the coordinator and the participant services communicate over REST&lt;/strong&gt;.
This allows to easily extend support for LRA to other languages.&lt;/p&gt;
&lt;p&gt;A LRA coordinator is a &lt;strong&gt;stateful component&lt;/strong&gt;. Indeed it&apos;s the only stateful piece of the quickstart but you don&apos;t need to
customize it. It&apos;s a generic component that your application will just use through the &lt;code&gt;camel-lra&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;Being stateful and persistent, it adds fault tolerance to your application: your business invariants are &lt;em&gt;eventually&lt;/em&gt; respected even in the case
of failure.&lt;/p&gt;
&lt;h2&gt;A Brief Overview of the Protocol&lt;/h2&gt;
&lt;p&gt;Nothing magic happens under the hood. The protocol is fairly simple and is explained briefly by the following diagram:&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/lra-sequence-diagram.png&quot; alt=&quot;LRA Sequence Diagram&quot;/&amp;gt;
&amp;lt;caption align=&quot;bottom&quot;&amp;gt;&amp;lt;i&amp;gt;Sequence diagram of a failed LRA saga&amp;lt;/i&amp;gt;&amp;lt;/caption&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;Here &lt;code&gt;service&lt;/code&gt; is the application starting the saga (the API Gateway in the previous example).
&lt;em&gt;Before&lt;/em&gt; doing any operation, it &lt;strong&gt;first creates a saga&lt;/strong&gt; (&lt;em&gt;startLRA&lt;/em&gt; operation) by communicating with the coordinator (REST).&lt;/p&gt;
&lt;p&gt;Then, it can talk with other services: &lt;code&gt;Service1&lt;/code&gt; and &lt;code&gt;Service2&lt;/code&gt; in the picture.
The &lt;strong&gt;Long-Running-Action&lt;/strong&gt; HTTP header is used to &lt;strong&gt;propagate the LRA context to the downstream services&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Before&lt;/em&gt; &lt;code&gt;Service1&lt;/code&gt; and &lt;code&gt;Service2&lt;/code&gt; do any operation they &lt;strong&gt;join the saga by registering a compensating action (Camel URI)&lt;/strong&gt; in the coordinator (&lt;em&gt;addCompensator&lt;/em&gt; operation, another REST call).&lt;/p&gt;
&lt;p&gt;Then, after the main actions are executed, the whole saga can complete normally (everything fine) or exceptionally (like in the diagram).
In case of abnormal termination of the saga, the &lt;strong&gt;LRA coordinator will ensure&lt;/strong&gt; that all registered compensating actions are called.&lt;/p&gt;
&lt;p&gt;And what if a compensating action fails? Of course, the coordinator will retry again and again.
This means that compensating actions must be &lt;strong&gt;idempotent&lt;/strong&gt; and assume they might be called more than once.&lt;/p&gt;
&lt;h2&gt;Caveats&lt;/h2&gt;
&lt;h3&gt;Idempotency and ... &quot;Commutativity&quot;&lt;/h3&gt;
&lt;p&gt;We have seen that a compensating action must be idempotent, because the LRA coordinator can call it multiple times,
especially in case of network error or application unavailability.&lt;/p&gt;
&lt;p&gt;But there&apos;s a more severe restriction that you need to respect in order to write correct services:
&lt;strong&gt;a compensating action should be commutative w.r.t. the main action&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It means that, since we are in a distributed environment, sometimes the compensating action may be called by the LRA coordinator
before the main action has completed (or has even started).&lt;/p&gt;
&lt;p&gt;So, for example, your train service must be able to cancel a reservation even if such reservation is still not present in the system, and the reservation
must be considered already canceled when (and if) it&apos;s created by a late running main action in the future.&lt;/p&gt;
&lt;p&gt;Sometimes it can be hard to satisfy the commutativity restriction... but there can be alternative solutions...&lt;/p&gt;
&lt;h2&gt;A Bit of Q&amp;amp;A&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Is the LRA Coordinator a single point of failure?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Not necessarily, e.g. the Narayana team is working to provide scalability and failover for the coordinator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Isn&apos;t a Saga just a kind of distributed transaction?&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No, a saga is composed of independent actions that are executed in different services during a long timespan (a transaction completes within few seconds, usually).&lt;/li&gt;
&lt;li&gt;It&apos;s true that in some cases you need to register a completion-callback in the downstream service to finalize the action and
this is similar with what happens with 2-phase-commit transactions. But this is not always necessary. E.g. the train service above
has not registered any &lt;em&gt;completion&lt;/em&gt; endpoint because once a seat is reserved by one customer, it cannot be reserved by another one, and it does not matter
if the reservation is confirmed (saga completed) or not (saga in progress).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nicolaferraro/camel-saga-quickstart&quot;&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apache/camel/blob/master/camel-core/src/main/docs/eips/saga-eip.adoc&quot;&gt;Camel Saga EIP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apache/camel/blob/master/components/camel-lra/src/main/docs/lra.adoc&quot;&gt;Camel LRA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA&quot;&gt;Microprofile LRA (Sandbox)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have Fun!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Introducing Camel K</title><link>https://www.nicolaferraro.me/posts/introducing-camel-k</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/introducing-camel-k</guid><pubDate>Mon, 15 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just few months ago, we were discussing about a new project that we could start as part
of Apache Camel. A project with the potential to change the way people deal with integration.
That project is now here and it&apos;s called &lt;strong&gt;&quot;Apache Camel K&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &quot;K&quot; in the title is an obvious reference to &lt;a href=&quot;https://kubernetes.io/&quot;&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;/a&gt;, you may think. But there&apos;s also a less-obvious reference to &lt;a href=&quot;https://cloud.google.com/knative/&quot;&gt;&lt;strong&gt;Knative&lt;/strong&gt;&lt;/a&gt;: a community
project with the target of creating a common set of building blocks for &lt;strong&gt;serverless&lt;/strong&gt; applications.
Yes, going &quot;serverless&quot; is the base idea that inspired many architectural decisions for Camel K.&lt;/p&gt;
&lt;p&gt;But, let&apos;s take this one step at time...&lt;/p&gt;
&lt;h2&gt;What is &quot;Camel K&quot;?&lt;/h2&gt;
&lt;p&gt;Apache Camel K is a lightweight cloud integration platform based on the Apache Camel framework. It &lt;strong&gt;runs natively on Kubernetes and Openshift&lt;/strong&gt; and it&apos;s specifically designed for &lt;strong&gt;serverless and microservice architectures&lt;/strong&gt;.
When I say &quot;it runs&quot;, I mean &quot;it runs, now, you can try it!&quot;. Just visit the homepage of the project on Github and follow the
instructions: &lt;a href=&quot;https://github.com/apache/camel-k&quot;&gt;&lt;strong&gt;https://github.com/apache/camel-k&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&apos;s based on the &quot;operator pattern&quot; and leverages the &lt;a href=&quot;https://github.com/operator-framework/operator-sdk&quot;&gt;Operator SDK&lt;/a&gt; to perform
operations on Kubernetes resources (we define some &lt;a href=&quot;https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/&quot;&gt;custom resources&lt;/a&gt; beside the standard ones).
The operator is written in &lt;a href=&quot;https://golang.org/&quot;&gt;Go&lt;/a&gt; while the runtime is JVM based and leverages &lt;strong&gt;all the 200+ components&lt;/strong&gt; already available
in Apache Camel.&lt;/p&gt;
&lt;p&gt;Like Kubernetes and OpenShift, also &lt;strong&gt;Knative&lt;/strong&gt; will be a target platform in the near future.
Specifically, we&apos;re following the development of &lt;a href=&quot;https://github.com/knative/eventing&quot;&gt;Knative Eventing&lt;/a&gt; and &lt;a href=&quot;https://github.com/knative/serving&quot;&gt;Knative Serving&lt;/a&gt;
building blocks to provide a full support for them, once they reach an adequate level of maturity.&lt;/p&gt;
&lt;p&gt;Camel K brings integration to the next level, but at the same time is a return back to the roots for the Camel project: the &lt;a href=&quot;https://www.enterpriseintegrationpatterns.com/patterns/messaging/&quot;&gt;&lt;strong&gt;Enterprise Integration Patterns (EIP)&lt;/strong&gt;&lt;/a&gt;.
Camel has been shaped around enterprise integration patterns since its inception and developers have created a DSL that often maps patterns in a 1:1 relationship.&lt;/p&gt;
&lt;p&gt;I&apos;m not exaggerating if I state that now: &lt;strong&gt;the Camel DSL is the language of EIP&lt;/strong&gt;. It&apos;s (at least in my opinion)
the language that expresses better most of the patterns that were present in the original &lt;a href=&quot;https://www.enterpriseintegrationpatterns.com/index.html&quot;&gt;&quot;book of integration&quot;&lt;/a&gt;,
but also other patterns that have been added by the community during all these years.
And the community keeps adding patterns and new components in every release.&lt;/p&gt;
&lt;p&gt;The idea of Camel K is simply stated: &lt;strong&gt;let people use those Enterprise Integration Patterns natively on Kubernetes&lt;/strong&gt;, expressing them using the &lt;strong&gt;poweful Camel DSL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If I should provide a &lt;strong&gt;architectural overview&lt;/strong&gt; on Camel K, I&apos;d draw the following diagrams:&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/post-camel-k-architecture.png&quot; alt=&quot;Deployment Models for Camel K&quot;/&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;Camel K is what you get if you take the &lt;strong&gt;integration DSL distilled&lt;/strong&gt; from the rest of the framework
and offer a way to write integration code that is executed directly on a cloud platform:
it may be a &lt;strong&gt;&quot;modern&quot; cloud&lt;/strong&gt; platform like Kubernetes or Openshift, or a &lt;strong&gt;&quot;futuristic&quot;
cloud&lt;/strong&gt; platform like Knative for serverless workloads (Knative can run on both OpenShift and Kubernetes and it&apos;s powered by &lt;a href=&quot;https://istio.io/&quot;&gt;Istio&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;Speaking technically, the starting point is writing the integration code that we want to run. For example:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;integrate.groovy&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// expose a rest endpoint that routes messages to a Kafka topic
rest().post(&quot;/resources&quot;)
  .route()
    .to(&quot;kafka:messages&quot;)
    
// transform all messages and publish them on a HTTP endpoint
from(&quot;kafka:messages&quot;)
  .transform()... // any kind of transformation
  .to(&quot;http://myendpoint/messages&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Integrations can range from simple &lt;a href=&quot;https://github.com/apache/camel-k/blob/35aa1b3d39508ea901be7a7a1c5f4d256ce0eabb/runtime/examples/routes.js#L29&quot;&gt;timer-to-log&lt;/a&gt; dummy examples
to complex processing workflows connecting several external systems, but you write them using the same Camel DSL.&lt;/p&gt;
&lt;p&gt;Actually, I talked about &quot;a&quot; Camel DSL, but many of you already know that the Camel DSL is not a proper standalone language, but a set of primitives that can be used in &lt;strong&gt;multiple programming languages&lt;/strong&gt;.
So far we support the following languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Groovy&lt;/strong&gt;: it is probably the best language for scripting and it is currently the preferred language for writing Camel K integration code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kotlin&lt;/strong&gt;: yes, we support also Kotlin that offers a similar experience to Groovy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java&lt;/strong&gt;: it&apos;s the classic Camel DSL that many of you already know&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XML&lt;/strong&gt;: it&apos;s also a classic DSL adaptation and give its best when you plan to use one of the visual editing tools that already exist&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;: yes, we support it as well!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s not complicate things too much and consider one of the simplest integration for the moment.
The classic &lt;strong&gt;&quot;Camel Hello World&quot;&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;File: &lt;em&gt;hello.groovy&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&quot;timer:tick?period=3s&quot;)
  .setBody().constant(&quot;Hello World from Camel K!!!&quot;)
  .to(&quot;log:message&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A user that wants to run this integration on a cloud platform needs to download a small binary file that is available in the
&lt;a href=&quot;https://github.com/apache/camel-k/releases&quot;&gt;release page on the Camel K Github repository&lt;/a&gt;. It&apos;s called &lt;strong&gt;kamel&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;kamel&lt;/strong&gt; binary contains also a command to prepare your Kubernetes cluster for running integrations.
Just run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Will take care of installing the Camel K CRDs, setting up privileges and create the operator (see next) in the current namespace.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; in some cluster configurations, you need to be a cluster admin to install a CRD (it&apos;s a operation that should be done only once for the entire cluster). The &lt;code&gt;kamel&lt;/code&gt; binary will help you troubleshoot.
If you want to work on a development cluster like &lt;em&gt;Minishift&lt;/em&gt; or &lt;em&gt;Minikube&lt;/em&gt;, you can easily follow the &lt;a href=&quot;https://github.com/apache/camel-k/blob/master/docs/cluster-setup.adoc&quot;&gt;dev cluster setup guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the cluster is prepared and the operator installed in the current namespace:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run hello.groovy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And your done!&lt;/p&gt;
&lt;p&gt;This is what happens under the hood:&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/post-camel-k-architecture-detail.png&quot; alt=&quot;Camel K Architecture Details&quot;/&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;kamel&lt;/strong&gt; tool will sync your code with a Kubernetes custom resource of Kind &lt;strong&gt;Integration&lt;/strong&gt; named &lt;strong&gt;hello&lt;/strong&gt; (after the file name) in
the current namespace.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Camel K Operator&lt;/strong&gt; is the component that makes all this possible by configuring all Kubernetes resources needed for running your integration.
I&apos;ll talk more about it later.&lt;/p&gt;
&lt;p&gt;There exists also a &lt;strong&gt;dev mode&lt;/strong&gt; that allow users to create integration incrementally and with &lt;strong&gt;immediate &quot;buildless&quot; redeploys&lt;/strong&gt;.
I think a demo is worth 1000 words.&lt;/p&gt;
&lt;h2&gt;Demo&lt;/h2&gt;
&lt;p&gt;The following video shows an example of what you can do with Camel K.
It starts &lt;strong&gt;from the installation&lt;/strong&gt; on a Minishift dev cluster, showing how to run a basic quickstart.
Then it proceeds with a &lt;strong&gt;more complex example&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The second integration shown in the video will connect a &lt;strong&gt;Telegram&lt;/strong&gt; bot (you can interact with it through the Telegram app on your
mobile phone) to a &lt;strong&gt;Kafka&lt;/strong&gt; topic that will be used to buffer messages and to throttle them.
Messages will be received from Kafka again, filtered through one of the basic
&lt;strong&gt;enterprise integration patterns&lt;/strong&gt; available out-of-the box in Apache Camel,
then &lt;strong&gt;forwarded to a external HTTPS&lt;/strong&gt; endpoint.&lt;/p&gt;
&lt;p&gt;All this is done in few minutes of video, and all integrations are created &lt;strong&gt;incrementally&lt;/strong&gt;,
leveraging the new build engine behind Camel K that requires &lt;strong&gt;just 1 second to redeploy&lt;/strong&gt; the integration
after each change.&lt;/p&gt;
&lt;p&gt;Take a look:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/9Y5JfYiiBwM&quot; frameborder=&quot;0&quot; allow=&quot;autoplay; encrypted-media&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bringing &quot;operators&quot; to the next level&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/operator-framework/operator-sdk&quot;&gt;Operator SDK&lt;/a&gt; is the framework
that makes it possible to create all Kubernetes resources needed for running the &quot;Camel DSL script&quot;.&lt;/p&gt;
&lt;p&gt;Operators are commonly used to install and configure applications or platforms on Kubernetes and Openshift.
They are the digital version of the &quot;human operator&quot; that once installed the application in legacy environments,
making sure that everything is in place for the application to run.&lt;/p&gt;
&lt;p&gt;We brought this concept to the &lt;strong&gt;next level&lt;/strong&gt; in Camel K. The operator is &lt;strong&gt;&quot;intelligent&quot;&lt;/strong&gt; and knows what you want to run. It &lt;strong&gt;can understand the Camel DSL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;for example&lt;/strong&gt;, if you define a REST endpoint using the Camel REST DSL, the operator will make sure that
your integration is exposed to the outside and it will create a Service and a Route on OpenShift to expose it, or a Ingress on vanilla Kubernetes.&lt;/p&gt;
&lt;p&gt;And in the future, it will have more administrative responsibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It will expose webhooks on Kubernetes and activate the webhook registration with the external provider to receive data&lt;/li&gt;
&lt;li&gt;It will subscribe to feeds that you need to manage in your integration&lt;/li&gt;
&lt;li&gt;It will convert your &quot;polling&quot; routes into Kubernetes Cronjobs for optimizing resource utilization&lt;/li&gt;
&lt;li&gt;It will use a optimized Camel runtime platform under the hood if your routes support it&lt;/li&gt;
&lt;li&gt;It will... do a lot of useful things!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The operator will make sure that all you should do is writing your integration in a &quot;Camel DSL Script&quot;, without caring about
any administrative operation. That&apos;s what we mean with &lt;strong&gt;&quot;intelligent operator&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;What&apos;s next&lt;/h2&gt;
&lt;p&gt;There are a lot of things coming. We keep updated the &lt;a href=&quot;https://github.com/apache/camel-k/projects&quot;&gt;projects section&lt;/a&gt; in the
github repository with the current areas we&apos;re working on. Those include the already mentioned work on &lt;strong&gt;Knative&lt;/strong&gt; and also a
&lt;strong&gt;Web UI&lt;/strong&gt; for Camel K that will really rock!&lt;/p&gt;
&lt;p&gt;We love contributions! If you&apos;re interested in the project, there are a lot of ways to contribute.&lt;/p&gt;
&lt;p&gt;Meet us in our &lt;a href=&quot;https://gitter.im/apache/camel-k?utm_source=share-link&amp;amp;utm_medium=link&amp;amp;utm_campaign=share-link&quot;&gt;dedicated Gitter room&lt;/a&gt; for more information.&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Camel K on Knative: Agile Integration becoming Serverless</title><link>https://www.nicolaferraro.me/posts/camel-k-on-knative</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/camel-k-on-knative</guid><pubDate>Mon, 10 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Knative is an open source project for adding serverless building blocks on Kubernetes
and it&apos;s constantly gaining traction among developers. In Apache Camel K, we&apos;ve been working
hard to leverage all the new possibilities that it provides and this article will show
the results we&apos;ve achieved so far.&lt;/p&gt;
&lt;p&gt;If you&apos;re not familiar with &lt;a href=&quot;https://github.com/apache/camel-k&quot;&gt;Camel K&lt;/a&gt;, you can &lt;a href=&quot;/2018/10/15/introducing-camel-k/&quot;&gt;read the introductory blog post&lt;/a&gt;.
Camel K provides a lot of new features when running on &lt;a href=&quot;https://github.com/knative/&quot;&gt;Knative&lt;/a&gt;, but it also runs on plain &lt;strong&gt;&quot;vanilla&quot; Kubernetes and OpenShift&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s start with the demo, then you can read the rest of the article to understand better what we&apos;re doing.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/btf_e2GniXM&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;So, what is Knative? (and what is not)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Knative is not a complete serverless platform. Nor it&apos;s going to become one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Knative provides a collection of Kubernetes &quot;Custom Resource Definitions&quot; (CRD)
together with related controllers that make it easier to build and deploy certain kind of applications&lt;br /&gt;
on Kubernetes.&lt;/p&gt;
&lt;p&gt;Knative building blocks can be roughly divided into &lt;strong&gt;3 major areas&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/knative/build&quot;&gt;&lt;strong&gt;Knative Build area&lt;/strong&gt;&lt;/a&gt; provides custom resources for &lt;strong&gt;building applications from source code&lt;/strong&gt;
and producing container images.&lt;/p&gt;
&lt;p&gt;The CRDs provided in &lt;a href=&quot;https://github.com/knative/serving&quot;&gt;&lt;strong&gt;Knative Serving area&lt;/strong&gt;&lt;/a&gt; allow to define services that
that &lt;strong&gt;scale automatically&lt;/strong&gt; based on the load. Services can expose generic HTTP endpoints (such as REST): they are not necessarily &quot;functions&quot; (as in FaaS).
These services can &lt;strong&gt;scale up&lt;/strong&gt; when the load increases, but also &lt;strong&gt;scale down to zero&lt;/strong&gt; when the load is absent for a certain amount of time.
Services that are scaled down to zero don&apos;t consume physical resources and they are brought up again as soon as they need to serve a new request.&lt;/p&gt;
&lt;p&gt;The last part of Knative I&apos;m going to describe (and the most important one for our purposes) is the &lt;a href=&quot;https://github.com/knative/eventing&quot;&gt;&lt;strong&gt;Knative Eventing area&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The Eventing Model&lt;/h2&gt;
&lt;p&gt;Knative Eventing provides a set of building blocks (CRD) for developing event-based applications.&lt;/p&gt;
&lt;p&gt;The main block is the &lt;strong&gt;Channel&lt;/strong&gt;. A channel is the abstraction of a
publish-subscribe resource: you can push data into the channel, other services can subscribe to it to receive your data.
The channel also decouples producers and consumers, so that producers can always push data into them and consumers can do processing when they are available.&lt;/p&gt;
&lt;p&gt;Channels can be backed by different implementations. You can use a &quot;in-memory&quot; implementation, but also a complex one:
currently &lt;strong&gt;Kafka&lt;/strong&gt;, &lt;strong&gt;GCP PubSub&lt;/strong&gt; or &lt;strong&gt;Nats&lt;/strong&gt;. Those are referred as &lt;strong&gt;provisioners&lt;/strong&gt; in the Knative area.&lt;/p&gt;
&lt;p&gt;You may ask now: why don&apos;t we just use Kafka or Nats directly, &lt;strong&gt;what&apos;s the value added by Knative?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just look at this schema.&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/post-knative-channel-model.png&quot; alt=&quot;Knative Eventing Model&quot;/&amp;gt;
&amp;lt;caption align=&quot;bottom&quot;&amp;gt;&amp;lt;i&amp;gt;The Knative Eventing Model&amp;lt;/i&amp;gt;&amp;lt;/caption&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;You can notice that the relationship between the channel and the service is somewhat &lt;strong&gt;reversed&lt;/strong&gt;
respect to a classical scenario.&lt;/p&gt;
&lt;p&gt;Normally, you define a service so that when it starts it connects to a messaging broker and start &lt;strong&gt;pulling&lt;/strong&gt; data
from within that connection. In &lt;strong&gt;Knative eventing&lt;/strong&gt;, you subscribe to a channel (using a specific &lt;code&gt;Subscription&lt;/code&gt; CRD), then it&apos;s the channel that &lt;strong&gt;pushes&lt;/strong&gt; events towards your service.&lt;/p&gt;
&lt;p&gt;The nice thing of all this, is that your service just receives messages through &lt;a href=&quot;https://github.com/cloudevents/spec&quot;&gt;incoming Cloudevents&lt;/a&gt;,
&lt;strong&gt;without&lt;/strong&gt; having to &lt;strong&gt;actively connect&lt;/strong&gt; to the broker. Your service &lt;strong&gt;becomes passive&lt;/strong&gt;.
And since Knative provides other building blocks for autoscaling, your &lt;strong&gt;service scales up and down with the number of events in the channel&lt;/strong&gt; to which it&apos;s subscribed.
&lt;strong&gt;Scaling to zero is included&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Another important building block in the Knative Eventing space is the concept of &lt;strong&gt;EventSource&lt;/strong&gt;.
A event source is a resource with the role of pushing data into a &lt;em&gt;Channel&lt;/em&gt;.
E.g. you can use a GithubSource to foward GitHub generated webhook events
into a channel.&lt;/p&gt;
&lt;p&gt;Current plan in Knative is to start adding as many &lt;em&gt;EventSources&lt;/em&gt; as possible and this is one of the places where
Camel and Camel K can do the difference. Camel is already able to connect to &lt;strong&gt;250+ different systems&lt;/strong&gt;.
And Camel is also famous for the variety of &lt;strong&gt;enterprise integration patterns (EIP)&lt;/strong&gt; it implements: EIPs are really
important in scenarios enabled by Knative Eventing.&lt;/p&gt;
&lt;h2&gt;How Camel K works&lt;/h2&gt;
&lt;p&gt;I&apos;ve already described some of the internals of Camel K in the &lt;a href=&quot;/2018/10/15/introducing-camel-k/&quot;&gt;introductory blog post&lt;/a&gt;
and there will be more blog posts from the Camel K developers in the next days (so, stay tuned!).&lt;/p&gt;
&lt;p&gt;The basic idea behind Camel K is explained in the following diagram.&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/post-camel-k-operator.png&quot; alt=&quot;Camel K CRD and Operator&quot;/&amp;gt;
&amp;lt;caption align=&quot;bottom&quot;&amp;gt;&amp;lt;i&amp;gt;Camel K CRD and Operator&amp;lt;/i&amp;gt;&amp;lt;/caption&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;Camel K users write their integration code (the Camel DSL) in a script file, using &lt;strong&gt;Groovy, Kotlin&lt;/strong&gt;, Java or even JavaScript or XML, and run
it directly in the cloud platform.&lt;/p&gt;
&lt;p&gt;What happens under the hood is that the script is &lt;strong&gt;wrapped into a &quot;Integration&quot; Custom Resource&lt;/strong&gt; and added to a Kubernetes namespace.
The &lt;strong&gt;Camel K Operator&lt;/strong&gt; (based on &lt;a href=&quot;https://github.com/operator-framework/operator-sdk&quot;&gt;operator SDK&lt;/a&gt;) will then detect the new Integration and &lt;strong&gt;materialize&lt;/strong&gt; it into running containers.
Normally Camel K materializes an Integration into a Kubernetes Deployment, but when running on Knative, it uses &lt;strong&gt;auto-scaling services&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What is really cool about Camel K is that it&apos;s able to &lt;strong&gt;materialize and startup integrations in few seconds&lt;/strong&gt;. This helps a lot
during the development phase, because you have immediate feedback on the code you&apos;re writing.
The &lt;a href=&quot;https://www.youtube.com/embed/9Y5JfYiiBwM&quot;&gt;video&lt;/a&gt; accompanying the first blog post emphasizes this feature.&lt;/p&gt;
&lt;h2&gt;Camel K and Knative&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Camel K fully supports Knative&lt;/strong&gt; since version v0.1.0.
I often tend to remind (so you don&apos;t forget it) that Camel K can also run on plain (= without Knative) OpenShift and &quot;vanilla&quot; Kubernetes,
but without &quot;serverless features&quot;.&lt;/p&gt;
&lt;p&gt;An important thing of the Knative model is that, since Knative is not a serverless platform,
but a set of building blocks, you can run on top of Knative even &lt;strong&gt;multiple serverless platforms&lt;/strong&gt;.
Knative does not only provide the building blocks for creating auto-scaling services, but
also the building blocks for those platforms to &lt;strong&gt;communicate with each other&lt;/strong&gt; (eventing).&lt;/p&gt;
&lt;p&gt;Camel K, thus, is not intended to run as &lt;em&gt;exclusive&lt;/em&gt; serverless platform on top of Knative,
it&apos;s rather a &lt;strong&gt;serverless integration layer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You are not expected to build generic functions with Camel, you can just use your FaaS platform to do it (provided that it works on top of Knative).
But there are at least &lt;strong&gt;three places&lt;/strong&gt; where using &lt;strong&gt;Camel K is the best choice&lt;/strong&gt; you can do.&lt;/p&gt;
&lt;h3&gt;1. Camel K for creating Event Sources&lt;/h3&gt;
&lt;p&gt;Camel can easily push data into Knative channels, acting as event source.&lt;/p&gt;
&lt;p&gt;We&apos;ve added a new component in Camel K named &quot;knative&quot;, that allows publishing and
subscribing to knative channels. You can use a Knative endpoint at the end of any route
to create a event source. And you can use any combination of the 250+ Camel components as starting point.&lt;/p&gt;
&lt;p&gt;For example, in the demo you&apos;re going to see the following route:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;telegram:bots/&amp;lt;put-here-your-botfather-authorization&amp;gt;&apos;)
  .convertBodyTo(String.class)
  .to(&apos;knative:channel/messages&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can run it by simply executing &lt;code&gt;kamel run telegram-feed.groovy&lt;/code&gt;. As already mentioned, &lt;code&gt;kamel&lt;/code&gt; is used to
simply wrap the code in a Kubernetes custom resource, while the materialization work is always accomplished inside
Kubernetes by the &lt;strong&gt;Camel K Operator&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The simple script above generates a &quot;event source&quot;: an integration that forwards all messages sent
to a specific bot on telegram to the &quot;messages&quot; Knative channel.&lt;/p&gt;
&lt;h3&gt;2. Camel K for Enterprise Integration Patterns (EIP)&lt;/h3&gt;
&lt;p&gt;Camel K can also be used within Knative for its powerful enterprise integration patterns.
You will see in the demo the following integration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;knative:channel/messages&apos;)
  .split().tokenize(&quot; &quot;)
  .to(&apos;knative:channel/words&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is an example of one of the simplest EIP available in Camel, the &lt;a href=&quot;https://www.enterpriseintegrationpatterns.com/patterns/messaging/Sequencer.html&quot;&gt;&lt;strong&gt;splitter EIP&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You run this integration as usual: &lt;code&gt;kamel run splitter.groovy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In Camel you have tons of EIP that you can use out-of-the-box, even within Knative: content-based router, dynamic router, message filter, message transformation, recipient list... and many others.&lt;/p&gt;
&lt;h3&gt;3. Camel K for defining Integration Functions&lt;/h3&gt;
&lt;p&gt;Many times you need to notify an external system that an event occurred in the serverless space.
In these cases, it&apos;s likely that you&apos;ll write an integration function that gets executed when a specific event is received from a channel.&lt;/p&gt;
&lt;p&gt;In the demo, you&apos;ll se something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;knative:channel/words&apos;)
  .to(&apos;slack:#camel-k-tests&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This integration snippet is simply forwarding text messages to a Slack channel, but it could be also be doing transformations or enriching content with external data.&lt;/p&gt;
&lt;h2&gt;Future Work&lt;/h2&gt;
&lt;p&gt;Camel K runs really well on Knative, but we want to provide a even better experience in the next months.&lt;/p&gt;
&lt;p&gt;The value that Camel K adds to Knative is a easy way for people to write EventSources, EIP and Integration Functions.
We need to enable people to just do that, but in a way that fits more closely the ideas that are being developed
within the Knative space.&lt;/p&gt;
&lt;p&gt;The roadmaps of Camel K and Knative are closely related.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/apache/camel-k&quot;&gt;Apache Camel K&lt;/a&gt; is already here. Grab it while it&apos;s hot!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Camel K 1.0 is here</title><link>https://www.nicolaferraro.me/posts/camel-k-is-here</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/camel-k-is-here</guid><pubDate>Mon, 08 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Apache Camel K has made a lot of progress since its inception and we&apos;re now proud to &lt;strong&gt;announce the 1.0 release&lt;/strong&gt;.
We&apos;ve been working hard in the past months to add more awesome features to Camel K, but also to improve stability
and performance. This post contains a list of cool stuff that you&apos;ll find in the 1.0 GA release.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; this article has been first published on the &lt;a href=&quot;https://camel.apache.org/blog/2020/06/camel-k-release-1.0.0/&quot;&gt;Apache Camel&apos;s Blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First of all, if you&apos;re living under a rock and it&apos;s the first time you hear about Camel K,
you can read some introductory blog posts here (&lt;a href=&quot;https://nicolaferraro.me/2018/10/15/introducing-camel-k/&quot;&gt;1 - introducing camel k&lt;/a&gt;, &lt;a href=&quot;https://www.nicolaferraro.me/2018/12/10/camel-k-on-knative/&quot;&gt;2 - camel k on knative&lt;/a&gt;)
or look at the Apache Camel website that contains a &lt;a href=&quot;/camel-k/latest/&quot;&gt;Camel K section&lt;/a&gt;
with a lot of material that is automatically generated from the &lt;a href=&quot;https://github.com/apache/camel-k&quot;&gt;Github repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;User experience&lt;/h2&gt;
&lt;p&gt;Camel K development style is minimalistic: you need just to write a single file with your integration routes and you can immediately
run them on any Kubernetes cluster. This way of defining things is common to many FaaS platforms (although Camel K is not a proper FaaS platform,
but a lightweight &lt;em&gt;integration&lt;/em&gt; platform) and it&apos;s technically difficult to provide IDE support, such as code completion and other utilities,
to developers.&lt;/p&gt;
&lt;p&gt;But now we&apos;ve done it. The integration tooling team has created some cool extensions for VS Code that make the development experience
with Camel K even more exciting.
You don&apos;t need to remember the Camel DSL syntax, the IDE will give you suggestions and error highlighting.&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/ide-autocompletion.gif&quot; alt=&quot;IDE Autocompletion&quot;/&amp;gt;
&amp;lt;caption align=&quot;bottom&quot;&amp;gt;&amp;lt;i&amp;gt;IDE Autocompletion&amp;lt;/i&amp;gt;&amp;lt;/caption&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;Code completion works with Java code, but it&apos;s not only limited to it: you also have suggestions and documentation out of the box when writing the Camel URIs and property files.
And you also have many options to run integrations and interact with them, all integrated in the IDE.&lt;/p&gt;
&lt;p&gt;Just install the VS Code &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=redhat.apache-camel-extension-pack&quot;&gt;Extension Pack for Apache Camel&lt;/a&gt; to have all these features available.&lt;/p&gt;
&lt;h2&gt;Getting started tutorials&lt;/h2&gt;
&lt;p&gt;Good tools are fundamental to have a great development experience with Camel K, but then you need to learn what you can do with such a great power.
We&apos;ve created a new repository in the Apache organization that hosts getting started examples: the &lt;a href=&quot;https://github.com/apache/camel-k-examples&quot;&gt;camel-k-examples&lt;/a&gt; repository.&lt;/p&gt;
&lt;p&gt;So far we&apos;ve added guides that drive you through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apache/camel-k-examples/tree/master/01-basic&quot;&gt;01 Basic&lt;/a&gt;: Learn the basics of Camel K and some interesting use cases&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apache/camel-k-examples/tree/master/02-serverless-api&quot;&gt;02 Serverless APIs&lt;/a&gt;: How to design a serverless (i.e. auto-scaling, scaling to zero) API and run it in a few minutes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;basic quickstart is &lt;a href=&quot;https://learn.openshift.com/middleware/courses/middleware-camelk/camel-k-basic&quot;&gt;also available online&lt;/a&gt;&lt;/strong&gt;, so you can have a look at how camel k works &lt;strong&gt;without installing anything on your laptop&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;More tutorials are expected to come in the following months. You are also welcome if you want to help us by &lt;strong&gt;contributing your own&lt;/strong&gt;.
They are based on the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=redhat.vscode-didact&quot;&gt;VSCode Didact&lt;/a&gt; project, that provides an
awesome user experience.&lt;/p&gt;
&lt;p&gt;If you are looking for Camel K code samples that you can just pick and run using the CLI, the &lt;a href=&quot;https://github.com/apache/camel-k/tree/master/examples&quot;&gt;examples directory&lt;/a&gt; of the Camel K main repository contains a lot of them. You can also run them directly from Github:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run https://raw.githubusercontent.com/apache/camel-k/master/examples/Sample.java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find ready-to-use examples written in different languages (e.g. &lt;a href=&quot;https://github.com/apache/camel-k/blob/5fb589090c2f45b28aef586118df48fad8838b3f/examples/hello.xml&quot;&gt;XML&lt;/a&gt;, &lt;a href=&quot;https://github.com/apache/camel-k/blob/5fb589090c2f45b28aef586118df48fad8838b3f/examples/simple.js&quot;&gt;JavaScript&lt;/a&gt; and others).&lt;/p&gt;
&lt;h2&gt;Serverless&lt;/h2&gt;
&lt;p&gt;Serverless is the most important area where we&apos;re focusing the new developments in Apache Camel K, although, you should remember,
you can have a wonderful Camel K experience even without serverless features.
To enable the serverless profile in Camel K, you just need to have &lt;strong&gt;&lt;a href=&quot;https://knative.dev&quot;&gt;Knative&lt;/a&gt; installed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In recent releases, we have added support for the most recent advancements in Knative, for example, Camel K is very well integrated
with the &lt;strong&gt;Knative event broker&lt;/strong&gt; and you can easily produce or consume events from it.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;2 lines of code&lt;/strong&gt; you can transfer events (e.g. generated by IoT devices) &lt;strong&gt;from your MQTT broker to the mesh&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;bridge.groovy&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;paho:mytopic?brokerUrl=tcp://broker-address:1883&amp;amp;clientId=knative-bridge&apos;)
  .to(&apos;knative:event/device-event&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No kidding, you just need to write those two lines of code in a file and run it with &lt;code&gt;kamel run bridge.groovy&lt;/code&gt; to
push data into the Knative broker.&lt;/p&gt;
&lt;p&gt;And you can also scale the Integration out (&lt;em&gt;Integration&lt;/em&gt; is a Kubernetes custom resource, &lt;code&gt;kubectl get integrations&lt;/code&gt; to see all of them)
to have a higher throughput. Scaling here is manual because the source of events is a MQTT broker (but we&apos;ve plans to put &lt;a href=&quot;https://github.com/apache/camel-k/issues/1107&quot;&gt;auto-scaling also in this scenario&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The Camel K embedded auto-scaling feature works really well when you want to react to some Knative events:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;listener.groovy&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;knative:event/device-event&apos;)
  .to(&apos;http://myhost/webhook/random-id&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This integration is configured to receive all events with &lt;code&gt;type=device-event&lt;/code&gt; and &lt;strong&gt;scales automatically with the load&lt;/strong&gt; because it is materialized into a &lt;a href=&quot;https://knative.dev/docs/serving/spec/knative-api-specification-1.0/#service&quot;&gt;Knative Serving Service&lt;/a&gt;
and automatically &lt;a href=&quot;https://knative.dev/docs/eventing/broker/&quot;&gt;subscribed to the Eventing Broker via a Trigger&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It then receives a &lt;a href=&quot;https://cloudevents.io/&quot;&gt;CloudEvent&lt;/a&gt; when your IoT devices produce something and scales down to zero if there&apos;s no data coming.
You just need to create it (as before, just &lt;code&gt;kamel run listener.groovy&lt;/code&gt;), all the remaining configuration is
done &lt;strong&gt;automatically by the Camel K operator&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We&apos;ve added much more features for having a better integration with the Knative ecosystem and we&apos;ve also fixed some compatibility and performance issues that were present in previous versions. The user experience is now much smoother.&lt;/p&gt;
&lt;p&gt;If you are a Knative YAML developer (!), instead of using Camel K directly, you also have the option to use &lt;strong&gt;&lt;a href=&quot;https://knative.dev/docs/eventing/samples/apache-camel-source/&quot;&gt;Knative Camel Sources&lt;/a&gt;&lt;/strong&gt; which are part of the Knative release. They are wrappers for Camel K integrations that are compatible with all the tools used by Knative developers (such as the &lt;code&gt;kn&lt;/code&gt; CLI or the OpenShift serverless console).
Sources in Knative can only push data into the various Knative endpoints, but not the other way around (i.e. they cannot be used to publish data from Knative to the outside).
In Camel K you don&apos;t have this limitation: the Route is the fundamental building block of a Camel integration and you can do whatever you want with it.&lt;/p&gt;
&lt;h2&gt;Fast startup and low memory&lt;/h2&gt;
&lt;p&gt;We cannot say we&apos;re serverless without mentioning the work that we&apos;ve been doing in improving the performance of Camel K integrations.&lt;/p&gt;
&lt;p&gt;Starting from &lt;strong&gt;Camel 3.3.0&lt;/strong&gt; which is the default version used by Camel K 1.0.0, you can benefit from all improvements that have been made directly in the Camel core to make it much more lightweight. More in depth details of the Camel core improvements can be found the following blog series that highlights what has been changed in the 3.x Camel timeline to reduce memory footprint and speedup the startup time, which is foundamental when running integrations in a serverless environment: &lt;a href=&quot;http://www.davsclaus.com/2020/01/apache-camel-31-more-camel-core.html?m=1&quot;&gt;part 1&lt;/a&gt;, &lt;a href=&quot;http://www.davsclaus.com/2020/01/apache-camel-31-more-camel-core_30.html?m=1&quot;&gt;part 2&lt;/a&gt;, &lt;a href=&quot;http://www.davsclaus.com/2020/02/apache-camel-31-more-camel-core.html?m=1&quot;&gt;part 3&lt;/a&gt;, &lt;a href=&quot;http://www.davsclaus.com/2020/03/apache-camel-32-reflection-free.html?m=1&quot;&gt;part 4&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But improvements are not only limited to the Camel core: we&apos;re doing much more. Several months ago we&apos;ve started a new subproject of Apache Camel named &lt;a href=&quot;https://github.com/apache/camel-quarkus&quot;&gt;&quot;Camel Quarkus&quot;&lt;/a&gt; with the goal of seamlessly running integrations on top of the Quarkus framework. As you probably know, Quarkus is able to reduce the memory footprint of Java applications and improve the startup time, because it moves much startup logic to the build phase. And Quarkus applications can also be compiled to a native binary, allowing a dramatic improvements in startup performance and very low memory footprint.&lt;/p&gt;
&lt;p&gt;In Camel K 1.0.0 we support &lt;strong&gt;Camel Quarkus in JVM mode&lt;/strong&gt;. A goal is to have also the in-cluster native compilation soon (for some DSL languages, such as YAML), in one of next releases!&lt;/p&gt;
&lt;p&gt;To use Quarkus as underlying runtime, you just need to enable the &lt;strong&gt;&lt;a href=&quot;https://camel.apache.org/camel-k/latest/traits/quarkus.html&quot;&gt;Quarkus trait&lt;/a&gt;&lt;/strong&gt; when running an integration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run myintegration.groovy -t quarkus.enabled=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quarkus is expected to be the default underlying runtime in the next release, and support for Standalone mode (via camel-main) will be deprecated and removed.
This means that you won&apos;t need to enable Quarkus manually in the next releases, but you still need to do it in 1.0.&lt;/p&gt;
&lt;h2&gt;Fast build time&lt;/h2&gt;
&lt;p&gt;Every application running on Kubernetes needs to be packaged in a container image, but &lt;strong&gt;in Camel K you only provide the integration DSL and the operator does what it takes to run it&lt;/strong&gt;, including building images directly in the cluster.&lt;/p&gt;
&lt;p&gt;The operator manages a pool of reusable container images and if you redeploy your integration code, it does try to reuse existing images from the pool rather than building a new one at each change, because it takes some time to build a new one. &lt;strong&gt;It was 1 minute at the beginning...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But Kubernetes is moving so fast that you cannot solve a problem once and forget about it, you need to take care of it continuously. It happened that some of our third party dependencies that we used for doing builds in &quot;vanilla Kube&quot; has slowly degraded in performance up to a point where Camel K user experience was highly affected.&lt;/p&gt;
&lt;p&gt;We decided to work harder on the build system in order to dramatically improve (again!) the build phase of Camel K integrations.&lt;/p&gt;
&lt;p&gt;Build time can be be now measured in seconds in dev environments such as Minikube. &lt;strong&gt;A bunch of seconds&lt;/strong&gt;, most of the times. This is more than a simple improvement!&lt;/p&gt;
&lt;h2&gt;Better CLI&lt;/h2&gt;
&lt;p&gt;The &apos;kamel&apos; CLI is the main tool we provide to developers to run integrations. It&apos;s not a mandatory requirement: at the end, an Integration is a Kubernetes custom resources and you can manage it with any Kubernetes standard tool (e.g. &lt;code&gt;kubectl&lt;/code&gt;). But the &lt;code&gt;kamel&lt;/code&gt; CLI adds a lot of value for integration developers.&lt;/p&gt;
&lt;p&gt;For example, if you&apos;re a Camel Java developer it&apos;s not super easy to remember the boilerplate that you have to write in order to instantiate a Camel route builder. Now you don&apos;t have to remember that:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel init Handler.java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You get a Java file with &lt;strong&gt;all the boilerplate written for you&lt;/strong&gt; and you just have to write your integration routes.&lt;/p&gt;
&lt;p&gt;It works also with all other languages: Groovy, XML, YAML, Kotlin and JavaScript.
For example you can write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel init foo.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way you get a simple route written in JavaScript.&lt;/p&gt;
&lt;p&gt;It&apos;s not just that. Often Camel K developers need to add a lot of command line options to configure the final behavior of their integration. For example, you may want to add a custom library with the &lt;code&gt;-d&lt;/code&gt; option or configure a trait with &lt;code&gt;-t&lt;/code&gt;. E.g.:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run -d mvn:org.my:lib:1.0.0 -d mvn:org.my:otherlib:2.0.0 -t quarkus.enabled=true Handler.java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes the number of command line parameters you&apos;ve to add &lt;strong&gt;can become too many&lt;/strong&gt;. For this reason we&apos;ve added the possibility to specify them as &lt;strong&gt;modeline options&lt;/strong&gt; in the integration file (done by adding a comment line with &lt;code&gt;camel-k:&lt;/code&gt; as prefix).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Handler.java&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// camel-k: dependency=mvn:org.my:lib:1.0.0 dependency=mvn:org.my:otherlib:2.0.0 trait=quarkus.enabled=true

// ...
// your routes here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the options are written in the file, you can run the routes with just:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// simply this, additional args are read from the file
kamel run Handler.java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other options are taken automatically from the file modeline. The CLI also displays the full command to let you know what&apos;s running.&lt;/p&gt;
&lt;p&gt;This kind of configuration is extremely useful in CI/CD scenarios because it allows you to have self-contained integration files and you don&apos;t need to change the pipeline to setup additional options. If you&apos;re curious about the CI/CD configurations, you can follow the &lt;a href=&quot;https://camel.apache.org/camel-k/latest/tutorials/tekton/tekton.html&quot;&gt;tutorial about Tekton pipelines&lt;/a&gt; to have more information.&lt;/p&gt;
&lt;h2&gt;Monitoring and Tracing&lt;/h2&gt;
&lt;p&gt;Ok, you&apos;ve finished level 1 of Camel K development and you want to make serious things. You&apos;re in a very good position because Camel K provides a lot of
useful tools to add visibility on &lt;strong&gt;what your integration routes are doing&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s suppose you&apos;ve a &lt;strong&gt;&lt;a href=&quot;https://prometheus.io/&quot;&gt;Prometheus&lt;/a&gt;&lt;/strong&gt; instance in your namespace and you want to &lt;strong&gt;publish your integration metrics&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run Routes.java -t prometheus.enabled=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s it. No need to setup services and labels to enable scraping. A default prometheus configuration file is also provided for the integration, with sensible defaults. Of course you also have the option to provide &lt;a href=&quot;https://camel.apache.org/camel-k/latest/traits/prometheus.html&quot;&gt;your own configuration&lt;/a&gt; for advanced use cases.&lt;/p&gt;
&lt;p&gt;Now, let&apos;s suppose you want to see what your routes are doing and trace the execution flow of an integration. What you need to do is to install an opentracing compatible application in the namespace, such as &lt;strong&gt;&lt;a href=&quot;https://www.jaegertracing.io/&quot;&gt;Jaeger&lt;/a&gt;&lt;/strong&gt;, and run the integration as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run Routes.java -t prometheus.enabled=true -t tracing.enabled=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s it again. The Camel K operator will add the &lt;a href=&quot;https://camel.apache.org/components/latest/others/opentracing.html&quot;&gt;camel-opentracing library&lt;/a&gt; and &lt;strong&gt;connect it to the Jaeger collector that is available in the namespace&lt;/strong&gt;.
Here again, &lt;a href=&quot;https://camel.apache.org/camel-k/latest/traits/tracing.html&quot;&gt;advanced use cases&lt;/a&gt; are supported.&lt;/p&gt;
&lt;h2&gt;Master routes&lt;/h2&gt;
&lt;p&gt;Good old Camel users know why and when master routes are useful, but for those who are not familiar with the term, I&apos;m going to provide a brief explanation.&lt;/p&gt;
&lt;p&gt;Whenever you have an integration route that must be running, at any point in time, in at most one single Camel instance, you need to use a master route. Master routes can be declared by simply prefixing the consumer endpoint by the &apos;master&apos; keyword and a name that will be used to create a named lock, e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;master:mylock:telegram:bots&apos;)
  .to(&apos;log:info&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can be used to print all messages that are sent to your Telegram bot. Since the Telegram API support a single consumer only, you can guard the route with a master prefix to have the guarantee that there will be at most only one consumer at any given time.&lt;/p&gt;
&lt;p&gt;If you&apos;re wondering how there can be two instances running of you deploy one, well, think just to when you change your code and need to do a rolling update: for some time there&apos;ll be two pods running in parallel. In some cases, you may decide to scale your service out but keep only one instance of a particular route among all the pods of your service. Or you may want to embed a master route in a Knative autoscaling service: in this case, the service can scale autonomously based on the load, but there&apos;ll be only one telegram consumer at any time.&lt;/p&gt;
&lt;p&gt;Master routes &lt;strong&gt;work out of the box&lt;/strong&gt; in Camel K, you just need to put a prefix in your endpoint uri. &lt;strong&gt;A leader election protocol&lt;/strong&gt; based on Kubernetes APIs resource locks will be &lt;strong&gt;automatically configured&lt;/strong&gt; for you!&lt;/p&gt;
&lt;h2&gt;CronJobs&lt;/h2&gt;
&lt;p&gt;All complex enough systems contain several scheduled jobs. This is especially true for that part of the system that handles integration with the outside.&lt;/p&gt;
&lt;p&gt;Ideally, if you need to execute a quick periodic task, say, every two seconds, you would startup an integration with a route based on timer to execute the periodic task. E.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&quot;timer:task?period=2000&quot;)
  .to(this, &quot;businessLogic&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if the period between two executions, instead of 2 seconds (&quot;2000&quot; in the Camel URI, which is measured in milliseconds) is 2 minutes (&quot;120000&quot;) or 2 hours (&quot;7200000&quot;)?&lt;/p&gt;
&lt;p&gt;You can see that keeping a container with a JVM running for a task that should be executed once every two minutes may be overkill (it is overkill for sure when the period is 2 hours). We live in a time where resources such as &lt;strong&gt;memory and CPU are really valuable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So the Camel K operator automatically handles this situation by deploying your integration not as a Kubernetes deployment, but as a &lt;strong&gt;Kubernetes CronJob&lt;/strong&gt;. This saves a lot of resources, especially when the period between executions is high. When it&apos;s time to run your integration code, a container starts, triggers the execution and then gracefully terminates. Everything is handled automatically by Camel K and Kubernetes.&lt;/p&gt;
&lt;p&gt;There are cases when you don&apos;t want this feature to be enabled, for example, when your code makes use of in memory caches that is better to keep between executions. In these cases, you can safely turn off the feature by passing the flag &lt;code&gt;-t cron.enabled=false&lt;/code&gt; to the &lt;code&gt;kamel run&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;The Cron feature does not only work with the &lt;code&gt;timer&lt;/code&gt; component. We&apos;ve also added a &lt;a href=&quot;https://camel.apache.org/components/latest/cron-component.html&quot;&gt;cron component&lt;/a&gt; since Camel 3.1 that works really well in combination with the &lt;a href=&quot;https://camel.apache.org/camel-k/latest/traits/cron.html&quot;&gt;cron trait&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So you can also write the cron expression in the route directly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&quot;cron:job?schedule=0/5+*+*+*+?&quot;)
  .to(this, &quot;businessLogic&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, a new pod with a JVM is started every 5 minutes to execute your scheduled task. For the remaining 4+ minutes you don&apos;t use any resource.&lt;/p&gt;
&lt;h2&gt;Transparency&lt;/h2&gt;
&lt;p&gt;Camel K does a lot of work for you when you run your integration code in the cluster and it&apos;s possible that you put some errors in the code that can block the deployment process. We&apos;ve added a lot of visibility on the deployment process that now communicates with the users via Kubernetes events that are printed to the console when you use the CLI.&lt;/p&gt;
&lt;p&gt;This way you&apos;re always notified of problems in the code and you can better understand what to fix to make your integration run.&lt;/p&gt;
&lt;h2&gt;How to try Camel K 1.0&lt;/h2&gt;
&lt;p&gt;The first step is to go to the &lt;a href=&quot;https://github.com/apache/camel-k/releases&quot;&gt;Camel K release page&lt;/a&gt; on Github (or the official &lt;a href=&quot;https://dist.apache.org/repos/dist/release/camel/camel-k/1.0.0/&quot;&gt;Apache release repository&lt;/a&gt;), &lt;strong&gt;download the kamel CLI&lt;/strong&gt; for your OS and put it in your system path.&lt;/p&gt;
&lt;p&gt;Installation is done usually using the &lt;code&gt;kamel install&lt;/code&gt; command, but, depending on the kind of Kubernetes cluster you&apos;re using,
you may need to execute additional configuration steps.
The Camel K documentation contains a section about &lt;strong&gt;&lt;a href=&quot;https://camel.apache.org/camel-k/latest/installation/installation.html&quot;&gt;installing it on various types of Kubernetes clusters&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you have trouble or you need to install it on a particular cluster that is not listed, just reach out in the &lt;a href=&quot;https://gitter.im/apache/camel-k&quot;&gt;Gitter chat&lt;/a&gt; and
we&apos;ll do our best to help you.&lt;/p&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;We&apos;ve reached version 1.0.0 and this is a great milestone for us. But we are not going to stop now: we&apos;ve big plans for the future and we&apos;ll continue to develop awesome new features.&lt;/p&gt;
&lt;p&gt;We need your help to improve Camel K and &lt;strong&gt;we love contributions!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Join us on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gitter: &lt;a href=&quot;https://gitter.im/apache/camel-k&quot;&gt;https://gitter.im/apache/camel-k&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/apache/camel-k&quot;&gt;https://github.com/apache/camel-k&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Event-driven serverless applications with Camel K</title><link>https://www.nicolaferraro.me/posts/event-driven-serverless-applications-with-camel-k</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/event-driven-serverless-applications-with-camel-k</guid><pubDate>Thu, 09 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the talks I&apos;ve most enjoyed doing in 2020. A DevNation Tech Talk explaining where do we see Camel K in the context of event-driven applications.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/hlUzLC71nAM&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Serverless Integration on Kubernetes with Apache Camel K</title><link>https://www.nicolaferraro.me/posts/serverless-integration-kubecon</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/serverless-integration-kubecon</guid><pubDate>Tue, 08 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve presented Apache Camel at the last Kubecon EU conference that took place on August 19th, 2020.&lt;/p&gt;
&lt;p&gt;As for many conferences this year, Kubecon EU was held online, not in the sunny Amsterdam as it was planned. No time to meet in person the developers that are making really good things in the Knative and Kubernetes space, but the
talks were pretty awesome, and now everybody can &lt;a href=&quot;https://www.youtube.com/playlist?list=PLj6h78yzYM2O1wlsM-Ma-RYhfT5LKq0XC&quot;&gt;watch them for free on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;m proud that Apache Camel was there, thanks to the hard work that all the team has been doing over the last two years, with the new Camel 3.x releases, Camel Quarkus and especially &lt;strong&gt;Camel K&lt;/strong&gt; that bring all those features to Kubernetes.&lt;/p&gt;
&lt;p&gt;The serverless space is an area where Camel K can make the difference. Camel K integration with Knative really rocks and we&apos;re working every day on improving it.&lt;/p&gt;
&lt;p&gt;If you want to know what I&apos;m talking about, why don&apos;t you listen it from myself?&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/beJOCndVfaU&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;As you&apos;ll learn from the video, many cool features are cooking in the pot. So, stay tuned!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Kamelets</title><link>https://www.nicolaferraro.me/posts/kamelets</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/kamelets</guid><pubDate>Mon, 12 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Kamelets are the most important feature released with Apache Camel K 1.2.0. Apart from their cool name, Kamelets represent a significant change in the whole Camel ecosystem, because they introduce new ways of using Apache Camel in the cloud and a novel approach for contributing new connectors.&lt;/p&gt;
&lt;h2&gt;What is a Kamelet?&lt;/h2&gt;
&lt;p&gt;A Kamelet is a &quot;&lt;strong&gt;Kamel&lt;/strong&gt; Route Snipp&lt;strong&gt;et&lt;/strong&gt;&quot;. Before going into the details of what this actually means, let&apos;s make a step backward to add some background context.&lt;/p&gt;
&lt;p&gt;Traditionally, the building blocks of Apache Camel have always been the &lt;strong&gt;components&lt;/strong&gt;. Camel users can write complex routes by leveraging the 350+ components that are available in Apache Camel. It&apos;s not a fixed pool: Camel developers and contributors are constantly increasing the collection of supported components at each new release.&lt;/p&gt;
&lt;p&gt;This model has worked very well for all these years and it will continue to work. But it &lt;strong&gt;misses an important feature&lt;/strong&gt; that we want to cover with Kamelets: the &lt;strong&gt;ability to abstract&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In Camel, if I want to publish a tweet in response to a Knative event, I&apos;d do something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;knative:event/public.post&apos;)
  .to(&apos;twitter-timeline://user&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every time some application sends an event of type &quot;public.post&quot; to the Knative broker, that event is published in my Twitter timeline.&lt;/p&gt;
&lt;p&gt;As a user, I don&apos;t care about what the &quot;twitter-timeline&quot; component is doing under the covers: it may contact a single API, or more than one, or it may establish several connections to various systems using strange protocols. I&apos;m only interested in the result.&lt;/p&gt;
&lt;p&gt;Now, being an enterprise user, I would like to do a similar thing with my own systems and create a new component to add an item to the inventory of my e-commerce application. I decide to create a new component named &lt;strong&gt;&quot;company-inventory&quot;&lt;/strong&gt; that provides an &lt;strong&gt;&quot;add&quot;&lt;/strong&gt; endpoint to implement such feature. So:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;knative:event/new.item&apos;)
  .to(&apos;company-inventory://add&apos;) // easy, but now try to implement it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it&apos;s time to implement the &quot;company-inventory&quot; component. When adding an item to the inventory, &lt;em&gt;we need to call an HTTP API to get the ID of the actual item type, call another API if the ID is not already present, in order to create a new one, then a third API to add the item, then add another event to a third-party Kafka topic to synchronize downstream services&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easy?&lt;/strong&gt; Of course, with Apache Camel. But guess what? &lt;strong&gt;You can&apos;t use Apache Camel when writing a new component&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;True. Developers who contribute code to Apache Camel usually adapt existing libraries to the Camel APIs, but they can&apos;t leverage existing components.
There&apos;s been an attempt in Camel 2.x to bring such possibility with the &lt;a href=&quot;https://camel.apache.org/components/2.x/routebox-component.html&quot;&gt;Routebox component&lt;/a&gt;,
but it was not intuitive in some parts and missed a good delivery model, so it wasn&apos;t widely used and it was finally removed in 3.x in favor of this new idea of Kamelets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kamelets come to the rescue&lt;/strong&gt;. With Kamelets you can encapsulate the logic to connect to a specific system into &lt;a href=&quot;https://camel.apache.org/manual/latest/route-template.html&quot;&gt;&lt;strong&gt;route templates&lt;/strong&gt; (new feature of Camel 3.5.0)&lt;/a&gt;. And guess what? &lt;strong&gt;Kamelets are made of pure Camel DSL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Kamelets are Kubernetes resources. We&apos;ll see shortly how to write them. As any Kubernetes resource, you can write a Kamelet into a file and install it on a cluster using Kubectl:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;company-inventory-add.kamelet.yaml&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
apiVersion: camel.apache.org/v1alpha1
kind: Kamelet
metadata:
  name: company-inventory-add
spec:
  # ...
  # The Kamelet will declare all accepted parameters
  # in JSON-schema format.
  # 
  # Skipping the details here.
  # ...
  flow: # Here&apos;s the route
    from:
      uri: &quot;kamelet:source&quot;
      steps:
        - to: &quot;http://first-endpoint&quot;
        - to: &quot;https://second-endpoint/{{itemType}}&quot;
        - choice:
          # ...
          - to: &quot;kafka:downstream&quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;m not going into the details of how to write a Kamelet, that is &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets.html&quot;&gt;covered in the Camel K user guide about Kamelets&lt;/a&gt;. We need just to know that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Kamelet exposes a well defined JSON-schema interface, that documents its purpose and defines the accepted parameters.&lt;/li&gt;
&lt;li&gt;A Kamelet can be a source of data or a sink (consumer or producer, in the Camel jargon). The &quot;company-inventory-add&quot; Kamelet is a sink.&lt;/li&gt;
&lt;li&gt;A Kamelet defines what Camel code should be executed when the Kamelet is used inside an integration: the code is expressed as route template that can use properties (e.g. &quot;{{itemType}}&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can install the Kamelet on a namespace by simply executing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f company-inventory-add.kamelet.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once done so, the Kamelet becomes available in all integrations that are deployed in the same Kubernetes namespace. So you can write a route like this to use the Kamelet:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;example.groovy&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;knative:event/new.item&apos;)
  .to(&apos;kamelet://company-inventory-add?itemType=grocery&apos;) // implementing this is much simpler
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And run it with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run example.groovy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The logic about what it means to add an inventory item is encapsulated in the Kamelet (multiple HTTP calls, enterprise integration patterns and sync with Kafka), that can be shared among all other integrations. And it&apos;s all &lt;strong&gt;Camel DSL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is only a simple example of what a Kamelet can do, there are many more interesting use cases out there.&lt;/p&gt;
&lt;h2&gt;What about Knative sources?&lt;/h2&gt;
&lt;p&gt;The first time we thought about Kamelets was in the context of &lt;a href=&quot;https://knative.dev/docs/eventing/sources/&quot;&gt;Knative Eventing sources&lt;/a&gt;. It was the end of 2018, believe it or not.
We thought that they could really make the difference in that space, but we were not ready for the leap.&lt;/p&gt;
&lt;p&gt;We are currently providing &lt;a href=&quot;https://knative.dev/docs/eventing/samples/apache-camel-source/&quot;&gt;CamelSources&lt;/a&gt; in Knative, and they are really cool because they &lt;em&gt;allow users to write a small piece of Camel DSL&lt;/em&gt; to produce any kind of event, taking data from any system that Camel supports.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So, what&apos;s wrong with CamelSources?&lt;/strong&gt; They are really cool from my point of view. But the problem is that Knative users are usually &lt;strong&gt;not&lt;/strong&gt; Camel users.
As a Camel user, I can write a piece of Camel DSL in a few minutes and make it work. But people with a background in Go or Python... they don&apos;t even know what Camel actually is.&lt;/p&gt;
&lt;p&gt;But that&apos;s where a Kamelet can help.&lt;/p&gt;
&lt;p&gt;Camel developers and passionate contributors will write the Camel DSL, creating &quot;connectors&quot; for external sources using the language of Kamelets.
In future versions of Camel K, we&apos;ll create a &lt;strong&gt;catalog of curated Kamelets&lt;/strong&gt; that will be installed together with Camel K.
Those Kamelets will be available to anyone who installs Camel K on a Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/kamelets-binding.png&quot; alt=&quot;kamelet-binding&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Without any knowledge of Apache Camel, people can list the catalog of the available Kamelets with standard Kubernetes tools:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ kubectl get kamelets
NAME
inventory-source
twitter-source
slack-source
telegram-source
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kamelets declare the list of expected parameters using a JSON-schema format, so it will be easy to check them and provide values.&lt;/p&gt;
&lt;p&gt;Users can then decide to use a Kamelet e.g. to push some twitter data into the Knative broker. To do so, they can create a &lt;strong&gt;KameletBinding&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: camel.apache.org/v1alpha1
kind: KameletBinding
metadata:
  name: twitter-source-to-knative
spec:
  source:
    ref:
      apiVersion: camel.apache.org/v1alpha1
      kind: Kamelet
      name: twitter-source
    properties:
      keywords: Apache Camel
  sink:
    ref:
      apiVersion: eventing.knative.dev/v1
      kind: Broker
      name: default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you see, the final user will not need to know anything about Camel, only use the source.&lt;/p&gt;
&lt;p&gt;Of course, the &lt;strong&gt;KameletBinding&lt;/strong&gt; resource is a wrapper for an Integration. I.e. under the hood the operator will create the Camel DSL corresponding to the binding, which is something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# only for demonstration, we don&apos;t generate groovy code ;)
from(&apos;kamelet:twitter-source?keywords=Apache+Camel&apos;)
  .to(&apos;knative:event&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes Kamelets available to different kind of users: Camel users and Knative users, with a different interface.&lt;/p&gt;
&lt;h2&gt;So, is it only about Knative?&lt;/h2&gt;
&lt;p&gt;Of course not: Kamelets are general purpose connectors, not directly linked to Knative.&lt;/p&gt;
&lt;p&gt;If I want to send data from my Twitter Kamelet to a Kafka topic, I just need to create the following code and run it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from(&apos;kamelet:twitter-source?keywords=Apache+Camel&apos;)
  .to(&apos;kafka:topic&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All Kamelets can be used to feed Kafka instead of Knative with the same exact approach. In fact, we&apos;ve also extended the &lt;strong&gt;KameletBinding&lt;/strong&gt; mechanism to Kafka via &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets.html#_binding_to_a_kafka_topic&quot;&gt;Strimzi&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What makes Kamelets great?&lt;/h2&gt;
&lt;p&gt;The main difference between a Kamelet and a Camel component is its purpose. While a component can serve several purposes
by specifying different combinations of the parameters, &lt;strong&gt;Kamelets are driven by use cases&lt;/strong&gt;. A Kamelet can let you perform
a specific action on a system or gather data from another system, with a limited degree of flexibility.&lt;/p&gt;
&lt;p&gt;Reducing the scope helps designing CLI or &lt;strong&gt;UI tools&lt;/strong&gt; around them.&lt;/p&gt;
&lt;p&gt;A Kamelet contains (see the &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets.html#kamelets-specification&quot;&gt;Kamelet specification&lt;/a&gt; for more details):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Title and description of the purpose of the Kamelet and how to use it&lt;/li&gt;
&lt;li&gt;A nice icon&lt;/li&gt;
&lt;li&gt;The set of expected parameters in JSON-schema format&lt;/li&gt;
&lt;li&gt;The schema of the output they produce (or the input they require)&lt;/li&gt;
&lt;li&gt;Implementation (Camel DSL)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Writing a UI that allows browsing the available Kamelets, configure them and bind them to a destination should be pretty easy.&lt;/p&gt;
&lt;p&gt;There are many possible use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A specialized UI, e.g. in the OpenShift dev console, can let the user browse the available Kamelets and configure them via a graphical form to send data to a particular Knative destination&lt;/li&gt;
&lt;li&gt;A second specialized UI about Kafka can include a section where the users can instantiate the Kamelets to bring data to a particular topic&lt;/li&gt;
&lt;li&gt;Another platform, e.g. like &lt;a href=&quot;https://syndesis.io/&quot;&gt;Syndesis&lt;/a&gt; can use the Kamelets to provide additional connectors for creating end-to-end integrations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The great thing about Kamelets is that they are not bound to a spcific technology: they are reusable connectors.&lt;/p&gt;
&lt;h2&gt;Try them out!&lt;/h2&gt;
&lt;p&gt;Camel K 1.2.0 has already been released, so, why don&apos;t you try this new feature?&lt;/p&gt;
&lt;p&gt;Feedback is welcome, as well as any kind of contribution!&lt;/p&gt;
&lt;p&gt;Meet us on &lt;a href=&quot;https://camel.zulipchat.com/&quot;&gt;Zulip&lt;/a&gt;!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Debugging Camel K</title><link>https://www.nicolaferraro.me/posts/debugging-camel-k</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/debugging-camel-k</guid><description>What if your Camel K integration does not work as expected? How do you debug it? Well, there&apos;s a \&quot;debug\&quot; command now...</description><pubDate>Mon, 30 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Camel K introduces new ways of dealing with integration problems by letting you develop and run routes in the cloud, where the services that you need to connect live.
This has many advantages, since it makes it easy to use all the features available in the cloud environment from the very beginning. For example, you can leverage service discovery, you can make your integration passive and let it receive push notifications from Knative with real data... But this comes with a cost.&lt;/p&gt;
&lt;p&gt;When something goes wrong while you&apos;re developing a new integration, you&apos;d like to easily understand what&apos;s going on and fix your code.
Since the integration is not running locally, it&apos;s not easy to leverage all your IDE tools to troubleshoot.
But we&apos;re working to improve the experience on many fronts. I&apos;m describing here the new &lt;code&gt;kamel debug&lt;/code&gt; command.&lt;/p&gt;
&lt;h2&gt;Debug command&lt;/h2&gt;
&lt;p&gt;Suppose you&apos;re working on an integration problem and you&apos;ve designed your route as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import org.apache.camel.Header;
import org.apache.camel.builder.RouteBuilder;

public class Flaky extends RouteBuilder {
  @Override
  public void configure() throws Exception {

    from(&quot;timer:clock?period=5000&quot;)
    .bean(this, &quot;createPayload&quot;)
    .to(&quot;https://postman-echo.com/post&quot;)
    .log(&quot;sent!&quot;);

  }

  public String createPayload(@Header(&quot;CamelTimerCounter&quot;) Integer tick) {
    return &quot;&quot; + (100 / (tick - 1));
  }

}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I&apos;m writing the &quot;createPayload&quot; method directly in the route file, but likely you&apos;ll put it in a separate library.&lt;/p&gt;
&lt;p&gt;This is a simple route that every 5 seconds builds a payload and sends it to a HTTPS destination.&lt;/p&gt;
&lt;p&gt;You can run it with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel run Flaky.java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once it starts, you notice that there&apos;s an issue in the way the payload is built,
since the output signals an error in the first exchange.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[1] 2020-11-30 09:22:02,377 WARN  [org.apa.cam.com.tim.TimerConsumer] (Camel (camel-1) thread #0 - timer://clock) Error processing exchange. Exchange[746A22E1144A36D-0000000000000000]. Caused by: [java.lang.ArithmeticException - / by zero]: java.lang.ArithmeticException: / by zero
[1]     at Flaky.createPayload(Flaky.java:18)
[1]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[1]     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[1]     at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[1]     at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[1]     at org.apache.camel.support.ObjectHelper.invokeMethodSafe(ObjectHelper.java:208)
[1]     at org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:425)
[1]     at org.apache.camel.component.bean.MethodInfo$1.doProceed(MethodInfo.java:247)
[1]     at org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:217)
[1]     at org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:154)
[1]     at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:56)
[1]     at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:404)
[1]     at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
[1]     at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60)
[1]     at org.apache.camel.processor.Pipeline.process(Pipeline.java:147)
[1]     at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:287)
[1]     at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:207)
[1]     at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:76)
[1]     at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
[1]     at java.base/java.util.TimerThread.run(Timer.java:506)
[1] 
[1] 2020-11-30 09:22:08,088 INFO  [route1] (Camel (camel-1) thread #0 - timer://clock) sent!
[1] 2020-11-30 09:22:13,236 INFO  [route1] (Camel (camel-1) thread #0 - timer://clock) sent!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s easy to understand what&apos;s wrong here, because this is a hand crafted example, but in a real integration case, your business logic may be
much more complex and it won&apos;t be easy to understand the problem, until you actually look into the running code.&lt;/p&gt;
&lt;p&gt;There&apos;s a new command in Camel K 1.3.0 that allows you to &lt;strong&gt;switch a remote integration to &quot;debug mode&quot;&lt;/strong&gt;. This way the integration can be connected to
your IDE and you can use breakpoints to check specific sections of the code for bugs. The kamel CLI will take care of setting the right flags on the
integration and also establishing a secure tunnel to let your IDE connect to the integration.&lt;/p&gt;
&lt;p&gt;To switch to the debug mode, just run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel debug flaky
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;flaky&lt;/code&gt; is just the name of the integration. This is an example of output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ kamel debug flaky
Enabling debug mode on integration &quot;flaky&quot;...
Forwarding from 127.0.0.1:5005 -&amp;gt; 5005
Forwarding from [::1]:5005 -&amp;gt; 5005
[1] Monitoring pod flaky-76f67fb58-rk8g8
[1] exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005 -cp ./resources:[...] io.quarkus.runner.GeneratedMain
[1] Listening for transport dt_socket at address: 5005
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you see, the integration is waiting for you to connect your IDE on &lt;code&gt;localhost&lt;/code&gt; on port &lt;code&gt;5005&lt;/code&gt; using the debug protocol.
You can configure your IDE to attach to the process via that host an port. This is IDE specific, but all modern IDEs support remote debugging.&lt;/p&gt;
&lt;p&gt;If you&apos;re using VSCode, you can put a &lt;code&gt;launch.json&lt;/code&gt; file in the &lt;code&gt;.vscode&lt;/code&gt; dir at the root of your project, with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;version&quot;: &quot;0.2.0&quot;,
    &quot;configurations&quot;: [
        {
            &quot;type&quot;: &quot;java&quot;,
            &quot;name&quot;: &quot;Debug Camel K Integration&quot;,
            &quot;request&quot;: &quot;attach&quot;,
            &quot;hostName&quot;: &quot;localhost&quot;,
            &quot;port&quot;: 5005
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is enough to connect. The final result is shown in the following image:&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align: center&quot;&amp;gt;
&amp;lt;img src=&quot;/images/camel-k-debug.gif&quot; alt=&quot;IDE Debug&quot;/&amp;gt;
&amp;lt;caption align=&quot;bottom&quot;&amp;gt;&amp;lt;i&amp;gt;IDE Debug&amp;lt;/i&amp;gt;&amp;lt;/caption&amp;gt;
&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;At the end of the debug session, the integration will be restored to its normal state.&lt;/p&gt;
&lt;p&gt;Have fun with Camel K!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Kamelet Catalog</title><link>https://www.nicolaferraro.me/posts/kamelet-catalog</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/kamelet-catalog</guid><description>We&apos;re starting a new initiative at Apache Camel to create a community-driven catalog of reusable Kamelets</description><pubDate>Wed, 24 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Note: this post has been published also in the &lt;a href=&quot;https://camel.apache.org/blog/2021/02/Kamelet-Catalog/&quot;&gt;Apache Camel blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/images/post-kamelet-catalog-featured.png&quot; alt=&quot;Kamelet Catalog&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We&apos;re starting a new initiative at Apache Camel to create a community-driven catalog of reusable Kamelets (&lt;em&gt;Camel&lt;/em&gt; route snipp&lt;em&gt;ets&lt;/em&gt;, i.e. connectors) that can be used to stream data from/to external systems into any platform powered by Apache Camel.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://camel.apache.org/camel-kamelets/latest&quot;&gt;&quot;Apache Camel Kamelet catalog&quot; is available here&lt;/a&gt; and it already contains a collection of useful Kamelets: we would like to extend it with help of the community.&lt;/p&gt;
&lt;p&gt;Kamelets are currently supported out-of-the-box by the &lt;a href=&quot;https://camel.apache.org/camel-k/latest&quot;&gt;Apache Camel K&lt;/a&gt; project and we&apos;re working to support them also in Camel core, so that they can run eventually in any Apache Camel subproject, like &lt;a href=&quot;https://camel.apache.org/camel-kafka-connector/latest/&quot;&gt;Camel Kafka Connector&lt;/a&gt; (but also camel-quarkus, camel-spring-boot, ...).&lt;/p&gt;
&lt;h2&gt;Why are they useful?&lt;/h2&gt;
&lt;p&gt;The most important reason why the new Kamelet catalog is so useful is that it provides a collection of connectors that are not tied to a particular platform, but they can be reused in multiple contexts. The new &lt;strong&gt;OpenShift 4.7 developer console&lt;/strong&gt; is a clear evidence of this pattern. You can look at what it provides in the following animation:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/kamelet-catalog-source-demo.gif&quot; alt=&quot;Kamelet Catalog demo in Openshift 4.7 Developer Console&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The console shows a serverless environment where a Knative channel has been created and it&apos;s ready to receive and dispatch events to a registered subscribing service.
From the console, the user can add a new &quot;Event Source&quot; and the UI displays a collection of possibilities: well, starting from Camel K 1.4.0, that collection of sources will display &lt;strong&gt;the official Apache Camel Kamelet catalog&lt;/strong&gt;. This means that &lt;a href=&quot;#contributing&quot;&gt;contributing&lt;/a&gt; new Kamelets to the catalog will allow you to enhance the OpenShift catalog of Knative sources, for instance.&lt;/p&gt;
&lt;p&gt;But there&apos;s nothing in the Kamelet catalog specifically related to OpenShift: &lt;strong&gt;we show this to encourage people to take the same approach&lt;/strong&gt; for other platforms (in-house or open source, especially Kubernetes-based) and use cases. One of the advantages of this approach is that, since Kamelets provide a &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets-user.html#kamelets-example&quot;&gt;well defined JSON-schema interface&lt;/a&gt; for their configuration, they can be made available for any kind of users, including those who don&apos;t even know anything about Apache Camel.&lt;/p&gt;
&lt;p&gt;So, no matter if you need ingress/egress for a specific destination (like in the Knative example above) or you&apos;re working on an event orchestration/workflow tool, or you&apos;re just creating a IFTTT clone: &lt;strong&gt;if you need connectors, look at Kamelets&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Kamelets are not only useful in Web/UI projects, they can be also used from a CLI. For instance, there&apos;s a &lt;a href=&quot;https://github.com/knative-sandbox/kn-plugin-source-kamelet&quot;&gt;plugin in the making in the Knative sandbox&lt;/a&gt; that will allow users to easily create Knative sources from Kamelets using the Knative &lt;code&gt;kn&lt;/code&gt; CLI.&lt;/p&gt;
&lt;p&gt;Leaving the Kubernetes world, you can also imagine how the Kamelet Catalog can improve the user experience in Camel Kafka Connectors. As of today, A Camel Kafka connector can be created from a single Camel component: this is a quite powerful model, since components have a high degree of configurability, but it has severe limitations because complex use cases cannot be fulfilled by configuring a single Camel component. The Kamelet model will allow Camel Kafka Connector users to develop more complex use cases (because a Kamelet is a route template that can use multiple components and enterprise integration patterns) and share their connectors with other users via the Kamelet catalog.&lt;/p&gt;
&lt;h2&gt;Kamelet vs. Component&lt;/h2&gt;
&lt;p&gt;There&apos;s a question that often arises and it relates to the difference between a Camel component and a Kamelet.&lt;/p&gt;
&lt;p&gt;From a pure user perspective, the main difference between them is that the Camel component is a highly configurable resource that is intended to be used in
a Camel development environment. Components contain lots of properties that allow to customize every aspect of their behavior and how they interact with the Camel context, the registry and so on. Additionally, a single Camel component can serve multiple purposes: e.g. the &lt;code&gt;camel-facebook&lt;/code&gt; component allows receiving any kind of event or execute any action on Facebook; the &lt;code&gt;camel-http&lt;/code&gt; component allows to contact any external &lt;code&gt;http&lt;/code&gt; or &lt;code&gt;https&lt;/code&gt; endpoint.&lt;/p&gt;
&lt;p&gt;By contrast, Kamelets are tailored around actual use cases. A &lt;code&gt;todo-sink&lt;/code&gt; Kamelet may be created in the catalog to transform an event into an entry of a &quot;To-Do Application&quot; (I refer here to that kind of applications where you add the things you need to, and later mark them as resolved). It may use the &lt;code&gt;camel-http&lt;/code&gt; component under the hood, but that will be an implementation detail. The &lt;code&gt;todo-sink&lt;/code&gt; Kamelet will also expose to the end user not the full list of parameters available in the &lt;code&gt;camel-http&lt;/code&gt; component, but a reduced set of configuration properties that are relevant for the business purpose (i.e. adding an entry into a &quot;To-Do Application&quot;).
Similarly, when the Kamelet model will evolve with the help of the community, there won&apos;t be a single &lt;code&gt;facebook-source&lt;/code&gt; Kamelet, but there will be probably many facebook-related sources, one for each use case that the community finds relevant.&lt;/p&gt;
&lt;p&gt;An important corollary of all this is that we&apos;re not going to auto-generate the Kamelet catalog from the components, instead, we&apos;ll follow a more opinionated approach taking into consideration the user needs rather than what the components already provide.&lt;/p&gt;
&lt;h2&gt;Contributing&lt;/h2&gt;
&lt;p&gt;Contributions are welcome for the Kamelet catalog. All you need to do is to follow the guidelines in the &lt;a href=&quot;https://github.com/apache/camel-kamelets&quot;&gt;official repository for the Kamelet catalog on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&apos;s a list of relevant resources that you may want to learn before starting creating your own Kamelets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets.html&quot;&gt;Introduction to Kamelets in Camel K documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nicolaferraro.me/2020/10/12/kamelets/&quot;&gt;Kamelets by Nicola Ferraro&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Camel K 1.4.0 Released</title><link>https://www.nicolaferraro.me/posts/camel-k-1-4</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/camel-k-1-4</guid><description>Details of what we have done in the Camel K 1.4.0 release.</description><pubDate>Tue, 20 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Note: this post has been published also in the &lt;a href=&quot;https://camel.apache.org/blog/2021/04/camel-k-140-Whatsnew/&quot;&gt;Apache Camel blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/images/camel-featured.png&quot; alt=&quot;Camel K 1.4.0&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Apache Camel K 1.4.0 has just been released!&lt;/p&gt;
&lt;p&gt;This is a new major release of Camel K with an improved stability over previous versions, but also adding new features
that simplify the overall user experience.&lt;/p&gt;
&lt;p&gt;It is based on Camel 3.9.0 and Camel-Quarkus 1.8.1, providing all improvements that they bring, plus much more. In this blog post, we&apos;re going to describe the most important changes.&lt;/p&gt;
&lt;h2&gt;Embedded Kamelet catalog&lt;/h2&gt;
&lt;p&gt;Camel K 1.4.0 comes with an embedded &lt;a href=&quot;https://camel.apache.org/camel-kamelets/latest/&quot;&gt;Kamelet catalog&lt;/a&gt; containing multiple connectors ready for use.&lt;/p&gt;
&lt;p&gt;When installing the operator into a namespace (but also globally in the cluster), the operator installs all the kamelets from the catalog (&lt;a href=&quot;https://github.com/apache/camel-kamelets/tree/v0.2.1&quot;&gt;version 0.2.1&lt;/a&gt;), so that any integration can use them directly.&lt;/p&gt;
&lt;p&gt;Users can bind them to a specific destination by writing a YAML binding file, as explained in the &lt;a href=&quot;https://camel.apache.org/camel-kamelets/latest/aws-sqs-source.html#_knative_source&quot;&gt;specific documentation related to each Kamelet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or, you can use the new &lt;code&gt;kamel bind&lt;/code&gt; command (see below).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; it&apos;s easy to write your own Kamelet and publish it to the Apache Catalog. Take a look at the &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets-dev.html&quot;&gt;Kamelets developer guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Kamel bind command&lt;/h2&gt;
&lt;p&gt;We&apos;ve added a &lt;code&gt;bind&lt;/code&gt; subcommand to the  &lt;code&gt;kamel&lt;/code&gt; CLI that provides a new way to use Kamelets directly when you need to connect them to Knative channels, Kafka topics and any other endpoint.&lt;/p&gt;
&lt;p&gt;E.g. Suppose that you want to get events of earthquakes happening around the world, as JSON objects, in your Knative channel named &lt;code&gt;earthquakes&lt;/code&gt;. All you need to do is to install Camel K on your cluster and then execute the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel bind earthquake-source channel:earthquakes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command creates the KameletBinding resource for you and the Camel K operator does the rest to bring that data into your channel.
Data is produced using the &lt;a href=&quot;https://camel.apache.org/camel-kamelets/latest/earthquake-source.html&quot;&gt;Earthquake Source&lt;/a&gt; Kamelet available in the embedded Katalog.&lt;/p&gt;
&lt;p&gt;You can use any other Kamelet from the catalog using the &lt;code&gt;kamel bind&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;You can also target any other Kubernetes reference that is supported by Camel K, for example, sink into a &lt;a href=&quot;https://strimzi.io/&quot;&gt;Strimzi KafkaTopic&lt;/a&gt;, using a fully qualified reference, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel bind earthquake-source kafka.strimzi.io/v1beta1:KafkaTopic:mytopic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, the command also supports plain Camel URIs, which are useful especially when you&apos;re developing a new Kamelet. For example, you can write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel bind earthquake-source log:info?showHeaders=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the command will create a binding that just prints to the log the JSON data produced by the source.&lt;/p&gt;
&lt;h2&gt;Kamel dump command&lt;/h2&gt;
&lt;p&gt;When users have issues understanding why Camel K is not behaving as expected, they often need to provide useful information
about the current state of their cluster, to let Camel K developers investigate the issue and provide a solution or a quick workaround (e.g. in a Github issue, or in the Zulip chat).&lt;/p&gt;
&lt;p&gt;Usually, to identify the root cause of an issue, developers need to know things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What routes the user is trying to run&lt;/li&gt;
&lt;li&gt;What the Camel K operator is doing&lt;/li&gt;
&lt;li&gt;What images have been built, which versions of all libraries are they using&lt;/li&gt;
&lt;li&gt;What&apos;s the state of the Camel K custom resources&lt;/li&gt;
&lt;li&gt;What errors do Camel K integration throw when they start&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Providing such information has always been hard, but we now have a quick way to obtain all that.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kamel dump status.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simple command will store in a text file all the information needed to investigate a possible issue in the cluster.
The user can now &lt;em&gt;edit the file to remove sensitive information&lt;/em&gt; (which the command may not be able to tell apart), then
share it with developers to have much better insights.&lt;/p&gt;
&lt;h2&gt;Stability and compatibility&lt;/h2&gt;
&lt;p&gt;We focused a lot on stability and improved compatibility with other tools of the ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Knative support&lt;/strong&gt; (0.22.0) has been improved by fixing compatibility issues that sometimes caused multiple revisions
to be present for the same service. We&apos;ve also changed the way channels and brokers are bound to the integrations. Now it&apos;s possible
to bind integrations to multiple channels and even create sequences of integrations attached to channels without any issue (e.g. &lt;a href=&quot;https://github.com/apache/camel-k/pull/2190&quot;&gt;#2190&lt;/a&gt;, &lt;a href=&quot;https://github.com/apache/camel-k/pull/2115&quot;&gt;#2115&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We&apos;ve improved &lt;strong&gt;installation options&lt;/strong&gt;, letting you configure things that may be important in a production environment, like &lt;a href=&quot;https://github.com/apache/camel-k/pull/2114&quot;&gt;setting toleration&lt;/a&gt; or using a &lt;a href=&quot;https://github.com/apache/camel-k/pull/2180&quot;&gt;secured maven repository&lt;/a&gt;.
At the same time, we&apos;ve fixed compatibility with recent dev environments, e.g. letting you &lt;a href=&quot;https://camel.apache.org/camel-k/latest/installation/registry/k3s.html&quot;&gt;smoothly install Camel K in K3S&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also kept doing changes to continuously improve speed. On the runtime side of Camel K, we now use the &lt;a href=&quot;https://github.com/apache/camel-k/pull/1931&quot;&gt;Quarkus fast-jar format&lt;/a&gt; to reduce boot times. And last but not least on the operator side, it&apos;s possible to install Camel K globally in a cluster and have much faster build times by &lt;a href=&quot;https://github.com/apache/camel-k/pull/2058&quot;&gt;sharing base images across the cluster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The list of important changes in the &lt;a href=&quot;https://github.com/apache/camel-k/releases/tag/v1.4.0&quot;&gt;1.4.0 release&lt;/a&gt; is too long for this blog post. There have &lt;strong&gt;never been so many contributors&lt;/strong&gt; as in this release and we &lt;strong&gt;thank them all for their awesome work!&lt;/strong&gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>From Camel to Kamelets: new connectors for event-driven applications</title><link>https://www.nicolaferraro.me/posts/from-camel-to-kamelets</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/from-camel-to-kamelets</guid><pubDate>Sun, 10 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve done two similar talks this year at ApacheCon @Home and Asia, both on the ease of use of the new Kamelet paradigm when building event-driven applications.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/xVL1gJ5AJVg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Low Code Camel</title><link>https://www.nicolaferraro.me/posts/low-code-camel</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/low-code-camel</guid><description>How Kamelets enable a low code integration experience.</description><pubDate>Wed, 03 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Apache Camel is a project in constant transformation. Anyone knows that Camel has been able to adapt to any new kinds of protocols and systems that have emerged in the past 15 years. But it&apos;s not only that: Camel is also able to adapt to any new ways of dealing with integration problems in the cloud era.
While Camel K represented a fundamental shift towards a new approach to cloud-native integration, &lt;a href=&quot;/2020/10/12/kamelets/&quot;&gt;&quot;Kamelets&quot;&lt;/a&gt; are driving a deeper transformation towards &quot;low code&quot; development.&lt;/p&gt;
&lt;p&gt;When I talk about &lt;strong&gt;&quot;low code&quot;&lt;/strong&gt;, I refer to a platform for &lt;em&gt;developers&lt;/em&gt; where you can achieve most of your goals without writing any code. But at the same time, a low code platform should be customizable enough to let you show your development skills when it&apos;s time to solve critical issues. It needs to be abstract in order to easily deal with the most common problems, even using a UI. But it should not prevent a developer to play with the low level details in order to extend the capabilities of the platform itself.&lt;/p&gt;
&lt;p&gt;If you&apos;re a bit familiar with how &lt;a href=&quot;/2020/10/12/kamelets/&quot;&gt;Kamelets&lt;/a&gt; work, I think you&apos;ve already got my point here.&lt;/p&gt;
&lt;h2&gt;Bindings and Karavans&lt;/h2&gt;
&lt;p&gt;It&apos;s really easy to use Kamelets, especially in combination with &lt;a href=&quot;https://github.com/apache/camel-k&quot;&gt;Camel K&lt;/a&gt;. I&apos;ve shown in &lt;a href=&quot;https://www.youtube.com/watch?v=xVL1gJ5AJVg&quot;&gt;a recent presentation at ApacheCon @Home&lt;/a&gt; that moving data from Knative or Kafka into an S3 bucket using streaming upload is as simple as writing something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: camel.apache.org/v1alpha1
kind: KameletBinding
metadata:
  name: events-to-s3
spec:
  source:
    ref:
      apiVersion: messaging.knative.dev/v1
      kind: Channel
      name: messages
      # Or a Strimzi &quot;KafkaTopic&quot;, if you prefer
  sink:
    ref:
      kind: Kamelet
      apiVersion: camel.apache.org/v1alpha1
      name: aws-s3-streaming-upload-sink
    properties:
      bucketNameOrArn: &quot;my-bucket&quot;
      accessKey: &quot;&amp;lt;your-key&amp;gt;&quot;
      # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href=&quot;https://github.com/nicolaferraro/apachecon-home-2021/blob/main/s3-sink-binding.yaml&quot;&gt;source&lt;/a&gt;, &lt;a&gt;S3 Kamelet Documentation&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;You write this file, apply it to a Kubernetes cluster where Camel K is installed: &lt;strong&gt;done!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And it&apos;s &lt;strong&gt;completely declarative&lt;/strong&gt;. You just specify where you want to move data from and to: no need to care about lower level details.&lt;/p&gt;
&lt;p&gt;If writing YAML is not your favourite sport, you can also opt for a visual UI. I&apos;ve shown in the &lt;a href=&quot;https://www.youtube.com/watch?v=xVL1gJ5AJVg&quot;&gt;previous video&lt;/a&gt; how the OpenShift dev console is already instructed to use Kamelets in combination with Knative. But there&apos;s a new project in the horizon at Apache that will bring this model even further...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/apache/camel-karavan&quot;&gt;&lt;strong&gt;Karavan&lt;/strong&gt;&lt;/a&gt; is a new project started at Apache by &lt;a href=&quot;https://github.com/mgubaidullin&quot;&gt;Marat Gubaidullin&lt;/a&gt;. It is a generic visual UI that can design integrations based
on Kamelets. If you either need to create a simple source/sink integration or a more complex one, Karavan can help designing it with ease. There&apos;s also a &lt;a href=&quot;https://camel.apache.org/blog/2021/10/camel-karavan-preview-release/&quot;&gt;blog post about Karavan&lt;/a&gt; if you want to learn more.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/karavan.png&quot; alt=&quot;Karavan&quot; /&gt;
&lt;em&gt;The Karavan UI&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After you finish to configure the integration, the output you get from the UI is an &lt;code&gt;Integration&lt;/code&gt; custom resource, that you can direcly apply to any Kubernetes cluster (having Camel K installed) and it will automatically run.&lt;/p&gt;
&lt;p&gt;We have now a wider &lt;a href=&quot;https://camel.apache.org/camel-kamelets/latest/&quot;&gt;catalog of Kamelets&lt;/a&gt; available upstream and it will cover many use cases that you may have in mind. They are the building blocks for letting you connect systems &lt;strong&gt;without writing any code&lt;/strong&gt;: just choose if you want to use the YAML configuration or let the Karavan UI create it for you.&lt;/p&gt;
&lt;h2&gt;Where&apos;s my Kamelet?&lt;/h2&gt;
&lt;p&gt;There&apos;s no doubt you&apos;ll find a use case which is not covered by a Kamelet. For example, what about moving data between parts of your organization?&lt;/p&gt;
&lt;p&gt;In traditional Camel the approach you would have taken to address this problem is to create one or more ad hoc integrations to
fullfill any of your needs. You&apos;d develop a custom integration route for each use case you have in mind.&lt;/p&gt;
&lt;p&gt;The Kamelet approach is completely different. You develop a reusable Kamelet that is responsible of taking specific data out of your system (a &lt;strong&gt;source&lt;/strong&gt;), or putting some data back into your system (a &lt;strong&gt;sink&lt;/strong&gt;).
Once you&apos;ve done that, you can &lt;strong&gt;treat it as a high level connector in the Karavan UI&lt;/strong&gt; and use it, whenever you need, in multiple scenarios where you need to move data around, without having to code everything from scratch each time.&lt;/p&gt;
&lt;p&gt;Writing a Kamelet is easy, &lt;em&gt;much easier than writing a Camel component&lt;/em&gt;, if you&apos;ve ever tried doing so. We&apos;ve written
an extended &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets-dev.html&quot;&gt;Kamelet developer guide&lt;/a&gt; that covers
both easy and complex scenarios.&lt;/p&gt;
&lt;p&gt;We know that creating a source or a sink and also &lt;strong&gt;doing it right&lt;/strong&gt; may be difficult (integration is hard, that&apos;s why we have Apache Camel) and involve multiple enterprise integration patterns. The
Kamelet developer guide contains a &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets-dev.html#_step_5_wrap_it_into_a_kamelet&quot;&gt;section about an &quot;Earthquake&quot; source&lt;/a&gt; that is complicated on purpose, to mimic a Kamelet that may be developed for handling data inside an organization.&lt;/p&gt;
&lt;p&gt;When writing a new Kamelet, you can use plain YAML to describe a route template, add Java (or Groovy, or ...) code snippets
if you need them, or also link an external Maven project in case you want to add a more complex behavior to it (we did it in the &lt;a href=&quot;https://github.com/apache/camel-kamelets/blob/1480bd372d42df0a185b4980b465ec245f2de0c5/avro-serialize-action.kamelet.yaml#L34&quot;&gt;camel-kamelets&lt;/a&gt; repository, where we build the default catalog of Kamelets).&lt;/p&gt;
&lt;p&gt;What does not change is that, once a Kamelet is written, the logic inside it is &lt;strong&gt;well encapsulated&lt;/strong&gt; and you can treat it
as &lt;strong&gt;any other connector&lt;/strong&gt;, in a Binding or in the Karavan UI.&lt;/p&gt;
&lt;p&gt;A Kamelet is then the element that enables low code development: it&apos;s easy to configure and embeddable in any UI (such as we&apos;ve done in Karavan), and allows you to fully customize its behavior, even writing various degrees of custom code, up to the lowest level elements of a Camel integration route.&lt;/p&gt;
&lt;h2&gt;Where to go next&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/apache/camel-karavan&quot;&gt;Karavan repository&lt;/a&gt;, where you can build an run the Karavan designer. There&apos;s also a &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=camel-karavan.karavan&quot;&gt;VSCode extension&lt;/a&gt; that will let you design integrations directly from the IDE.&lt;/p&gt;
&lt;p&gt;Then start playing with Karavan in combination with &lt;a href=&quot;https://camel.apache.org/camel-k/latest/&quot;&gt;Camel K&lt;/a&gt; and
the &lt;a href=&quot;https://camel.apache.org/camel-kamelets/latest/&quot;&gt;Kamelet catalog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And finally look at how easy is to &lt;a href=&quot;https://camel.apache.org/camel-k/latest/kamelets/kamelets-dev.html&quot;&gt;create and use your own Kamelets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&apos;d love to hear your feedback!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item><item><title>Camel meets KEDA</title><link>https://www.nicolaferraro.me/posts/camel-meets-keda</link><guid isPermaLink="true">https://www.nicolaferraro.me/posts/camel-meets-keda</guid><description>Camel K integrations can leverage KEDA to scale based on the number of incoming events.</description><pubDate>Fri, 21 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://keda.sh&quot;&gt;KEDA&lt;/a&gt; (Kubernetes Event Driven Autoscalers) is a fantastic project (currently &lt;a href=&quot;https://cncf.io&quot;&gt;CNCF&lt;/a&gt; incubating) that provides Kubernetes-based autoscalers to help applications to scale out according to the number of incoming events when they are listening to several kinds of event sources. In Camel K we&apos;ve long supported &lt;a href=&quot;https://knative.dev&quot;&gt;Knative&lt;/a&gt; for providing a similar functionality for integrations that are triggered by HTTP calls, so supporting KEDA was something planned since long time, because it enables full autoscaling from a wider collection of sources. The KEDA integration has now been merged and it will be available in &lt;strong&gt;Camel K 1.8.0&lt;/strong&gt;. This post highlights some details of the solution. If you want to see it in action, you can just jump to the end to see the &lt;a href=&quot;#demo&quot;&gt;demo recording&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Why KEDA and Camel K?&lt;/h2&gt;
&lt;p&gt;Users may want to set up integrations that automatically scale, e.g. depending on the &lt;strong&gt;number of messages left in a Kafka topic&lt;/strong&gt; (for their consumer group). The integration code may do e.g. transformations, aggregations and send data do a destination and it would be great if the number of instances deployed to a Kubernetes cluster could increase when there&apos;s work left behind, or they can &lt;strong&gt;scale to zero&lt;/strong&gt; when there&apos;s no more data in the topic.
This is what KEDA does by itself with scalers (Kafka is &lt;a href=&quot;https://keda.sh/docs/2.5/scalers/&quot;&gt;one of the many scalers available in KEDA&lt;/a&gt;). What you have now is that KEDA is now automatically configured by Camel K when you run integrations, so you get the autoscaling features out of the box (you just need to turn a flag on).&lt;/p&gt;
&lt;h2&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;In Camel K 1.8.0 a new &lt;a href=&quot;https://camel.apache.org/camel-k/next/traits/keda.html&quot;&gt;KEDA trait&lt;/a&gt; has been introduced.
The trait allows to manually tweak the KEDA configuration to make sure that some &lt;em&gt;ScaledObjects&lt;/em&gt; (KEDA concept) are generated as part of the &lt;em&gt;Integration&lt;/em&gt; reconciliation, but this is mostly an internal detail. The interesting part about the KEDA trait is that it can recognize special KEDA markers in Kamelets and automatically create a KEDA valid configuration when those Kamelets are used as sources. So users can just use Kamelets to create bindings as usual and, if they &lt;strong&gt;enable a KEDA flag&lt;/strong&gt; via an annotation, they get an event driven autoscaler automatically configured.&lt;/p&gt;
&lt;p&gt;The Kamelet catalog embedded in next release (&lt;a href=&quot;https://github.com/apache/camel-kamelets/tree/v0.7.0&quot;&gt;v0.7.0&lt;/a&gt;) contains two Kamelets enhanced with KEDA metadata: &lt;code&gt;aws-sqs-source&lt;/code&gt; and &lt;code&gt;kafka-source&lt;/code&gt;. These are just two examples of the many Kamelets that can be augmented in the future. The metadata configuration system is open and Kamelets can be marked at any time to work with KEDA: this means that you don&apos;t need to wait for a new Camel K release to enable KEDA on a different source and, more importantly, that you can mark your own Kamelets with KEDA metadata to enable autoscaling from your internal organization components.&lt;/p&gt;
&lt;p&gt;The Kamelet developer guide contains a new section on &lt;a href=&quot;https://camel.apache.org/camel-k/next/kamelets/kamelets-dev.html#_keda_integration&quot;&gt;how to mark a Kamelet with KEDA metadata&lt;/a&gt;, but essentially markers are used to map Kamelet properties into KEDA configuration options, so that when you provide a Kamelet configuration, the corresponding KEDA options can be generated from it (all the work is done under the cover by the Camel K operator).&lt;/p&gt;
&lt;h2&gt;A binding example&lt;/h2&gt;
&lt;p&gt;Before looking at the demo, here&apos;s an example of &lt;strong&gt;autoscaling binding&lt;/strong&gt; that you can create with the latest Camel K:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: camel.apache.org/v1alpha1
kind: KameletBinding
metadata:
  name: kafka-to-sink
  annotations:
    trait.camel.apache.org/keda.enabled: &quot;true&quot;
spec:
  source:
    ref:
      apiVersion: camel.apache.org/v1alpha1
      kind: Kamelet
      name: kafka-source
    properties:
      bootstrapServers: &quot;&amp;lt;-- bootstrap servers --&amp;gt;&quot;
      consumerGroup: my-group
      topic: &quot;&amp;lt;-- the topic --&amp;gt;&quot;
      user: &quot;&amp;lt;-- user --&amp;gt;&quot;
      password: &quot;&amp;lt;-- pwd --&amp;gt;&quot;
  sink:
    # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can notice that the only difference from a standard binding is the presence of the &lt;code&gt;trait.camel.apache.org/keda.enabled=true&lt;/code&gt; annotation that enables the
KEDA trait in Camel K. The information about how to map Kamelet properties into KEDA options is encoded in the Kamelet definition.&lt;/p&gt;
&lt;h2&gt;Demo&lt;/h2&gt;
&lt;p&gt;Time for the demonstration. You&apos;ll see both the &lt;code&gt;aws-sqs-source&lt;/code&gt; and the &lt;code&gt;kafka-source&lt;/code&gt; in action with Camel K and KEDA.&lt;/p&gt;
&lt;p&gt;The code for the demo is in the &lt;a href=&quot;https://github.com/nicolaferraro/camel-k-keda-demo&quot;&gt;nicolaferraro/camel-k-keda-demo&lt;/a&gt; repository on GitHub.&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/z67ES6VAYV4&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Next steps&lt;/h2&gt;
&lt;p&gt;There are many other Kamelets to enhance in &lt;a href=&quot;https://github.com/apache/camel-kamelets&quot;&gt;apache/camel-kamelets&lt;/a&gt; and things to improve in Camel K that are listed in the &lt;a href=&quot;https://github.com/apache/camel-k/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2FKEDA&quot;&gt;area/KEDA&lt;/a&gt; section of the issue tracker.&lt;/p&gt;
&lt;p&gt;Contributions are always welcome!&lt;/p&gt;
</content:encoded><author>Nicola Ferraro</author></item></channel></rss>