Apache Camel K and Quarkus on Kubernetes

Apache Camel K and Quarkus on Kubernetes

Apache Camel K and Quarkus may simplify our development on Kubernetes. They are both relatively new products. Apache Camel K is a lightweight integration framework that runs natively on Kubernetes. It allows us to run code written in Camel DSL on the cloud. We may easily integrate it with the Quarkus framework. As a result, we would have a powerful solution that helps us in building serverless or microservices applications.

It is my first article about Apache Camel K. However, you will find many interesting posts about Quarkus on my blog. It is worth reading Guide to Quarkus on Kubernetes before proceeding with this article. If you would like to know more about microservices with Quarkus you should also refer to Quick Guide to Microservices with Quarkus on OpenShift.

In this article, I will show you how to integrate Quarkus with Apache Camel. Consequently, we will use the Camel Quarkus project for that. It provides Quarkus extensions for many of the Camel components. Finally, you will also learn how to install Apache Camel K on Kubernetes and then use it to deploy our Quarkus Camel application there. Ok, let’s do this!

Source code

If you would like to try it by yourself, you may always take a look at my source code. In order to do that you need to clone my repository sample-camel-quarkus. Then you should go to the account-service directory, and just follow my instructions 🙂 If you are interested in more details about Apache Camel you should read its documentation.

Enable integration between Apache Camel and Quarkus

We are going to create a simple application that exposes a REST API and uses an in-memory repository. There are many camel.quarkus.* components that may be used between Apache Camel and Quarkus. In order to build a REST-based application, we need to include three of them: Rest, Jackson, and Platform HTTP. I have also included a well-known Lombok module.

<dependency>
   <groupId>org.apache.camel.quarkus</groupId>
   <artifactId>camel-quarkus-platform-http</artifactId>
</dependency>
<dependency>
   <groupId>org.apache.camel.quarkus</groupId>
   <artifactId>camel-quarkus-rest</artifactId>
</dependency>
<dependency>
   <groupId>org.apache.camel.quarkus</groupId>
   <artifactId>camel-quarkus-jackson</artifactId>
</dependency>
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.18.16</version>
</dependency>

Then we should add a dependencyManagement section with Camel Quarkus BOM. Apache Camel K ignores this section during deployment on Kubernetes. However, it may be useful for a local run with mvn compile quarkus:dev.

<dependencyManagement>
   <dependencies>
      <dependency>
         <groupId>org.apache.camel.quarkus</groupId>
         <artifactId>camel-quarkus-bom</artifactId>
         <version>${camel-quarkus.version}</version>
         <type>pom</type>
         <scope>import</scope>
      </dependency>
   </dependencies>
</dependencyManagement>

Create Quarkus application using Apache Camel DSL

The most comfortable way to deploy the application on Kubernetes with Apache Camel K is by setting a single file name in the running command. So, we should have the logic closed inside a single source code file. Although it is a standard for serverless applications, it is not comfortable for microservices. Let’s take a look at the model class. Both model and repository classes will be nested inside the single AccountRoute class.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Account {
   private Integer id;
   private String number;
   private int amount;
   private Integer customerId;
}

Here’s our in-memory repository implementation.

public class AccountService {

   private List<Account> accounts = new ArrayList<>();

   AccountService() {
      accounts.add(new Account(1, "1234567890", 5000, 1));
      accounts.add(new Account(2, "1234567891", 12000, 1));
      accounts.add(new Account(3, "1234567892", 30000, 2));
   }

   public Optional<Account> findById(Integer id) {
      return accounts.stream()
            .filter(it -> it.getId().equals(id))
            .findFirst();
   }

   public List<Account> findByCustomerId(Integer customerId) {
      return accounts.stream()
            .filter(it -> it.getCustomerId().equals(customerId))
            .collect(Collectors.toList());
   }

   public List<Account> findAll() {
      return accounts;
   }

   public Account add(Account account) {
      account.setId(accounts.size() + 1);
      accounts.add(account);
      return account;
   }

}

Finally, we may proceed to the AccountRoute implementation. It extends a Camel RouteBuilder base class. It has to override the configure method to define Camel routes using the REST component. Firstly, we need to set a global JSON binding mode for all the routes. Then we may define REST endpoints using rest() DSL method. There are four HTTP endpoints as shown below:

  • GET /accounts/{id} – find a single account object by its id.
  • GET /accounts/customer/{customerId} – find a list of account objects by the customer id.
  • POST /accounts – add a new account.
  • GET /accounts – list all available accounts.
@ApplicationScoped
public class AccountRoute extends RouteBuilder {

   AccountService accountService = new AccountService();

