![]() |
Dekorate
is a library that defines a set of annotation processors used for generating
and decorating Kubernetes/OpenShift manifests. In fact you just need to
annotate your application main class properly and Dekorate will take care of
everything else. To use this library you only have to include it in your Maven
pom.xml as shown below.
<dependency>
<groupId>io.dekorate</groupId>
<artifactId>openshift-spring-starter</artifactId>
<version>0.8.2</version>
</dependency>
The starter contains not only annotations and annotation processors
that may be used on your application, but also support for generation during
Maven build, which is executed during compile phase. To enable Decorate during
build you need to set property dekorate.build to true. You can also enable
deployment by setting property dekorate.deploy to true as shown below.
$ mvn clean
install -Ddekorate.build=true -Ddekorate.deploy=true
Dekorate
supports OpenShift S2I. It generates ImageStream for builder and target
application, and also BuildConfig resource. If you enable deploy mode it also
generates deployment config with required resources. Here’s the screen with
logs from Maven build executed on my local machine.
#In this
case Dekorate is generating OpenShift manifest files and saves them inside directory
target/classes/META-INF/dekorate/, and then performing deployment on my
instance of Minishift available under virtual address 192.168.99.100.
Unfortunately,
we have to modify generated BuildConfig for our convenience. So instead of
source type Binary we will just declare Git source repository address.
apiVersion:
"build.openshift.io/v1"
kind: "BuildConfig"
metadata:
labels:
app: "sample-app" version: "1.1.0" group:
"minkowp" name: "sample-app" spec:
output:
to:
kind:
"ImageStreamTag" name: "sample-app:1.1.0" source:
git:
uri: 'https://github.com/piomin/sample-app.git'
type: Git
strategy:
sourceStrategy:
from:
kind: "ImageStreamTag" name: "s2i-java:2.3"
In order to apply the changes execute the following
commands:
$ oc delete bc
sample-app
$ oc apply -f build-config-dekorate.yaml
Customization
If you have Spring Boot applications it is possible to completely
bypass annotations by utilizing already-existing, framework-specific metadata.
To customize the generated manifests you can add dekorate properties to your
application.yml or application.properties descriptors. I have some problems
running these mode with Dekorate, so I avoided it. However, I prefer using
annotations on the code, so I prepared the following configuration, which has
been succesfully generated:
@SpringBootApplication
@OpenshiftApplication(replicas = 2, expose = true, envVars = {
@Env(name="sample-app-config", configmap =
"sample-app-config")
})
@JvmOptions(xms = 128, xmx = 256, heapDumpOnOutOfMemoryError = true)
@EnableSwagger2
public class SampleApp {
public
static void main(String[] args) { SpringApplication.run(SampleApp.class, args);
}
// ... REST OF
THE CODE
}
In
the fragment of code visible above we have declared some useful settings for
the application. First, it should be run in two pods (replicas=2). It also
should be exposed outside a cluster using OpenShift route (expose=true). The
application uses Kubernetes ConfigMap as a source of dynamically managed
configuration settings. By annotating the main class with @JvmOptions we may
customize behaviour of JVM running on the container, for example by setting
maximum heap memory consumption. Here’s the definition of ConfigMap created for
the test purpose:
apiVersion:
v1 kind: ConfigMap metadata:
name:
sample-app-config namespace: myproject data:
showAddress:
'true' showContactInfo: 'true' showSocial: 'false'
Sample Application
This very basic Spring Boot web application exposes simple REST API
with some monitoring endpoints included with Spring Boot Actuator and API
documentation generated using Swagger.
<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>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Dekorate is able to automatically detect existence of Spring Boot
Actuator dependency and basing on it generate OpenShift readiness and liveness
healthchecks definitions as shown below. By default it sets timeout on 10
seconds, and period on 30 seconds. We can override a default behaviour using
fields liveness and readiness of @OpenshiftApplication.
dekorate-3
The
controller class provides implementation for some basic CRUD REST operations.
It also injects some environment variables taken from ConfigMap sample-app-config.
Basing on their values it decides whether to show or not to show additional
person parameters like address, contact information or social links. Here’s an
implementation of PersonController:
@RestController
@RequestMapping("/persons") public class PersonsController {
private static
final Logger LOGGER = LoggerFactory.getLogger(PersonsController.class);
@Autowired
PersonRepository repository;
@Value(value
= "${showAddress:false}") boolean showAddress;
@Value(value
= "${showContactInfo:false}") boolean showContactInfo;
@Value(value
= "${showSocial:false}") boolean showSocial;
@PostMapping
public
Person add(@RequestBody Person person) { LOGGER.info("Person add:
{}", person);
return repository.add(person);
}
@GetMapping("/{id}")
public
Person findById(@PathVariable("id") Integer id) {
LOGGER.info("Person find: id={}", id);
return hidePersonParams(repository.findById(id));
}
@GetMapping
public
List<Person> findAll() { LOGGER.info("Person find");
return repository.findAll().stream().map(this::hidePersonParams).collect(Collectors.toList());
}
private
Person hidePersonParams(Person person) { if (!showAddress)
person.setAddress(null);
if (!showContactInfo) person.setContact(null); if (!showSocial)
person.setSocial(null); return person;
}
}
Here’s an
implementation of a model class. I used Lombok library for getters/setters and
constructor generation.
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
private
Integer id; private String name; private int age;
private
Gender gender; private Address address; private Contact contact; private Social
social;
}
3 Comments
good
ReplyDeleteThanks for sharing such a great information.. It really helpful to me.I always search to read the quality content and finally i found this in you post. keep it up!
ReplyDeleteVery Good… i really like your blog…
ReplyDelete