DEV Community

Cover image for Kubernetes Configuration Management: Mastering Helm Values Files for Multi-Environment Deployments
Shingai Zivuku
Shingai Zivuku

Posted on

Kubernetes Configuration Management: Mastering Helm Values Files for Multi-Environment Deployments

Introduction

Overview of Kubernetes

Kubernetes (K8s) is an open-source container orchestration platform that automates the deployment, scaling, and management of containers. In K8s, applications typically run as containers, organized into different resource objects such as Deployments, Services, ConfigMaps, and Secrets. To ensure stable operation of applications in different environments (development, testing, pre-production, and production), customized configurations are needed for each environment.

The Importance of Values Files

Values files are configuration files used when managing Kubernetes application deployments using Helm, typically in YAML format. Helm is the package manager for Kubernetes, packaging and managing Kubernetes resources as a whole, called a Chart. Values files play a crucial role in this, allowing us to modify and adjust application configurations in different deployment environments without altering the application code or Kubernetes resource definition files. This ensures the application runs as expected at different stages, while maintaining configuration flexibility and maintainability.

Differences in configuration requirements for different environments

  • Development environment: Primarily used by developers for code development and debugging. It typically involves frequent configuration updates, may use relatively small resources, and has relatively lower performance and reliability requirements. For example, a development environment can use a local database or a simple development environment database, and the log level can be set to verbose to allow developers to promptly identify and resolve issues in the code.
  • Test environment: Used for functional testing, integration testing, and performance testing, it needs to have a similar configuration to the production environment, but allows for a certain degree of flexibility. The database in the test environment may be dedicated to testing, and its data and performance requirements may vary depending on the testing purpose; for example, it may simulate the data volume or load of the production environment.
  • Pre-production environment: This is a rehearsal of the production environment, designed to simulate the production environment as closely as possible, including configuration, resource scale, and performance requirements, to ensure that potential problems are identified and resolved before the official launch.
  • Production environment: requires the highest stability, performance, and security, needs to use real production databases, usually has a large resource scale, and has strict requirements for service availability and performance.

Implementation Method

Creating a Helm Chart

First, you need to create a Helm Chart, which is a directory structure containing the application's Kubernetes resource template and default Values files. You can create a new Helm Chart using the following command:

helm create my-application
Enter fullscreen mode Exit fullscreen mode

This command will create a my-application directory named <directory_name> containing multiple subdirectories and files. The templates directory contains template files for Kubernetes resources, while values.yaml is the default Values file.

Modify the default Values file

In the values.yaml configuration file, you can define various configuration parameters for the application, such as:

replicaCount: 1
image:
  repository: my-image
  tag: latest
service:
  type: ClusterIP
  port: 80
environment: development
database:
  url: jdbc:mysql://localhost:3306/devdb
  username: devuser
  password: devpass
Enter fullscreen mode Exit fullscreen mode

This section defines the number of replicas, image information, service type, port, and database connection information. However, these configurations are generic, and we need to customize them for different environments.

Create customized Values files for different environments

Create a separate Values file for each environment and save it in the Chart directory. For example:

Development environment: values-dev.yaml

replicaCount: 1
image:
  repository: my-image-dev
  tag: latest-dev
service:
  type: ClusterIP
  port: 8080
environment: development
database:
  url: jdbc:mysql://dev-db-server:3306/devdb
  username: devuser
  password: devpass
  logging:
    level: debug
Enter fullscreen mode Exit fullscreen mode

Test environment: values-test.yaml

replicaCount: 2
image:
  repository: my-image-test
  tag: latest-test
service:
  type: NodePort
  port: 8081
environment: testing
database:
  url: jdbc:mysql://test-db-server:3306/testdb
  username: testuser
  password: testpass
  logging:
    level: info
Enter fullscreen mode Exit fullscreen mode

Pre-release environment: values-preprod.yaml

replicaCount: 3
image:
  repository: my-image-preprod
  tag: latest-preprod
service:
  type: LoadBalancer
  port: 80
environment: preproduction
database:
  url: jdbc:mysql://preprod-db-server:3306/preproddb
  username: preproduser
  password: preprodpass
  logging:
    level: warn
Enter fullscreen mode Exit fullscreen mode

Production environment: values-prod.yaml

replicaCount: 5
image:
  repository: my-image-prod
  tag: latest-prod
service:
  type: LoadBalancer
  port: 80
environment: production
database:
  url: jdbc:mysql://prod-db-server:3306/proddb
  username: produser
  password: prodpass
  logging:
    level: error
Enter fullscreen mode Exit fullscreen mode

Using template languages

In the templates Kubernetes resource template file within the directory, you can use Helm's template language to reference configurations from the Values file. For example, in the deployment.yaml template file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{.Release.Name }}-my-application
spec:
  replicas: {{.Values.replicaCount }}
  selector:
    matchLabels:
      app: {{.Release.Name }}-my-application
  template:
    metadata:
      labels:
        app: {{.Release.Name }}-my-application
    spec:
      containers:
        - name: my-application
          image: {{.Values.image.repository }}:{{.Values.image.tag }}
          ports:
            - containerPort: {{.Values.service.port }}
          env:
            - name: DATABASE_URL
              value: {{.Values.database.url }}
            - name: DATABASE_USER
              value: {{.Values.database.username }}
            - name: DATABASE_PASSWORD
              value: {{.Values.database.password }}
            - name: LOGGING_LEVEL
              value: {{.Values.database.logging.level }}
Enter fullscreen mode Exit fullscreen mode