   @Override
   public void configure() throws Exception {
      restConfiguration().bindingMode(RestBindingMode.json);

      rest("/accounts")
            .get("/{id}")
               .route().bean(accountService, "findById(${header.id})").endRest()
            .get("/customer/{customerId}")
               .route().bean(accountService, "findByCustomerId(${header.customerId})").endRest()
            .get().route().bean(accountService, "findAll").endRest()
            .post("/")
               .consumes("application/json").type(Account.class)
               .route().bean(accountService, "add(${body})").endRest();
   }

   // model and repository implementations ...
}

Install Apache Camel K on Kubernetes

Our Quarkus application is ready. Now, we need to deploy it on Kubernetes. And here comes Apache Camel K. With this solution, we can easily deploy Camel routes directly from the source code by executing command kamel run $SOURCE_FILE_LOCATION. After that, the integration code immediately runs in the cloud. Of course, to achieve that we first need to install Apache Camel K on Kubernetes. Let’s take a closer look at the installation process.

The first information is not very positive. Apache Camel K supports the default registry for OpenShift (including local Minishift or CRC) and Minikube. I’m using Kubernetes on Docker Desktop… Ok, it doesn’t put me off. We just need to add some additional parameters in the installation command. Let’s set the docker.io repository. Of course, you need to have an account on Docker Hub as shown below.

$ kamel install --registry docker.io --organization your-user-id --registry-auth-username your-user-id --registry-auth-password your-password

This command will create custom resource definitions on the cluster and install the operator on the current namespace. Let’s verify it.

Deploy Quarkus on Kubernetes using Apache Camel K

Then, we should go to the account-service directory. In order, to deploy the Quarkus application with Apache Camel K we need to execute the following command.

$ kamel run --name account --dev \
   src/main/java/pl/piomin/samples/quarkus/account/route/AccountRoute.java \
   --save

Unfortunately, Apache Camel K is not able to detect all the dependencies declared in Maven pom.xml. Therefore, we will declare them inside the comment on the AccountRoute class. They must be preceded by a keyword camel-k as shown below.

// camel-k: dependency=mvn:org.apache.camel.quarkus:camel-quarkus-jackson
// camel-k: dependency=mvn:org.projectlombok:lombok:1.18.16

@ApplicationScoped
public class AccountRoute extends RouteBuilder {
   ...
}

If everything goes fine, our Quarkus Camel application successfully starts on Kubernetes. So, you should see similar logs after executing the kamel run command.

apache-camel-k-quarkus-on-kubernetes-quarkus-logs

Then, we may take a look at a list of deployments once again. Apache Camel K has created a new deployment with the name account. We had set such a name in kamel run command using the name parameter.

In the background, Apache Camel K creates the CRD Integration. So, if you are interested in how it works, it is worth to print details about the Integration object.

$ kubectl get integration account -o yaml

Final testing

Since our application is running on Kubernetes, we may proceed to the tests. Firstly, let’s see a list of Kubernetes services. Fortunately, Apache Camel K automatically creates the service with a NodePort type. In my case, the account service is exposed at the port 30860.

apache-camel-k-quarkus-on-kubernetes-svc

Finally, let’s just send some test requests.

$ curl http://localhost:30860/accounts
[{"id":1,"number":"1234567890","amount":5000,"customerId":1},
 {"id":2,"number":"1234567891","amount":12000,"customerId":1},
 {"id":3,"number":"1234567892","amount":30000,"customerId":2}]
$ curl http://localhost:30860/accounts/1
{"id":1,"number":"1234567890","amount":5000,"customerId":1}
$ curl http://localhost:30860/accounts/2
{"id":2,"number":"1234567891","amount":12000,"customerId":1}
$ curl http://localhost:30860/accounts/customer/1
[{"id":1,"number":"1234567890","amount":5000,"customerId":1},
 {"id":2,"number":"1234567891","amount":12000,"customerId":1}]

And the last cool feature at the end. Let’s assume we will perform some changes in the Account.java file. The command kamel run is still running and watching for changes in the main Camel file. The latest version of the application with changes is immediately deployed on Kubernetes.

Conclusion

Apache Camel K fits perfectly to the serverless applications, where the whole code is encapsulated in a single file. However, we may also use it to deploy microservices on Kubernetes. We may take advantage of the built-in integration between Apache Camel K and Quarkus. The only constraint on using it is the necessity to have the whole code not directly related to Camel routes in a single file or in an external library. Other than that, Apache Camel K seems promising. Unfortunately, it doesn’t have the same level of support for Spring Boot as for Quarkus. I hope it will be improved in the near future. I’ll definitely keep an eye on the development of this framework.

Leave a Reply