Skip to main content
The QeetMart Helm chart provides a complete, configurable deployment package for Kubernetes. Helm simplifies the deployment process by templating Kubernetes manifests and managing releases.

Prerequisites

Before installing the Helm chart, ensure you have:
  • Kubernetes cluster 1.27 or later
  • Helm 3.12 or later
  • kubectl CLI configured
  • NGINX Ingress Controller (if ingress is enabled)

Quick start

1

Clone the repository

git clone https://github.com/qeetgroup/qeetmart.git
cd qeetmart/helm
2

Create a values file

Create my-values.yaml with your configuration:
global:
  secrets:
    JWT_SECRET: "your-secure-jwt-secret-min-32-chars"
    AUTH_DB_PASSWORD: "your-auth-password"
    USER_DB_PASSWORD: "your-user-password"
    PRODUCT_DB_PASSWORD: "your-product-password"
    INVENTORY_DATABASE_URL: "postgres://postgres:password@inventory-postgres:5432/inventory?sslmode=disable"

ingress:
  enabled: true
  host: api.yourdomain.com
3

Install the chart

helm install qeetmart ./qeetmart -f my-values.yaml
4

Verify installation

helm status qeetmart
kubectl get pods -l app.kubernetes.io/instance=qeetmart

Chart structure

The Helm chart is located in helm/qeetmart/ with the following structure:
qeetmart/
├── Chart.yaml              # Chart metadata
├── values.yaml             # Default values
└── templates/
    ├── deployment.yaml     # Deployment template
    ├── service.yaml        # Service template
    ├── hpa.yaml           # HorizontalPodAutoscaler template
    ├── ingress.yaml       # Ingress template
    └── config-secret.yaml # ConfigMap and Secret templates

Chart metadata

apiVersion: v2
name: qeetmart
description: Helm chart for Qeetmart microservices
version: 0.1.0
appVersion: "0.1.0"
type: application

Configuration

Global configuration

Global settings shared across all services:
global:
  imagePullSecrets: []
  config:
    JWT_ISSUER_URI: "http://auth-service:4001"
    JPA_DDL_AUTO: "validate"
    GIN_MODE: "release"
  secrets:
    JWT_SECRET: "CHANGE_ME"
    AUTH_DB_PASSWORD: "CHANGE_ME"
    USER_DB_PASSWORD: "CHANGE_ME"
    PRODUCT_DB_PASSWORD: "CHANGE_ME"
    INVENTORY_DATABASE_URL: "postgres://postgres:CHANGE_ME@inventory-postgres:5432/inventory?sslmode=disable"
Always override the default CHANGE_ME values with secure secrets. Never commit real secrets to version control.

Ingress configuration

Configure external access to the API Gateway:
ingress:
  enabled: true
  className: nginx
  host: api.qeetmart.local
  annotations: {}
    # cert-manager.io/cluster-issuer: letsencrypt-prod
    # nginx.ingress.kubernetes.io/rate-limit: "100"

Service configuration

Each microservice can be independently configured:

API Gateway

services:
  apiGateway:
    enabled: true
    replicas: 2
    port: 4000
    servicePort: 80
    image:
      repository: ghcr.io/qeetgroup/qeetmart/api-gateway
      tag: latest
      pullPolicy: IfNotPresent
    livenessPath: /health
    readinessPath: /health
    env:
      PORT: "4000"
      HOST: "0.0.0.0"
      TRUST_PROXY: "true"
      REQUIRE_AUTH: "true"
      AUTH_SERVICE_URL: "http://auth-service:4001"
      USER_SERVICE_URL: "http://user-service:8082"
      PRODUCT_SERVICE_URL: "http://product-service:8083"
      INVENTORY_SERVICE_URL: "http://inventory-service:8080"
      JWT_ISSUER: "$(JWT_ISSUER_URI)"
      JWT_SECRET: "$(JWT_SECRET)"
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 500m
        memory: 512Mi
    autoscaling:
      enabled: true
      minReplicas: 2
      maxReplicas: 20
      targetCPUUtilizationPercentage: 70