Here, we use {{.Values.xxx }} syntax to reference the configuration in the Values file and insert them into the appropriate locations in the Kubernetes resources.

Deploying the application

Use Helm commands to deploy using the appropriate Values file based on different environments:

Development environment:

helm install my-application-dev my-application --values my-application/values-dev.yaml
Enter fullscreen mode Exit fullscreen mode

Test environment:

helm install my-application-test my-application --values my-application/values-test.yaml
Enter fullscreen mode Exit fullscreen mode

Pre-release environment:

helm install my-application-preprod my-application --values my-application/values-preprod.yaml
Enter fullscreen mode Exit fullscreen mode

Production environment:

helm install my-application-prod my-application --values my-application/values-prod.yaml
Enter fullscreen mode Exit fullscreen mode

Implementation Case

Suppose we have a simple web application; here is a complete implementation example:

Creating a Helm Chart

helm create my-webapp
Enter fullscreen mode Exit fullscreen mode

Modify the values.yaml document:

appName: my-webapp
replicaCount: 1
image:
  repository: my-webapp-image
  tag: latest
service:
  type: ClusterIP
  port: 80
database:
  url: jdbc:mysql://default-db:3306/defaultdb
  username: defaultuser
  password: defaultpass
logging:
  level: info
Enter fullscreen mode Exit fullscreen mode

Creating Values files for different environments:

Development environment: values-dev.yaml

appName: my-webapp-dev
replicaCount: 1
image:
  repository: my-webapp-dev-image
  tag: latest-dev
service:
  type: ClusterIP
  port: 8080
database:
  url: jdbc:mysql://dev-db:3306/devdb
  username: devuser
  password: devpass
logging:
  level: debug
Enter fullscreen mode Exit fullscreen mode

Test environment: values-test.yaml

appName: my-webapp-test
replicaCount: 2
image:
  repository: my-webapp-test-image
  tag: latest-test
service:
  type: NodePort
  port: 8081
database:
  url: jdbc:mysql://test-db:3306/testdb
  username: testuser
  password: testpass
logging:
  level: info
Enter fullscreen mode Exit fullscreen mode

Pre-release environment: values-preprod.yaml

appName: my-webapp-preprod
replicaCount: 3
image:
  repository: my-webapp-preprod-image
  tag: latest-preprod
service:
  type: LoadBalancer
  port: 80
database:
  url: jdbc:mysql://preprod-db:3306/preproddb
  username: preproduser
  password: preprodpass
logging:
  level: warn
Enter fullscreen mode Exit fullscreen mode

Production environment: values-prod.yaml

appName: my-webapp-prod
replicaCount: 5
image:
  repository: my-webapp-prod-image
  tag: latest-prod
service:
  type: LoadBalancer
  port: 80
database:
  url: jdbc:mysql://prod-db:3306/proddb
  username: produser
  password: prodpass
logging:
  level: error
Enter fullscreen mode Exit fullscreen mode

Modify the template file

In templates/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{.Release.Name }}-{{.Values.appName }}
spec:
  replicas: {{.Values.replicaCount }}
  selector:
    matchLabels:
      app: {{.Release.Name }}-{{.Values.appName }}
  template:
    metadata:
      labels:
        app: {{.Release.Name }}-{{.Values.appName }}
    spec:
      containers:
        - name: {{.Values.appName }}
          image: {{.Values.image.repository }}:{{.Values.image.tag }}
          ports:
            - containerPort: {{.Values.service.port }}
          env:
            - name: DATABASE_URL
              value: {{.Values.database.url }}
            - name: DATABASE_USER
              value: {{.Values.database.username }}
            - name: DATABASE_PASSWORD
              value: {{.Values.database.password }}
            - name: LOGGING_LEVEL
              value: {{.Values.logging.level }}
Enter fullscreen mode Exit fullscreen mode

Deploying the application

Use the following command to deploy the application to different environments:

Development environment:

helm install my-webapp-dev my-webapp --values my-webapp/values-dev.yaml
Enter fullscreen mode Exit fullscreen mode

Test environment:

helm install my-webapp-test my-webapp --values my-webapp/values-test.yaml

Enter fullscreen mode Exit fullscreen mode

Pre-release environment:

helm install my-webapp-preprod my-webapp --values my-webapp/values-preprod.yaml
Enter fullscreen mode Exit fullscreen mode

Production environment:

helm install my-webapp-prod my-webapp --values my-webapp/values-prod.yaml
Enter fullscreen mode Exit fullscreen mode

In this way, we can easily deploy applications in different environments and customize the configuration according to the characteristics of each environment. This approach ensures the flexibility and manageability of applications in different environments, while reducing problems caused by configuration errors.

Summary

Using Values files to customize application configurations across different Kubernetes environments is a powerful and flexible approach. Leveraging Helm's template capabilities, it allows developers and operations personnel to easily adjust application configurations at different deployment stages without modifying code or Kubernetes resource definition files. By using Values files appropriately, we can better manage application development, testing, pre-production, and production environments, ensuring smooth operation at each stage and meeting corresponding performance, security, and availability requirements. Simultaneously, this approach facilitates continuous integration and continuous deployment (CI/CD) processes, enabling teams to deliver and maintain software more efficiently.

Please remember that in practical applications, appropriate adjustments and optimizations are needed based on the specific requirements of the application and the characteristics of the Kubernetes cluster to ensure the accuracy and effectiveness of the configuration. At the same time, pay attention to the management of sensitive information (such as database passwords), avoid storing it in plaintext in configuration files, and consider using Kubernetes' Secret resources for storage and management.

Top comments (0)