Development on Kubernetes with Okteto and Spring Boot

Development on Kubernetes with Okteto and Spring Boot

Okteto Platform seems to be an interesting alternative to the other more popular tools that simplify development on Kubernetes. In comparison to the tools like Skaffold or Draft, the idea around Okteto is to move development entirely to Kubernetes. What does it mean in practice? Let’s check it out.
Okteto decouples development from deployment. It means that we can deploy our application using kubectl, Helm, or even Skaffold, and then use Okteto for implementing and testing application components. Of course, we may do the whole process just using Okteto commands available within CLI. This simple idea – “code locally, run and debug directly on Okteto Cloud” – accelerate your local development, reduces local setup, and eliminates integration issues.
In this article, I’m going to show you how to use Okteto for the development of a Spring Boot application that connects to a MongoDB database running on Kubernetes. The sample application will be built using Maven, which is supported on Okteto. There is a small catch in this solution – it is payable. However, you may take advantage of the developer free plan, which includes 2 CPUs and 4GB RAM, and sleeps after 24h. Developer PRO plan with 4 CPUs and 8GB RAM is available for 14 days free trial.

I have already described another useful tool for deploying applications on Kubernetes – Skaffold. If you are interested in more details you may refer to the following article Local Java Development on Kubernetes.

Example

The source code of the sample Spring Boot application that connects to MongoDB is as usual available in my GitHub repository: https://github.com/piomin/sample-spring-boot-on-kubernetes.git.

Getting started with Okteto

You should start from downloading Okteto CLI. The same as other similar solutions it is available as a single executable file that needs to be placed in your PATH. After that you should execute command okteto login that downloads and adds your Okteto’s account credentials to kubeconfig file, and sets it as a current context. Now you can use kubectl to interact with your new remote Kubernetes cluster.

okteto-login

Okteto configuration

In fact, to start development with Okteto you just need to add file okteto.yml with required configuration to the root directory of your application. You have pretty configuration options, but you should add the name of your application and an image used for development. What is very important here – it is not the Docker image just with your application. When Okteto development mode is initialized for your application, it replaces your application container with a development container that contains development tools (e.g. maven and jdk, or npm, python, go compiler, debuggers, etc). In that case we are using a special Docker image dedicated for maven okteto/maven. We are also setting Maven command for starting our Spring Boot application, some environment variables with MongoDB credentials and database name, and port forwarding option.


name: employee-service
image: okteto/maven
command: ["mvn", "spring-boot:run" ]
workdir: /app
environment:
- MONGO_USERNAME=okteto
- MONGO_DATABASE=okteto
- MONGO_PASSWORD=okteto
forward:
- 8080:8080

Now, all you need to do is to execute command okteto up in the root directory of your application. Okteto is able to automatically create Deployment, perform Maven build and deploy your Spring Boot application on a remote Kubernetes cluster.

Spring Boot development

Spring Boot application has been started on Okteto Cloud by executing Maven goal spring-boot:run. Before that it runs the full Maven build. Okteto is listening for changes in the code and synchronizes it to your remote development environment. Of course such change should not trigger Maven build once again – like for example in Skaffold. To enable that feature the only thing we need to do is to add Spring Boot Devtools to the project dependencies.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
</dependency>

Applications that use spring-boot-devtools will automatically restart whenever files on the classpath change. With Okteto the change in the local file system will trigger the restart of the application running on your remote development environment. It is also important to enable the automatic rebuilding of an application on file change in your local development IDE. If you are using IntelliJ IDEA you should enable the option Build project automatically inside Compiler section and also enable some additional registry keys. Here’s the article with a detailed description of all required steps:
https://mkyong.com/spring-boot/intellij-idea-spring-boot-template-reload-is-not-working/.

Implementation of Spring Boot for Okteto

We are building a simple application that uses Mongo as a backend store and exposes REST endpoints outside. Here’s the list of required Maven dependencies.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
</dependency>

We are using Spring Data Repository pattern for integration with Mongo. We are adding some custom find methods to the inherited list of methods defined for CrudRepository in Spring Data Mongo.

public interface PersonRepository extends CrudRepository<Person, String> {

   Set<Person> findByFirstNameAndLastName(String firstName, String lastName);
   Set<Person> findByAge(int age);
   Set<Person> findByAgeGreaterThan(int age);

}

