maartenjan.dev

Hi! I'm Maarten-Jan, a Software Engineer focussed on Java, Kotlin, Event Sourcing and Kubernetes. I sometimes write down what I do.

Kubernetes Tips & Tricks

This blog post is adapted in november of 2025 from a presentation I did in back in 2022.

I've learned a few things about Kubernetes over the years, and how to deploy specifically JVM apps on them.

In my examples, I'm using Spring Boot apps as an example (because I'm familiar with them), but the concepts are of course more widely applicable.

Tip 1: Use probes

Probes are essentially meant to keep track of the liveness of your application, and to act when it is not.

Links:

Startup Probes

startupProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
  failureThreshold: 30
  periodSeconds: 5

Liveness Probe

livenessProbe:
 httpGet:
   path: /actuator/health/liveness
   port: 8081
 failureThreshold: 3
 periodSeconds: 20

Readiness Probe

readinessProbe:
 httpGet:
   path: /actuator/health/readiness
   port: 8080
 failureThreshold: 3
 periodSeconds: 20

Is your pod available to handle requests?

Tip 2: Use graceful shutdowns

For Java spring boot applications:

server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=20s

Since Spring 3.5 or so, graceful shutdowns are the default.

Tip 3: Read Only File system

If at all possible, make your file system read only (Reference). Some images, like Spring boot apps, require a temp folder to write data to. An example config below:

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
...
 containers:
  - image: <spring-boot-image>
    volumeMounts:
    - mountPath: /tmp
      name: tmp
  volumes:
  - name: tmp
    emptyDir: {}

Tip 4: Service accounts

Through service accounts the container you run has access to the Kubernetes api. With too many privileges, you could give your container control over your entire cluster. This is sometheing you probably do not want. So sensible settings are to not use the default service account, but create one for each workload. And make sure the roles are limited to what's required (usually none).

Tip 5: Manage your resources

Commonly, cpu usage is quite variable, while memory usage is quite stable. So a sensible starting point is to leave cpu alone, while setting memory request and limits to the same value.

Why the same value? Assuming your memory usage is relatively stable, and you want an as stable pod as possible, you simply want to make sure the memory you require (the limit) is actually reserved for this pod on startup (the request). If you reserve less than required, the node you run on may schedule more pods than it is able to serve (fully). Which will lead to instability.

resources:
  requests:
    memory: 1024Mi
  limits:
    memory: 1024Mi

refs:

Tip 6: Manage the JVM

Default HEAP in a container is 1/4 of the available memory. That generally makes no sense in a container. I advise you to set this to 75% as a starting point: -XX:MaxRAMPercentage=75

links: