DEV Community

Raj Beemi
Raj Beemi

Posted on

Mastering Helm Charts for Spring Boot: Managing Common Properties

As a developer working with Spring Boot applications in Kubernetes, you've likely encountered the challenge of managing configurations across different environments. Helm charts provide an excellent solution to this problem, allowing you to template your Kubernetes manifests and manage environment-specific configurations efficiently. In this post, we'll explore how to create a Helm chart for a Spring Boot application, focusing on managing common properties.

Why Helm Charts for Spring Boot?

Before we dive in, let's quickly recap why Helm charts are beneficial for Spring Boot applications:

  1. Environment-specific configurations: Easily manage different configurations for dev, staging, and production.
  2. Reproducible deployments: Ensure consistent deployments across environments.
  3. Version control: Track changes to your Kubernetes configurations over time.
  4. Simplified rollbacks: Easily revert to previous versions of your application.

Creating a Helm Chart for Spring Boot

Let's start by creating a basic Helm chart structure for our Spring Boot application:

helm create spring-boot-app
Enter fullscreen mode Exit fullscreen mode

This creates a directory structure like this:

spring-boot-app/
├── Chart.yaml
├── values.yaml
├── templates/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
└── charts/
Enter fullscreen mode Exit fullscreen mode

Managing Common Properties

Spring Boot applications often have properties that need to be configured differently for each environment. Let's look at how to manage these using Helm.

1. Defining Properties in values.yaml

First, let's define our common properties in values.yaml:

# values.yaml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: dbuser
    password: dbpass
  jpa:
    hibernate:
      ddl-auto: update
  kafka:
    bootstrap-servers: localhost:9092

app:
  logLevel: INFO
  feature:
    featureA: true
    featureB: false
Enter fullscreen mode Exit fullscreen mode

2. Using Properties in Kubernetes Manifests

Now, let's use these properties in our Kubernetes deployment manifest:

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "spring-boot-app.fullname" . }}
spec:
  # ... other deployment specs ...
  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          env:
            - name: SPRING_DATASOURCE_URL
              value: {{ .Values.spring.datasource.url }}
            - name: SPRING_DATASOURCE_USERNAME
              value: {{ .Values.spring.datasource.username }}
            - name: SPRING_DATASOURCE_PASSWORD
              value: {{ .Values.spring.datasource.password }}
            - name: SPRING_JPA_HIBERNATE_DDL_AUTO
              value: {{ .Values.spring.jpa.hibernate.ddl-auto }}
            - name: SPRING_KAFKA_BOOTSTRAP_SERVERS
              value: {{ .Values.spring.kafka.bootstrap-servers }}
            - name: APP_LOGLEVEL
              value: {{ .Values.app.logLevel }}
            - name: APP_FEATURE_FEATUREA
              value: "{{ .Values.app.feature.featureA }}"
            - name: APP_FEATURE_FEATUREB
              value: "{{ .Values.app.feature.featureb }}"
Enter fullscreen mode Exit fullscreen mode

3. Creating Environment-Specific Value Files

For different environments, create separate value files:

# values-dev.yaml
spring:
  datasource:
    url: jdbc:postgresql://dev-db:5432/mydb
    username: devuser
    password: devpass
  kafka:
    bootstrap-servers: dev-kafka:9092

app:
  logLevel: DEBUG
  feature:
    featureA: true
    featureB: true

# values-prod.yaml
spring:
  datasource:
    url: jdbc:postgresql://prod-db:5432/mydb
    username: produser
    password: prodpass
  kafka:
    bootstrap-servers: prod-kafka-1:9092,prod-kafka-2:9092,prod-kafka-3:9092

app:
  logLevel: WARN
  feature:
    featureA: true
    featureB: false
Enter fullscreen mode Exit fullscreen mode

Handling Secrets

For sensitive information like database passwords, it's better to use Kubernetes Secrets. Here's how you can modify your Helm chart to use secrets:

  1. Create a template for secrets:
# templates/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: {{ include "spring-boot-app.fullname" . }}-secret
type: Opaque
data:
  db-password: {{ .Values.spring.datasource.password | b64enc }}
Enter fullscreen mode Exit fullscreen mode
  1. Update the deployment to use this secret:
# templates/deployment.yaml
# ... previous content ...
          env:
            # ... other env variables ...
            - name: SPRING_DATASOURCE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: {{ include "spring-boot-app.fullname" . }}-secret
                  key: db-password
Enter fullscreen mode Exit fullscreen mode

Using ConfigMaps for Application Properties

For non-sensitive configurations, you can use ConfigMaps. This is particularly useful for managing application.properties or application.yaml files:

  1. Create a template for ConfigMap:
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "spring-boot-app.fullname" . }}-config
data:
  application.yaml: |
    spring:
      datasource:
        url: {{ .Values.spring.datasource.url }}
        username: {{ .Values.spring.datasource.username }}
      jpa:
        hibernate:
          ddl-auto: {{ .Values.spring.jpa.hibernate.ddl-auto }}
      kafka:
        bootstrap-servers: {{ .Values.spring.kafka.bootstrap-servers }}
    app:
      logLevel: {{ .Values.app.logLevel }}
      feature:
        featureA: {{ .Values.app.feature.featureA }}
        featureB: {{ .Values.app.feature.featureB }}
Enter fullscreen mode Exit fullscreen mode
  1. Mount this ConfigMap in your deployment:
# templates/deployment.yaml
# ... previous content ...
    spec:
      containers:
        - name: {{ .Chart.Name }}
          # ... other specs ...
          volumeMounts:
            - name: config
              mountPath: /app/config
      volumes:
        - name: config
          configMap:
            name: {{ include "spring-boot-app.fullname" . }}-config
Enter fullscreen mode Exit fullscreen mode

Deploying Your Application

To deploy your Spring Boot application with environment-specific configurations:

# For development
helm install my-spring-app ./spring-boot-app -f values-dev.yaml

# For production
helm install my-spring-app ./spring-boot-app -f values-prod.yaml
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Use Specific Versions: Always specify exact versions for your Spring Boot application image.
  2. Separate Concerns: Keep your application code separate from your Helm chart.
  3. Version Your Chart: Use semantic versioning for your Helm chart.
  4. Document Your Values: Clearly document what each value in your values.yaml represents.
  5. Use Helper Templates: For repeated blocks of configuration, create helper templates.
  6. Validate Your Chart: Use helm lint and helm template to validate your chart before deployment.

Conclusion

Helm charts provide a powerful way to manage Spring Boot applications in Kubernetes. By effectively managing common properties across different environments, you can ensure consistent, reproducible deployments while maintaining the flexibility to customize configurations as needed.

Remember, the key to successful Helm chart management is clear organization, good documentation, and regular testing of your charts across all target environments.

Have you used Helm charts with your Spring Boot applications? What strategies have you found effective for managing configurations across environments? Share your experiences and tips in the comments below!

Top comments (0)