Database connection settings are configured in application.yml. We are using environment variables injected to the container and set in okteto.yml configuration file.

spring:
  application:
    name: sample-spring-boot-on-kubernetes
  data:
    mongodb:
      uri: mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb/${MONGO_DATABASE}
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: ALWAYS

We are injecting the repository into the controller and implementing simple CRUD methods exposed as HTTP endpoints.

@RestController
@RequestMapping("/persons")
public class PersonController {

   private PersonRepository repository;

   PersonController(PersonRepository repository) {
      this.repository = repository;
   }

   @PostMapping
   public Person add(@RequestBody Person person) {
      return repository.save(person);
   }

   @PutMapping
   public Person update(@RequestBody Person person) {
      return repository.save(person);
   }

   @DeleteMapping("/{id}")
   public void delete(@PathVariable("id") String id) {
      repository.deleteById(id);
   }

   @GetMapping
   public Iterable<Person> findAll() {
      return repository.findAll();
   }

   @GetMapping("/{id}")
   public Optional<Person> findById(@PathVariable("id") String id) {
      return repository.findById(id);
   }

   @GetMapping("/first-name/{firstName}/last-name/{lastName}")
   public Set<Person> findByFirstNameAndLastName(@PathVariable("firstName") String firstName,
         @PathVariable("lastName") String lastName) {
      return repository.findByFirstNameAndLastName(firstName, lastName);
   }

   @GetMapping("/age-greater-than/{age}")
   public Set<Person> findByAgeGreaterThan(@PathVariable("age") int age) {
      return repository.findByAgeGreaterThan(age);
   }

   @GetMapping("/age/{age}")
   public Set<Person> findByAge(@PathVariable("age") int age) {
      return repository.findByAge(age);
   }

}

Deploy Spring Boot on Okteto

Before deploying our example application on Okteto we will initialize MongoDB there. Okteto provides a web-based management console. Besides managing currently developed applications, we may easily deploy some predefined software, like databases or message brokers. As you may easily run MongoDB in a single click.

okteto-spring-boot-mongodb

Of course, in the background Okteto is creating Deployment and required Secrets.

okteto-mongo-kubectl

Now, we can finally initialize our remote development environment on Okteto Cloud. The command code>okteto up is able to create new Deployment if it does not exist. Then it is enabling port forwarding on localhost:8080 and starting Maven build as shown below.

okteto-spring-boot-up

After running command okteto up we have two the Deployment object and two running pods.

okteto-pods

We can verify the status of the environment using Okteto Web UI.

okteto-webui

Our application is exposing some Actuator and /persons endpoints outside. We can easily access them at the address https://sample-spring-boot-on-kubernetes-piomin.cloud.okteto.net. Since we have already enabled port forwarding, we can also just call it using a localhost address.

okteto-spring-boot-curls

Now, we are ready to send some test requests. Let’s add two persons using POST /persons endpoint.

okteto-testadd

Finally let’s call GET /persons method to verify if two Persons has been succesfully saved in Mongo.

okteto-curls-find

Conclusion

With Okteto you don’t have Docker or Kubernetes installed on your machine. You can focus just on development in your favorite programming IDE, the same as you would do without using any cloud platform. By defining a single Okteto configuration file and then by running a single command using Okteto CLI you are able to prepare your remote development environment. In fact, you don’t have to know much about Kubernetes to start your development with Okteto, but in case you need it you may still take advantage of all Kubernetes features and special resources.

4 COMMENTS

comments user
Andrés Torres (@towerspro)

octeto typo should be oKteto

    comments user
    Piotr Mińkowski

    Definitely, thanks paying attention. Fixed

comments user
Piotr Statuch

Great artitle, however I think it need a little update.
It seems that to deploy your app (using okteto up) directly into development-container it reqiured to set autocrate flag to true in the okteto manifest file.
Moreover the rebuilding-on-change seems to be quite extravagant option, it will transfered files in quite uncontrolled maner. what you can do is just run mvn compile onece your change or fix is done, and okteto will redeploy it. Anyway it’s a great article, enjoyed reading it.

    comments user
    piotr.minkowski

    Hi, thanks. Well, maybe some things were changed in okteto during the time I created an article. So if you have any suggestions don’t afraid to create PR with changes in the repository.

Leave a Reply