Development on Kubernetes with Okteto and Spring Boot


Okteto Platform seems to be an interesting alternative to the another more popular tools that simplify development on Kubernetes. In comparison to the tools like Skaffold or Draft the idea around Octeto 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 Octeto commands available within CLI. This simple idea – “code locally, run and debug directly on Octeto Cloud” – accelerates your local development, reduces local setup and eliminates integration issues.
In this article I’m going to show you how to use Octeto for development of Spring Boot application that connects to MongoDB database running on Kubernetes. The sample application will be built using Maven, which is supported on Octeto. There is a small catch in this solution – it is payable. However, you may take an advantage of 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

You should start from downloading Octeto CLI. The same as other similar solutions it is available as a single executable file that needs to places in your PATH. After that you should execute command octeto login that downloads and adds your Octeto’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

Octeto configuration

In fact, to start development with Octeto you just need to add file octeto.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 Octeto 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 special Docker image dedicated for maven octeto/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 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 restart of application running on your remote development environment. It is also important to enable automatic rebuild of application on file change in your local development IDE. If you are using IntelliJ IDEA you should enable enable option Build project automatically inside Compiler section and also enable some additional registry keys. Here’s the article with detailed description of all required steps:
https://mkyong.com/spring-boot/intellij-idea-spring-boot-template-reload-is-not-working/.

Implementation

We are building 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 repository into the controller and implementing simple CRUD methods exposed as HTTP enpoints.

@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);
	}

}

Deployment

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

okteto-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-up

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

okteto-pods

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

okteto-webui

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

okteto-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 favourite 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 an advantage of all Kubernetes features and special resources.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.