Auth Service

  authService:
    enabled: true
    replicas: 2
    port: 4001
    servicePort: 4001
    image:
      repository: ghcr.io/qeetgroup/qeetmart/auth-service
      tag: latest
      pullPolicy: IfNotPresent
    livenessPath: /actuator/health/liveness
    readinessPath: /actuator/health/readiness
    env:
      SERVER_PORT: "4001"
      DB_HOST: auth-postgres
      DB_PORT: "5432"
      DB_NAME: auth_db
      DB_USERNAME: postgres
      DB_PASSWORD: "$(AUTH_DB_PASSWORD)"
      JWT_SECRET: "$(JWT_SECRET)"
      JWT_ISSUER_URI: "$(JWT_ISSUER_URI)"
      JPA_DDL_AUTO: "$(JPA_DDL_AUTO)"
    resources:
      requests:
        cpu: 150m
        memory: 256Mi
      limits:
        cpu: 1000m
        memory: 1Gi
    autoscaling:
      enabled: true
      minReplicas: 2
      maxReplicas: 20
      targetCPUUtilizationPercentage: 70

Environment variable references

The chart uses a special syntax $(VARIABLE_NAME) to reference global configuration:
  • Values in global.config are injected as ConfigMap references
  • Values in global.secrets are injected as Secret references
  • Other values are used directly

Helm commands

helm install qeetmart ./qeetmart -f my-values.yaml

Advanced configuration

Disable specific services

You can disable services you don’t need:
services:
  inventoryService:
    enabled: false

Override image tags

Use specific image versions:
services:
  apiGateway:
    image:
      tag: v1.2.3
  authService:
    image:
      tag: v1.2.3

Custom resource limits

Adjust resources for your workload:
services:
  authService:
    resources:
      requests:
        cpu: 500m
        memory: 512Mi
      limits:
        cpu: 2000m
        memory: 2Gi

Autoscaling configuration

Customize autoscaling behavior:
services:
  apiGateway:
    autoscaling:
      enabled: true
      minReplicas: 5
      maxReplicas: 50
      targetCPUUtilizationPercentage: 60

Image pull secrets

For private registries:
global:
  imagePullSecrets:
    - name: ghcr-credentials
Create the secret:
kubectl create secret docker-registry ghcr-credentials \
  --docker-server=ghcr.io \
  --docker-username=your-username \
  --docker-password=your-token

Production values example

Create a production-values.yaml file:
global:
  config:
    JPA_DDL_AUTO: "validate"  # Never use "update" in production
    GIN_MODE: "release"
  secrets:
    # Use external secret management in production
    JWT_SECRET: "externally-managed-secret"
    AUTH_DB_PASSWORD: "externally-managed-secret"
    USER_DB_PASSWORD: "externally-managed-secret"
    PRODUCT_DB_PASSWORD: "externally-managed-secret"
    INVENTORY_DATABASE_URL: "externally-managed-url"

ingress:
  enabled: true
  className: nginx
  host: api.qeetmart.com
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"

services:
  apiGateway:
    replicas: 5
    image:
      tag: v1.0.0
    autoscaling:
      minReplicas: 5
      maxReplicas: 50

  authService:
    replicas: 3
    image:
      tag: v1.0.0
    autoscaling:
      minReplicas: 3
      maxReplicas: 30
Deploy to production:
helm upgrade --install qeetmart ./qeetmart \
  -n production \
  --create-namespace \
  -f production-values.yaml

Validation

Lint the chart

helm lint ./qeetmart

Validate templates

helm template qeetmart ./qeetmart -f my-values.yaml | kubectl apply --dry-run=client -f -

Troubleshooting

View rendered templates

If installation fails, check the rendered templates:
helm template qeetmart ./qeetmart -f my-values.yaml --debug

Check release status

helm status qeetmart
helm get manifest qeetmart

View installation hooks

helm get hooks qeetmart

Debug failed installation

helm install qeetmart ./qeetmart -f my-values.yaml --debug --dry-run
For production deployments, consider using external secret management solutions like HashiCorp Vault, AWS Secrets Manager, or Kubernetes External Secrets Operator instead of storing secrets in values files.

Build docs developers (and LLMs) love